#内核调度的对象是线程,不是进程
#对Linux而言,线程只是特殊的进程
#进程提供两种虚拟机制:虚拟处理器、虚拟内存
#创建进程通过fork()来从父进程复制创建进程
#任务队列:双向链表(每一项都是task_struct--->进程描述符)
#Linux通过slab分配器分配task_struct
#内核通过唯一的进程标识值(PID)来标识进程
#五种进程状态: 1.TASK_RUNNING 进程可执行
2.TASK_INTERRUPTIBLE 可中断
3.TASK_UNINTERRUPTIBLE 不可中断
4._TASK_TRACED 被其他进程跟踪
5._TASK_STOPPED 进程停止执行
#设置进程状态: set_task_state(task, state)函数和set_surrent_state(state)函数
#所有进程都是PID为1的init进程的后代
#init进程描述符 init_task
#fork()和exec()
fork()拷贝当前进程创建子进程
exec()读入可执行文件并载入空间地址开始执行
#写时拷贝:fork()使用写时拷贝(copy-on-write)使得地址空间的页拷贝被推迟到实际发生写入时才进行
(fork()后立即执行exec()就无需进行拷贝)
fork()的实际开销就是复制父进程的页表以及分配进程描述符
#fork()执行过程:通过系统调用clone()调用fork()
clone()调用do_fork(),do_fork()调用copy_process()
copy_process()过程:
1.调用dum_task_struct()为新进程创建内核栈、thread_info、task_struct
2.确保创建子进程后当前进程数没有超过限制
3.子进程开始与父进程区别开来,进程描述符中的许多成员初始化或清0
4.子进程的状态被设置为TASK_UNINTERRUPTIBLE
5.调用copy_flags()更新来更新task_struct的flags成员
6.调用alloc_pid()为新进程分配PID
7.copy_process()拷贝共享打开的文件、文件系统信息、信号处理函数、进程地址空间和命名空间
8.copy_process()做扫尾工作并返回一个指向子进程的指针
#vfork():向clone()系统调用传递一个特殊标志来进行:
? ?1.调用copy_process()时,task_struct的vfork_done成员被设置为NULL
? ?2.如果执行do_fork()时给定地址,vfork_done会指向一个特定地址
? ?3.子进程开始执行后,父进程不会立即开始执行,直到vfork_done指针向它发出信号
? ?4.调用mm_release()进程退出地址空间,并检查vfork_done是否为空,若不为空,等待父进程发送信号
? ?5.回到do_fork(),父进程醒来并返回
#线程机制提供了在同一程序中共享内存地址的空间运行的一组线程
#Linux将所有的线程当做进程来实现
#创建线程:
?clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND , 0)
#发生在进程调用exit()系统调用时:
?任务大部分要靠do_exit()来完成:
? ?1.将task_struct的标志成员设置为PF_EXITING
? ?2.调用del_timer_sync()删除任一内核定时器
? ?3.如果BSD的进程记账开启,do_exit()调用acct_update_integrals()来输出记账信息
? ?4.调用exit_mm()释放进程占用的mm_struct
? ?5.调用sem_exit(),如果进程等待IPC信号,则离开队列
? ?6.调用exit_files()和exit_fs()
? ?7.把存放在task_struct的exit_code成员中的任务退出代码置为由exit()提供的退出代码
? ?8.调用exit_notify()向父进程发送信号,为子进程寻找养父,养父为线程组中的其他线程或者init,并把进程状态设为EXIT_ZOMBIE
? ?9.do_exit()调用schedule()切换到新的进程
#删除进程描述符:调用了do_exit(),进程僵死,但是系统还保留了进程描述符
?释放进程描述符时,release_task()会被调用:
? ?1.调用_exit_signal(),该函数调用_unhash_process(),后者又调用 detach_pid()从pidhash上删除该进程,同时也要从任务列表中删除该进程
? ?2._exit_signal()释放目前僵死进程的资源,进行统计记录
? ?3.如果该进程为进程组最后一个进程,并且领头已经死掉,release_task()通知领头进程的父进程
? ?4.release_task()调用put_task_struct()释放进程内核栈和thread_info所占的页
#孤儿进程造成的进退维谷:如果父进程在子进程之前退出,必须有机制保证子进程能找到新的父亲
原文地址:http://blog.csdn.net/luoyhang003/article/details/40262147