我的windows 结束进程命令10长期出现进程页下CPU使用率100%,但在详细信息页下空闲进程98这种情况,请问怎么解决呢?

Linux下查看CPU使用率!系统资源使用情况!
我的图书馆
Linux下查看CPU使用率!系统资源使用情况!
top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器。下面详细介绍它的使用方法。top - 01:06:48 up 1:22, 1 user, load average: 0.06, 0.60, 0.48Tasks: 29 total, 1 running, 28 sleeping, 0 stopped, 0 zombieCpu(s): 0.3% us, 1.0% sy, 0.0% ni, 98.7% id, 0.0% wa, 0.0% hi, 0.0% siMem: 191272k total, 173656k used, 17616k free, 22052k buffersSwap: 192772k total, 0k used, 192772k free, 123988k cachedPID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND1379 root 16 0 80 S 0.7 1.3 0:11.03 sshd14704 root 16 0
R 0.7 0.5 0:02.72 top1 root 16 0
S 0.0 0.3 0:00.90 init2 root 34 19 0 0 0 S 0.0 0.0 0:00.00 ksoftirqd/03 root RT 0 0 0 0 S 0.0 0.0 0:00.00 watchdog/0统计信息区前五行是系统整体的统计信息。第一行是任务队列信息,同 uptime 命令的执行结果。其内容如下:01:06:48 当前时间up 1:22 系统运行时间,格式为时:分1 user 当前登录用户数load average: 0.06, 0.60, 0.48 系统负载,即任务队列的平均长度。三个数值分别为 1分钟、5分钟、15分钟前到现在的平均值。第二、三行为进程和CPU的信息。当有多个CPU时,这些内容可能会超过两行。内容如下:Tasks: 29 total 进程总数1 running 正在运行的进程数28 sleeping 睡眠的进程数0 stopped 停止的进程数0 zombie 僵尸进程数Cpu(s): 0.3% us 用户空间占用CPU百分比1.0% sy 内核空间占用CPU百分比0.0% ni 用户进程空间内改变过优先级的进程占用CPU百分比98.7% id 空闲CPU百分比0.0% wa 等待输入输出的CPU时间百分比0.0% hi0.0% si最后两行为内存信息。内容如下:Mem: 191272k total 物理内存总量173656k used 使用的物理内存总量17616k free 空闲内存总量22052k buffers 用作内核缓存的内存量Swap: 192772k total 交换区总量0k used 使用的交换区总量192772k free 空闲交换区总量123988k cached 缓冲的交换区总量。内存中的内容被换出到交换区,而后又被换入到内存,但使用过的交换区尚未被覆盖,该数值即为这些内容已存在于内存中的交换区的大小。相应的内存再次被换出时可不必再对交换区写入。进程信息区统计信息区域的下方显示了各个进程的详细信息。首先来认识一下各列的含义。序号 列名 含义a PID 进程idb PPID 父进程idc RUSER Real user named UID 进程所有者的用户ide USER 进程所有者的用户名f GROUP 进程所有者的组名g TTY 启动进程的终端名。不是从终端启动的进程则显示为 ?h PR 优先级i NI nice值。负值表示高优先级,正值表示低优先级j P 最后使用的CPU,仅在多CPU环境下有意义k %CPU 上次更新到现在的CPU时间占用百分比l TIME 进程使用的CPU时间总计,单位秒m TIME+ 进程使用的CPU时间总计,单位1/100秒n %MEM 进程使用的物理内存百分比o VIRT 进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RESp SWAP 进程使用的虚拟内存中,被换出的大小,单位kb。q RES 进程使用的、未被换出的物理内存大小,单位kb。RES=CODE+DATAr CODE 可执行代码占用的物理内存大小,单位kbs DATA 可执行代码以外的部分(数据段+栈)占用的物理内存大小,单位kbt SHR 共享内存大小,单位kbu nFLT 页面错误次数v nDRT 最后一次写入到现在,被修改过的页面数。w S 进程状态。D=不可中断的睡眠状态R=运行S=睡眠T=跟踪/停止Z=僵尸进程x COMMAND 命令名/命令行y WCHAN 若该进程在睡眠,则显示睡眠中的系统函数名z Flags 任务标志,参考 sched.h默认情况下仅显示比较重要的 PID、USER、PR、NI、VIRT、RES、SHR、S、%CPU、%MEM、TIME+、COMMAND 列。可以通过下面的快捷键来更改显示内容。更改显示内容通过 f 键可以选择显示的内容。按 f 键之后会显示列的列表,按 a-z 即可显示或隐藏对应的列,最后按回车键确定。按 o 键可以改变列的显示顺序。按小写的 a-z 可以将相应的列向右移动,而大写的 A-Z 可以将相应的列向左移动。最后按回车键确定。按大写的 F 或 O 键,然后按 a-z 可以将进程按照相应的列进行排序。而大写的 R 键可以将当前的排序倒转。命令使用1. 工具(命令)名称top2.工具(命令)作用显示系统当前的进程和其他状况; top是一个动态显示过程,即可以通过用户按键来不断刷新当前状态.如果在前台执行该命令,它将独占前台,直到用户终止该程序为止. 比较准确的说,top命令提供了实时的对系统处理器的状态监视.它将显示系统中CPU最“敏感”的任务列表.该命令可以按CPU使用.内存使用和执行时间 对任务进行排序;而且该命令的很多特性都可以通过交互式命令或者在个人定制文件中进行设定.3.环境设置在Linux下使用。4.使用方法4.1使用格式top [-] [d] [p] [q] [c] [C] [S] [s] [n]4.2参数说明d 指定每两次屏幕信息刷新之间的时间间隔。当然用户可以使用s交互命令来改变之。p 通过指定监控进程ID来仅仅监控某个进程的状态。q该选项将使top没有任何延迟的进行刷新。如果调用程序有超级用户权限,那么top将以尽可能高的优先级运行。S 指定累计模式s 使top命令在安全模式中运行。这将去除交互命令所带来的潜在危险。i 使top不显示任何闲置或者僵死进程。c 显示整个命令行而不只是显示命令名4.3其他  下面介绍在top命令执行过程中可以使用的一些交互命令。从使用角度来看,熟练的掌握这些命令比掌握选项还重要一些。这些命令都是单字母的,如果在命令行选项中使用了s选项,则可能其中一些命令会被屏蔽掉。  Ctrl+L 擦除并且重写屏幕。  h或者? 显示帮助画面,给出一些简短的命令总结说明。  k 终止一个进程。系统将提示用户输入需要终止的进程PID,以及需要发送给该进程什么样的信号。一般的终止进程可以使用15信号;如果不能正常结束那就使用信号9强制结束该进程。默认值是信号15。在安全模式中此命令被屏蔽。  i 忽略闲置和僵死进程。这是一个开关式命令。  q 退出程序。  r 重新安排一个进程的优先级别。系统提示用户输入需要改变的进程PID以及需要设置的进程优先级值。输入一个正值将使优先级降低,反之则可以使该进程拥有更高的优先权。默认值是10。  S 切换到累计模式。  s 改变两次刷新之间的延迟时间。系统将提示用户输入新的时间,单位为s。如果有小数,就换算成m s。输入0值则系统将不断刷新,默认值是5 s。需要注意的是如果设置太小的时间,很可能会引起不断刷新,从而根本来不及看清显示的情况,而且系统负载也会大大增加。  f或者F 从当前显示中添加或者删除项目。  o或者O 改变显示项目的顺序。  l 切换显示平均负载和启动时间信息。  m 切换显示内存信息。  t 切换显示进程和CPU状态信息。  c 切换显示命令名称和完整命令行。  M 根据驻留内存大小进行排序。  P 根据CPU使用百分比大小进行排序。  T 根据时间/累计时间进行排序。W 将当前设置写入~/.toprc文件中。这是写top配置文件的推荐方法。&&关于 load & average:&命令输出的最后内容表示在过去的1、5、15分钟内运行队列中的平均进程数量。 &&& ??一般来说只要每个CPU的当前活动进程数不大于3那么系统的性能就是良好的,如果每个CPU的任务数大于5,那么就表示这台机器的性能有严重问题。对 于上面的例子来说,假设系统有两个CPU,那么其每个CPU的当前任务数为:8.13/2=4.065。这表示该系统的性能是可以接受的。&分享到:
TA的推荐TA的最新馆藏[转]&
喜欢该文的人也喜欢随笔 - 302&
&&&&&&&&&&&
进程、轻量级进程(LWP)、线程
进程:程序执行体,有生命期,用来分配资源的实体
线程:分配CPU的实体。
&&用户空间实现,一个线程阻塞,所有都阻塞。
&&内核实现,不会所用相关线程都阻塞。用LWP实现,用线程组表示这些线程逻辑上所属的进程。
进程描述符
进程描述符(简称pd, process descriptors),结构体是:task_struct
&&数据较多,存放在kenerl的动态内存空间。
&&pd的引用放在thread_info中,
& &thread_info与内核栈,放在一个8K空间(它的地址8K对齐)。内核程序使用的栈空间很小。
& &thread_info在底部,内核栈在顶部向下增长。
& & 好处:多CPU时方便,每个CPU根据自己的栈指针就可以找到当前的pd (以后用current表示当前CPU运行的进程描述符)。
& &&&esp(内核栈指针)低8位置零,就是thread_info地址。
& &每进程有自己的thread_info, (分配释放函数: alloc_thread_info, free_thread_info)
描述符的内容
&&相关的ID (一个4元素数组)
& &进程ID (PID)
& & PID按创建顺序连续增长,到最大值后从最小值开始。
& & 0号进程:交换进程(swapper)
& & 有PID可用位图,表示那一个PID可用,至少占一个页。
& &线程组ID(tgid),用LWP实现多线程支持
& & 多进程时,进程id,就是线程组id, 也就是组长的pid(LWP)。 getpid() 取的是线程组的id(tgid), 也是组长的pid.
& & 单线程时,pid = gid。所以getpid,也是真正的pid.
& &进程组ID(pgrp)。
& &回话的ID(session).
& & 组ID,都是组长的PID。FIXME: 但pb也有各组长的PID
& &&&线程组长:tgid
& &&&进程组长:signal-&pgrp ,
& &&&会话长:signal-&session
& &管理ID数据结构——哈希表管理 (利用id找到所用相关的pd,方便)。
& & 一个哈希表数组(pid_hash),存放四个哈希表, 每一个表代表一类id (pid, tgid, pgrp, session)
& & 每个哈希表的由数组(索引为哈希值)和二维链表(嵌入到进程描述符内的pids中)实现
& &&&第一维链表:哈希冲突链表。
& &&&第二维链表:要查找的值相同的链表, 叫per-PID list(同一组的所有线程,同一组的所有进程,同一会话的所有进程);
& &进程组ID(pgrp), 回话ID(session)在共享信号的数据结构里。因为同一进程内的所有LWP,这两个ID都是一样的
&&家族关系:由pd里的链表(下级)和pd指针(上级)实现
& & 亲生父亲:创建自己的进程,或是托孤进程(创建自己的进程死了)。
& & 父亲:自己死时要发信号告知的。一般是亲生父亲,有时是监控自己的进程 (调用ptrace)
& & 孩子:
& & 兄弟:
& &监控(自己起的名字,类似于监护。由于管理方式相同,也归为家族关系)
& & 监控的进程列表:ptrace_children
& & 被监控的其他进程:ptrace_list (类似于被监控的兄弟)
& &在链表里为了管理方便:
& & 最大儿子的兄弟是父亲
& & 最小儿子的弟弟也是父亲
& & 父亲保管最大儿子,和最小儿子
&&进程资源及资源限制:
& &CPU相关:
& & 占用CPU总时间
& & 用户的最大进程数
& &内存相关:
& & 进程地址空间
& & 锁住内存大小
& & 进程页数 (只有记录,没有限制)
& & 堆大小,栈大小
& &资源相关:
& & 文件:
& &&&core dump大小
& &&&最大文件大小
& &&&打开文件个数
& & 进程同步与通信
& &&&锁数目,
& &&&悬挂信号数据
& &&&在消息列队中占的大小
& &相关数据结构 和 处理流程
& & pd-&sigal-&rlim 是一个表示进程资源使用情况以及限制的结构&的数组。
& & 表示进程资源使用情况以及限制的结构:包含当前值,最大值两个数值。
& &只有超级用户才能增大资源限制。
& &一般用户登陆时:
& & kernel创建root进程,减少limit,
& & 建一个 shell子进程,继承limit.
& & 把shell进程的用户,改成登陆的那个用户
&&进程状态(state)
& &运行,TASK_RUNNING
& & 组织pd的结构:就绪进程链:
& &&&一个CPU一组链表,每个链表表示一种优先级。
& & 可中断阻塞,TASK_INTERRUPTIBLE
& &&&可被硬件中断,“释放资源”事件,信号唤醒。
& & 不可中断阻塞,TASK_UNINTERRUPTIBLE
& &&&可被硬件中断,“释放资源”事件,唤醒。
& &&&但不能被信号唤醒。可用于驱动程序中。
& & 组织pb的结构:等待列队: 每一类事件一个列队,用内嵌链表实现(虽然没列出内嵌链表节点)
& &&&列队头:
& && &自旋锁:防止有一个主函数和中断函数同时操作列队。
& &&&列队节点:
& && &独占标志:表示该进程是否要独占资源 (不再唤醒别的进程)
& && &指向pd的指针
& && &用于唤醒进程的回调函数。(提供进程的执行机会,是否操作等待列队由用户决定)
& & 停止TASK_STOPPED
& &&&被信号停止
& & 追踪TASK_TRACED
& &&&该进程被一个调试进程监控以后,收到任何一个信号就进入该状态
& & 组织pb的结构:FIXME: 信号的等待列队?
& & 退出_僵尸EXIT_ZOMBIE
& &&&进程终止,资源没有被回收(父进程要用,没有调wait系列函数)
& & 退出_死亡EXIT_DEAD
& &&&进程终止,资源正在被回收(父进程要用,没有调wait系列函数)。
& &&&一旦资源回收完成,进程描述符也就被回收了。
& &&&它防止该进程再次被wait.
& & 组织pb的结构:不挂到队列上,只在家族关系中,等待父进程收回资源
进&程控制&:
阻塞(current阻塞到某个列队上):
&&基本流程
& &临时生成一个列队节点,初始化。
& &改变current的状态,放入节点,挂到列队上。
& &调度 (=====》至此,阻塞完成。 一旦被别的进程唤醒====》从调度函数中返回)
& &从等待列队上摘除节点。
& &将挂列队、调度、从列队删除三步拆开,便于灵活处理。
& &可中断的、限时、独占的函数类似。只不过进程状态、调度函数、独占标志不同。
& &非独占的从列队开始添加,独占的从末尾添加。(但一个列队内既有独占的,又有非独占的等待进程,很少见)
&&基本流程
& &唤醒一个进程:调用节点里的回调函数
& &唤醒的时候从列队开头依次唤醒,直到唤醒一个独占的后停止。
& &是否只唤醒可中断的进程. (_interruptible后缀)
& &唤醒的独占进程的数目(1个,多个(_nr后缀),所有(_all后缀))
& &唤醒后是否不检查优先级,马上给予CPU (有_sync的不检查优先级)。
&&切换pgd (全局页目录),此章不讨论。
&&切换内核栈,硬件上下文
& &硬件上下文,就是CPU的寄存器。
& & 一部分(大多数CPU寄存器(除了通用寄存器))在pd中保存(task_struct-&thread, 类型是thread_struct),
& & 一部分(通用寄存器)保存在内核栈中.
& &原来用硬件指令()保存CPU信息。后来改成软件(一个个MOV指令)
& & 容易控制,可以挑选信息保存,便于优化。不保存的做其他用(如:进程间传递)
& && && & far jmp:跳至目标进程的TSSD。而linux是每个CPU一个TSS,不是每进程一个
& & 对于一些寄存器(ds、es)可以检查值。
& & 与用硬件指令保存时间差不多。
&&switch_to 宏
& &三个参数:
& & prev: 要换走的进程,一般是当前进程
& & next: 要换到的进程。
& & last: 传出参数。当前进程再次被换到时,最后一个占用CPU的进程。(prev指向的进程 就是 next指向的进程 的last)
& & 栈切换, 完成后就是在新进程的上执行了:
& &&&保存prev(放在eax)
& &&&eflags,ebp入内核栈;
& &&&保存并装载新的esp (旧的esp放到prev-&thread.esp,新的esp是next-&thread.esp)
& && &此时current就是新的esp所指的thread_info内的task指针
& & 设置返回地址:
& &&&prev进程以后得到执行时的__switch_to的返回地址: __switch_to后的第一条指令, 放入prev-&thread.eip,
& &&&准备next进程的从__switch_to返回的地址: next-&thread.eip入栈.
& & 调用__switch_to ()函数,该函数动作如下:
& &&&更新CPU的相关信息(tss和gdt):
& && &存next-&thread.esp0(内核栈低)到本地TSS.esp0中。
& && &所在CPU的全局段表里的TLS段, 设成next进程的.
& && &更新tss的I/O位图.
& &&&更新CPU的寄存器(pd-&thread (tss) 与 CPU寄存器交换数据):
& && &保存FPU, MMX, XMM寄存器, 先不装载以后需要时通过中断装载(TODO: )
& && &保存prev的fs, gs寄存器. 装载next的
& && &装载next的debug寄存器(debug寄存器一个8个, 进程切换时只需6个)
& && &prev放入eax (prev就是新进程的last)
& & ret返回的地址: (__switch_to之前被存入栈中, __switch_to ret时进入eip)
& &&&如果是next新进程, next-&thread.eip是iret_from_fork.
& &&&如果next不是新进程:
& && &弹出ebp, elfags
& && &把eax放入last变量 (prev就是next进程的last)
任务状态段(一个存CPU状态的数组,tss_struct init_tss[])
& & 每个CPU用段上的一个元素。(FIXME: 用于:用户模式要进入内核模式时,设置相应寄存器)
& && &TSS上存内核栈地址。CPU上的程序从用户模式转到内核模式,设置esp。
& && &TSS存I/O端口许可位图。用户模式程序用到I/O时,检查有无权限
& && &所以,进程切换时,要保存的寄存器在pd-&thread中。
& && &&&thread_struct不是thread_info。thread_info中只有少量的数据或指针, 用于通过esp快速定位数据
& & 进程切换时,更新TSS上的信息。
& && &CPU控制单元再从TSS上取需要的信息。
& && &即反应了CPU的当前进程情况,又不需要维护所有进程的状态数据。
& & TSS的描述符在GDT里。
& && &TSSD:任务状态段描述符 (其实应该叫任务状态描述符,每个TSSD,表示一个CPU的状态, FIXME: :具体以源码为准)
& && &CPU原始设计,每个进程一个TSS元素。
& && &linux设计,每个CPU一个TSS元素。
& && &cpu里的tr寄存器,保存着自己的TSSD(即init_ttss[cpu_id]),不用总上gdt里去取。
进程创建: clone, fork, vfork系统调用
&&clone系统调用
& & 执行函数(fn), 参数(arg)
& & flags|死亡时给父进程发的信号 (clone_flags): 以下介绍clone_flags
& &&&资源共享
& && &段,页,打开文件共享:
& && & 页表(不是页, CLONE_VM),
& && & 打开文件(clone_files),
& && & 建一个新tls段(clone_settls)
& && &路径和权限设置:
& && & clone_fs: 共享根目录, 当前目录, 创建文件初始权限.
& && & clone_newns: 新的根路径, 自己的视野看文件系统
& && &线程通信
& && & clone_sighand: 信号处理action, 阻塞和悬挂的信号
& && & clone_sysvsem: 共享undoable信号量操作
& &&&进程关系
& && &同父: clone_parent 创建进程与新进程是兄弟 (同父), 新进程不是创建进程的子进程
& && & 为了方便期间, 以下讨论暂时不考虑这一因素(它很容易实现), 认为创建进程就是父进程
& && &同一个线程组: clone_thread. 属于同一个进程(线程组)
& && &都被trace: clone_ptrace
& && &子进程不被trace: clone_untrace (内核设置, 覆盖clone_ptrace)
& &&&返回tid
& && &向父进程返回tid: clone_parent_settid
& && &向子进程返回tid: clone_child_settid
& &&&子进程的状态:
& && &子进程开始就stop: clone_stopped
& &&&进程死亡或exec通知:
& && &启动内核机制: 如果子进程死亡或exec, 它自己空间内的tid(*ctid)清零, 并唤醒等待子进程死亡的进程.
& & 赋给子进程的资源
& &&&子进程的栈(父进程alloc的内存地址)
& &&&线程局部仓库段(tls)
& & 返回子进程tid的地址
& &&&父进程用户空间内的地址
& &&&子进程用户空间的地址
&&clone, fork, vfork实现方式
&&大致相同:
& & 系统调用服务例程sys_clone, sys_fork, sys_vfork三者最终都是调用do_fork函数完成.
& & do_fork的参数与clone系统调用的参数类似, 不过多了一个regs(内核栈保存的用户模式寄存器). 实际上其他的参数也都是用regs取的
& &区别在于:
& & clone:
& &&&clone的API外衣, 把fn, arg压入用户栈中, 然后引发系统调用. 返回用户模式后下一条指令就是fn.
& &&&sysclone: parent_tidptr, child_tidptr都传到了 do_fork的参数中
& &&&sysclone: 检查是否有新的栈, 如果没有就用父进程的栈 (开始地址就是regs.esp)
& & fork, vfork:
& &&&服务例程就是直接调用do_fork, 不过参数稍加修改
& &&&clone_flags:
& && &sys_fork: SIGCHLD|0;
& && &sys_vfork: SIGCHLD| (clone_vfork | clone_vm)
& &&&用户栈: 都是父进程的栈.
& &&&parent_tidptr, child_ctidptr都是NULL.
具体实现函数do_fork() (内核函数)的工作流程:
&&分配PID, 确定子进程到底是否traced.
& &分配空闲的PID
& &确定clone_ptrace位. (确定子进程到底要不要被trace, 而不是参数所说的希望被trace)
& & 设置该位: 参数已设该位, 且创建线程被trace中
& & 清除该位: 父进程没有被trace, 或 clone_untrace已经设置.
&&复制进程描述符(copy_process)
& &检查clone_flags是否兼容, 是否安全
& & clone_newns 与 clone_fs 互斥
& & clone_sighand 是 clone_thread 的必要条件: 线程必须共享信号处理
& & clone_vm 是 clone_sighand 的必要条件 : 共享信号处理, 首先要共享信号处理的代码(在进程页面里)
& & 附加的安全检查: security_task_create(clone_flags)
& &复制进程描述符
& & 在父进程的thread_info里保存浮点寄存器: __unlazy_fpu()
& & 分配新的进程pd(alloc_task_struct), 并拷贝父进程pd
& & 分配新的thread_info(alloc_thread_info), 并拷贝父进程的thread_info.
& & 新的thread_info和新分配的pd 相互引, 新pd的引用计数设为2 (表示:新pd有用, 且不是僵尸进程)
& &相关计数加1: (此处先相关计数检查, 都通过后再都加1)
& & 检查并增加: 用户拥有进程数, 系统总共进程数.
& &&&一般来说, 所有进程的thread_info总和, 不超过物理内存的1/8
& & 新进程的可执行格式的引用计数(FIXME: pd里标有可执行个数吗)
& & 系统执行fork总数.
& &进程pd的关键域的设置(顺序与源码可能不一致):
& & 进程关系
& &&&设置父子关系 (parent, real_parent, 考虑被trace的情况)
& &&&设置新pd的PID
& &&&设置tgid, 线程组长的pd(pd-&group_leader). (根据是不是线程组长, 即clone_thread位是否为0)
& &&&加入PID哈希表(pid, tgid, 如果是进程组长加入pgid和sid表),(调attach_pid())
& &&&拷贝tid到父进程的用户空间(parent_tidptr)
& & 拷贝资源(如果clone_flags没标明共享):
& &&&文件,目录,内存:copy_files, copy_mm, copy_namespace,
& &&&进程通信: copy_signal, copy_sighand, copy_semundo
& & 设置子进程的内核栈(thread_info), 内核态相关寄存器(thread_struct, 不知道这个结构的具体用处): copy_thread()
& &&&子进程的thread_struct:
& && &esp, esp0 - 内核栈顶, 内核栈底
& && &eip - ret_from_fork()的地址 (用户态切到内核态的第一条指令)
& && &I/O许可位图 - 如果父进程有, 就拷贝一份过来
& && &TLS - 如果用户空间提供了TLS段, 拷贝过来
& &&&设置子进程的内核栈:
& && &child_regs.esp = 传入的栈地址参数;
& && &child_regs.eax = 0, 给用户态的返回值是0
& && &清除thread_info中的, TIF_SYSCALL_TRACE位, 防止运行ret_from_fork时, 系统通知调试进程
& && &设置子进程的thread_info的cpuid
& & 设置调度信息(sched_fork())
& &&&设置task_running状态,
& &&&初始化调度参数(时间片),
& &&&子进程禁止内核抢占(thread_info.preempt_cout = 1)
& & 其他:
& &&&如果没有被trace,pd-&ptrace = 0;
& &&&设置pd-&exit_signal:
& && &有clone_thread位: 设为参数clone_flags中的退出信号
& && &没有clone_thread位: 设为-1 (表示进程终止时, 该LWP不给父进程发信号)
& &&&pd-&flags: 清除PF_SUPERPRIV , 设置PF_FORKNOEXEC
& &&&大内核锁 pd-&lock_depth = -1
& &&&exec次数: pd-&did_exec = 0
& &&&拷贝child_tidptr到pd-&set_child_tid. 以备子进程开始执行时, 把tid放到自己内存空间的child_tidptr
&&设置父子进程的运行状态, 调度信息
& &设置子进程的状态.
& & 挂信号: 如果创建出来的是停止(clone_stopped)或被trace(pd-&ptrace里有PT_PTRACE位)的进程, 悬挂一个SIGSTOP信号.
& &&&只有debugger发出SIGCONT信号后, 才能进入运行状态
& & 设状态,入列队:如果有clone_stopped位, 子进程设为stopped状态; 否则调用wake_up_new_task(), 把子进程加入就绪列队:
& &&&调整父进程和子进程的调度参数 (主要是时间片)
& &&&如果父子在同一CPU上运行, 且页表不同享, 子进程在插在父进程前
& && &子进程很可能exec, 不与父进程共享页. 这样防止父进程无用的copy on write.
& &&&如果不同CPU上运行, 或者共享页表, 子进程放在列队最后
& &如果父进程处于被调试状态, 程通知调试器
& & 当前进程给debugger进程发信号, 告知自己创建了子进程; 并停止自己(进入traced状态), 使debugger运行.
& &&&子进程的pid保存在current-&ptrace_message中, 供debugger用
& &&&调试器发信号, 使父进程继续后, 再进行下一步; 否则父进程一直处于traced状态
& &设置父进程状态
& & 如果有clone_vfork, 把自己放到一个等待列队.
& &&&内核处理完系统调用后, 会执行调度, 这样就阻塞父进程了.
& &&&直到子进程释放了它的内存地址空间, 即子进程终止或exec新程序, 用信号唤醒父进程.
&&返回子进程的pid.
&&子进程被调度后,执行pd.thread.eip(ret_from_fork). 调用关系(=&): ret_from_fork=&schedule_tail=&finish_task_switch.
& &schedule_tail的另一件事就是: 把pid保存到地址pd-&set_child_tid (创建进程使的parent_tidptr)
& &finish_task_switch的动作是: 装载内核栈保存的寄存器(regs-&eax为0),返回到用户态。系统调用返回值就是eax(0)
内核线程:
&&只运行于kernel模式,只能访问大于3G的空间。而普通进程在内核模式时,能访问整个4G空间
&&创建方法, 类似于clone
& &准备返回地址fn: 构造一个regs. 里面有fn, args, __KERNEL_CS等. regs-&eip是汇编函数kernel_thread_helper
& &do_fork (flags|CLONE_VM|clone_untraced, 0, &regs, 0, NULL, NULL)
& & 创建线程, 与父进程共享页. 用上步构造的regs初始化新程的内核栈
& &新线程被调度后. 由ret_from_fork, 用regs恢复寄存器, 开始执行kernel_thread_helper
& &kernel_thread_helper: 把args压入栈, call fn(args, fn都寄存器中)
&&典型的内核线程:
& &进程0: 所有进程的祖先
& & 编译时存在.
& &&&pd, 内核栈: init_task, init_thread_union
& &&&资源: init_mm, init_files, init_fs.&&信号: init_signals, init_sighand
& &&&页表: swapper_gd_dir
& &&&初始化系统数据,
& && &多CPU系统中, 开始时BIOS禁用其他CPU.
& && &初始化系统数据后, 进程0拷贝自己到其他CPU的调度列队上, 启动其他CPU, 所有的PID都是0.
& &&&使能中断
& &&&创建内核线程1, (函数是init)
& &&&进入idle
& & init函数 exec可执行文件init, 使内核线程变成了普通进程.
& & 管理其他进程, 称为托孤进程
& &其他内核线程:
& & 执行工作列队:
& &&&ksoftirqd: 执行 softlets
& &&&kblockd: 执行工作列队 kblockd_workqueue, 定期激活块设备驱动
& &&&keventd (又叫events): 处理工作列队 keventd_wq
& & 管理资源:
& &&&kapmd: 电源管理
& &&&kswapd: 交换进程, 用于回收内存资源
& &&&pdflush: flush脏的磁盘缓存
&&系统调用
& &整个进程终止: exit_group(), 由do_group_exit处理系统调用. c函数 exit()也是用的这系统调用
& &某个线程终止: _exit(), 由do_exit处理. C函数中用到此系统调用的API: pthread_exit
&&do_group_exit流程: (整个组内至少有一个线程调用它, 用于整组协调)
& &检查线程组的退出过程是否启动: 检查signal_group_exit(线程组内的公共数据)是否非零. 如果没有启动, 执行一下操作来启动退出过程:
& & 设置启动标志signal_group_exit.
& & 存储终止码(exit_group的参数), 在current-&signal-&group_exit_cold
& & 向其他线程发SIG_KILL信号, (它们收到信号后, 调do_exit())
& &调用do_exit, 使本线程退出
&&do_exit流程:
& &设置线程的终止标志, 退出码
& & 设置PF_EXITING, 标明要被终止
& & 设置pd-&exit_code
& &&&系统调用参数
& &&&或是内核提供的错误码, 表示异常终止
& &释放资源:
& & 删除该进程的定时器
& & 去除对资源的引用:
& &&&exit_mm, __exit_
& &&&__exit_fs(root路径,工作路径, 创建文件权限), exit_namespace(挂载的文件系统的视野);
& &&&exit_thread(thread_struct), exit_sem,
& &如果这个线程的函数实现了一种可执行格式, 可执行格式数的引用计数--; FIXME: 还没看到这块儿, 凑合翻译的不一定对
& &改变父子关系, 并向父进程发信号, 改变自己的状态(exit_notify)
& & 托付终止线程创建的子进程:
& &&&如果终止线程还有同组线程: 终止线程创建的子进程, 作为与同组线程的子进程.
& &&&否则: 终止线程创建的子进程, 作为孤儿进程, 由init进程托管
& & 向父进程发信号
& &&&exit_signal有意义 && 最后线程 :&&发exit_signal
& &&&否则:
& && &被trace : 发SIGCHLD
& && &没被trace : 不发信号
& & 僵尸自己或直接死亡,&&并设置PF_DEAD位
& &&&exit_signal没意义 && 没被trace : 直接死亡 (这种情况没有发信号)
& && &变成EXIT_DEAD状态,
& && &release_task() (后面介绍). pd引用计数变为1, 不会马上释放
& &&&否则: 僵尸
& && &exit_signal有意义 || 被trace : 僵尸
& &&&整理"僵尸"与"发临僵尸信号"的关系:
& && &将发信号的条件中"最后线程"去掉, 可简化为(exit_signal有意义)||(被trace) == (发信号)
& && &可得出后: (发信号) == (僵尸)
& && &又可推出: (没有trace && exit_signal有意义 && 不是最后进程) == (僵尸了,但没法信号) , 这种情况在移除死进程时, 会给其父进程发信号 (FIXME: 待验证)
& &调度. 调度函数会忽略僵尸进程, 但会减少僵尸进程的pd的使用计数; 会检查PF_DEAD位, 把它变成exit_dead状态
进程移除 TODO:
阅读(...) 评论()}

我要回帖

更多关于 windows查看进程命令 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信