Linux系统进程基础知识描述

嵌入式技术

1372人已加入

描述

Linux进程描述符如下

进程描述符都是task_struct类型结构,它的域包含了与一个进程相关的所有信息。

PID

进程状态

运行状态

暂停状态

可中断的等待状态:进程被挂起(睡眠),直到一些条件变为真。

不可中断的等待状态:这种情况用的很少,当进程打开一个设备文件时,其相应的设备驱动程序开始探测相应的硬件设备时会用到这个状态。

僵死状态:进程执行被终止,但是,父进程还没发布wait()类系统调用以返回死进程有关的信息,父进程在发布wait()调用前,不能丢弃死进程的描述符的数据,因为父进程可能还要使用。

标识一个进程

目前,pthread库已合并到标准的C库中,并吸收了轻量级进程的优点。

其中,任何类Unix操作系统允许用户使用一个叫做进程标识符PID的数来标识进程。PID是32位无符号整数,存放在进程描述符的pid域中。PID被顺序编号(最大为32767)。

任务数组:内核在它自己的地址空间保存了一个全局静态数组task,数组中的元素就是进程描述符指针。

因为进程是动态实体,因此其被存放在动态内存中,而不是存放在永久性分配给内核的内存区。

进程描述符和进程内核态堆栈的存放:

 

PID

esp寄存器是CPU栈寄存器,用来存放栈顶的地址。Intel系统中,栈起始于末端,并朝这个内存区开始的方向增长。从用户态切换到内核态以后,进程的内核态堆栈的内核态堆栈总是空的,因此,esp寄存器直接指向这个内存区的顶端。

每个进程都拥有独立的内核栈和机器上下文,资源描述符,当用户态进程进入内核态执行内核代码时,需要保存运行时刻的栈与机器上下文。

进程链表

一个双向循环链表把所有进程联系起来:

PID

当然如果扫描所有进程找出可运行的进程是非常低效的,所以可以专门设一个可运行进程链表。当然还有空闲链表。

PIDhash表

为了方便kill()函数利用PID号杀死进程,产生了PIDhash表,表项即为进程描述符,当进程描述符冲突时(因为将进程描述符加入表时是通过散列函数分配的 NR_TASKS/4),Linux利用链接表来处理冲突的PID号。

PID

进程切换

为了控制进程的执行,内核必须有能力挂起正在CPU上运行的进程,并恢复以前挂起的某个进程的执行。

硬件上下文

因所有进程共享CPU寄存器,所以进程切换时需要将硬件上下文部分存放在TSS段(任务状态段),而剩余部分保存在内核态堆栈。

进程切换只发生在内核态。在进程切换执行之前,用户态下的进程使用的所有寄存器的内容都已被保存,这也包括指定用户态堆栈指针地址的ss和esp寄存器的内容。

 每个进程包含有它自己最小长度为104字节的TSS段。操作系统还需要额外的字节来存放硬件不能自动保存的寄存器以及I/O的访问权位图。需要这种位图是因为ioperm()及iopl()系统调用可以允许用户态进程直接访问特殊的I/O端口。尤其是,如果把eflag寄存器的IOPL域设置为3,就允许用户态的进程访问权位图位为0的任何一个I/O端口。

GDT中存放着TSSD选择符指向TSS,但这样通过GDT查找很麻烦,所以在tr寄存器中包含了当前正在CPU上运行的TSSD选择符和两个非编程域Base域和Limit域。

内核线程
        
在Linux中,内核线程在以下几个方面不同于普通进程:

每个内核线程执行一个单独指定的内核函数,而普通进程只有通过系统调用执行内核函数。

内核线程只允许在内核态,而普通进程既可以运行在内核态,也可以运行在用户态。

因为内核线程只运行在内核态,它们只使用大于PAGE_OFFSET的线性地址空间。另一方面,不管是在用户态还是内核态,普通进程可以使用4GB的线性地址空间。

进程0

所有进程的祖先叫做进程0,或因为历史原因叫做swapper进程,它在Linux内核初始化阶段从无到有创建一个内核线程/进程。

进程0创建内核线程执行init()函数初始化四个必要的线程(处理内存高速缓存及交换活动),init()调用execve()系统调用装入可执行程序init。因此init内核线程变成一个普通进程,它拥有自己的内核数据结构,且从不终止,因为它创建和监控OS外层的所有所有进程活动。

当撤销进程时,由终止进程创建的所有进程都成为init的子进程。避免孤儿进程的出现。



审核编辑:刘清

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分