全部博文(18)
分类: LINUX
2009-04-29 13:03:58
3.1 进程描述符及任务结构
进程存放在任务队列task list的双向循环链表中;
链表中存放进程描述符,task_struct(定义在
linux通过slab分配器分配task_struct结构,达到对象复用和缓存着色的目的;
slab分配器动态生成task_struct,只需在栈底船舰一个新的结构struct thread_info:
|
每个任务的thread_info结构在它的内核栈的尾端分配,其中的task域指向实际task_struct指针。
current_thread_info()->task;指向当前进程描述符
进程状态:
set_task_state(task, state);设置进程状态
set_current_state(state)与set_task_state(current, state)等价;
进程描述符中还包括进程间的关系,指向父进程的task_struct parent以及称为children的子进程链表
3.2 进程创建
fork()+exec()——fork()通过拷贝当前进程创建一个子进程;exec()读取可执行文件并将其载入地址空间运行。
写时拷贝——父子进程共享同一拷贝,只有在需要写入时,数据才会复制,从而使各个进程拥有各自的拷贝
fork():
调用clone();
clone()调用do_fork();
do_fork()调用copy_process();
(1) 调用dup_task_struct()为新进程创建内核栈、thread_info结构和task_struct,与当前进程值相同;
(2) 父子进程开始区别,子进程描述符中很多成员清0或设置初始值;
(3) 子进程状态设为TASK_UNINTERRUPTIBLE,以保证不会投入运行;
(4) 调用copy_flags()更新task_struct的flags成员,表明进程是否拥有超级用户权限的PF_SUPERPRIV标志清0,表明进程还没调用exec()函数的PF_FORKNOEXEC标志被设置;
(5) get_pid()为新进程获取有效PID
(6) 根据传递给clone()的参数标志,拷贝或共享打开的文件、文件系统信息、信号处理函数、进程地址空间和命名空间等。
(7) 父子进程平分剩余时间片;
(8) copy_process()作扫尾工作并返回一个指向子进程的指针
clone()参数标志:
Flag |
Meaning |
CLONE_FILES |
Parent and child share open files. |
CLONE_FS |
Parent and child share filesystem information. |
CLONE_IDLETASK |
Set PID to zero (used only by the idle tasks). |
CLONE_NEWNS |
Create a new namespace for the child. |
CLONE_PARENT |
Child is to have same parent as its parent. |
CLONE_PTRACE |
Continue tracing child. |
CLONE_SETTID |
Write the TID back to user-space. |
CLONE_SETTLS |
Create a new TLS for the child. |
CLONE_SIGHAND |
Parent and child share signal handlers and blocked signals. |
CLONE_SYSVSEM |
Parent and child share System V SEM_UNDO semantics. |
CLONE_THREAD |
Parent and child are in the same thread group. |
CLONE_VFORK |
vfork() was used and the parent will sleep until the child wakes it. |
CLONE_UNTRACED |
Do not let the tracing process force CLONE_PTRACE on the child. |
CLONE_STOP |
Start process in the TASK_STOPPED state. |
CLONE_SETTLS |
Create a new TLS (thread-local storage) for the child. |
CLONE_CHILD_CLEARTID |
Clear the TID in the child. |
CLONE_CHILD_SETTID |
Set the TID in the child. |
CLONE_PARENT_SETTID |
Set the TID in the parent. |
CLONE_VM |
Parent and child share address space. |
3.3 线程
线程也拥有自己的task_struct,与普通进程的区别是内核线程没有独立的地址空间(mm指针为NULL)
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
一般情况下,内核线程会将创建的函数永远执行下去,该函数由一个循环构成,需要时唤醒并执行,完成任务会自行休眠。
3.4 进程终结
exit()
调用do_exit():
(1) 将task_struct中的标志成员设置为PF_EXITING
(2) 调用del_timer_sync()删除任意内核定时器;
(3) 调用acct_process()来输出记账信息;
(4) 调用__exit_mm()放弃进程占用的内存描述符mm_struct;
(5) exit_sem();
(6) 调用__exit_files(), __exit_fs(), exit_namespace(), exit_sighand() 分别递减文件描述符、文件系统数据、进程名字空间、信号处理函数的引用计数;
(7) 把task_struct中的exit_code成员中的任务退出代码设置为exit()提供的代码;
(8) 调用exit_notify()向父进程发送信号,将子进程的父进程重新设置为线程组中的其他进程或init进程,进程状态设置为TASK_ZOMBE
(9) 调用schedule()切换到其他进程
调用do_exit()后,线程已僵死,但系统保留了进程描述符。
删除进程描述符release_task():
(1) free_uid()减少进程拥有者的进程使用计数;
(2) unhash_process()从pidhash上删除该进程,同时从task_list中删除该进程;
(3) 将跟踪进程的父进程重设为其最初的父进程并将其从ptract list中删除;
(4) 调用put_task_struct()释放进程内核栈和thread_info所占的页,释放task_struct所占的slab高速缓存。