进程是程序执行时的一个实例。你可以把他看做充分描述程序已经执行到何种程度的数据结构的汇集。
完全没有用户空间,内核线程
共享用户空间,用户线程
一个进程必定同时又是一个内核线程
task_struct通过pidhash_next与pidhash_pprev两个指针连入到杂凑表的某个队列中
线性队列的第一个建立的进程为init_task,这个进程是所有进程的总根,这个线性队列就是以init_task为起点,每个进程都是通过其task_struct结构中的next_task和prev_task两个指针链入这个线性队列中
task_struct中进程状态:
可运行状态 TASK_RUNNING(就绪态)
可中断等待状态TASK_INTERRUPTIBLE(睡眠,进程被挂起)
不可中断的等待状态TASK_UNINTERRUPTIBLE()
暂停状态TASK_STOPPED(进程的执行被暂停)
跟踪状态TASK_TRACED(进程的执行由debugger程序暂停)
僵死状态EXIT_ZOMBIE(进程的执行被终止,父进程还没有通过系统调用来返回有关死亡进程的信息)
僵死撤销状态EXIT_DEAD(最终状态)
内核使用alloc_thread_info和free_thread_info宏分配和释放存储thread_info结构和内核栈的内存区
current->pid返回在cpu上正在执行的进程的pid
用list_head数据结构构造一个双向列表
处理函数和宏:
list_add(n,p)把n指向的元素插入p所指向的特定元素之后
list_add_tail(n,p)把n指向的元素插入p所指向的特定元素之前
list_del(p)删除p所指定的元素
list_empty(p)检测由第一个元素的地址p指定的链表是否为空
list_entry(p,t,m)返回类型为t的数据结构的地址,其中类型t中含有list_head字段,而list_head字段中含有名字m和地址p
list_for_each(p,h)对表头地址h指定的链表进行扫描,在每次循环时,通过p返回指向链表元素的list_head结构的指针
list_for_each_entry(p,h,m)与list_for_each类似,但是返回包含list_head结构的数据结构的地址,而不是list_head结构本身的地址
进程列表把所有进程的描述符链接起来,每个task_struct结构都包含一个list_head类型的tasks字段,prev与next分别指向前一个和后一个task_struct元素
进程链表头是init_task描述符,它是所谓的0进程或swapper进程的进程描述符,init_task的tasks.prev字段指向链表的最后插入的进程描述符的tasks字段
for_each_process(p), 扫描整个进程链表,从init_task开始
在多处理器系统中,每个cpu都有它自己的运行队列(TASK_RUNNING状态的进程链表)
real_parent 指向创建了P的进程的描述符(如果父进程不存在了,就指向init进程的描述符->用户运行后台程序后关闭shell,此程序就指向init_task)
parent指向P的当前父进程,通常与real_parent一致
children链表的头部,链表的所有元素都是P创建的子进程
sibling指向兄弟进程链表中的下一个元素或者前一个元素的指针,这些兄弟进程的父进程都是P
P0创建了P1,P2,P3,进程P3又创建了P4
pid_hashfn宏把PID转化为表索引,散列函数(hash)并不总能确保PID与表的索引一一对应。两个不同的PID散列到相同的表的索引称为冲突