分类: LINUX
2008-12-22 09:25:08
Kernel阅读手记之进程
每个进程都有独立的task_struct,里面包含了进程的相关信息,可以通过pid标记不同的进程。
do_fork负责处理clone(),fork(),vfork()系统调用,三个系统调用在使用do_fork时仅仅时标志不同
1、 当clone_flags中没有CLONE_STOPPED标记时,定义一个静态的,子大部分时候用于读操作的计数器count,并设置初始值为100
2、 当count大于0,并且printk_ratelimit()返回值不为0时,count减1,输出信息
3、 如果是用户态调用的,则准备创建一个新的克隆子程序,内核态则不需要对trace做其他修改
4、 把p设置成新复制的子进程。复制的东西有寄存器、和所有父进程环境中合适的部分。但是不运行此进程。
5、 当p设置成功时,得到p的进程号交给nr
6、 处理带有CLONE_PARENT_SETTID,CLONE_VFORK标签的情况
7、 在p运行前通知父进程准备运行p
8、 清除p的标签中的PF_STARTING
9、 当clone_flags 中没有CLONE_STOPPED标签时,标记p,并设置p的状态为停止等待结束状态。否则,开始p这个进程
10、 通知父进程,当前P已经开始运行
11、 clone_flags中含有CLONE_VFORK标签时,如果当前进程是用户态时,停止计数直到当前completion的结束,通知其父进程,不含有CLONE_VFORK标签时,将nr的值设置为PTR_ERR(p)
12、 返回nr
copy_process()作用是创建进程的描述符及子进程执行所必须的其他数据结构,在do_fork()的第四步中使用
1、 当clone_flags中有错误的参数时,返回错误代码
2、 使用security_task_create()对clone_flags进行安全性检查,返回值赋值给retval,不为0时,返回错误
3、 将retval设置成-ENOMEM
4、 调用dup_task_struct对current的子进程分配进程描述符,将结果交给p,错误则返回ERR_PTR(retval)
5、 将retval的值设置成-EAGAIN
6、 当前进程拥有者所拥有的进程的数量大于等于p->signal->rlim[RLIMIT_NPROC].rlim_cur,并且进程没有root权限,CAP_SYS_ADMIN和CAP_SYS_RESOURCE不被允许时,返回错误
7、 p->user的__count和processes以及p->group_info->usage增加1
8、 如果系统中的当前进程数大于系统上限时,或者无法得到其模块,或者linux所接受的二进制形式时,回滚操作并返回错误
9、 设置p->did_exec 的值为1 ,初始化p的参数
10、 将执行调度相关的设置交给一个cpu来做
11、 对retval的值进行错误处理
12、 如果pid不是初始化之后的,设置retval 为-ENOMEM,并重新分配一个pid,当clone_flags中有CLONE_NEWPID标签时重新设置retval的值,同时进行错误处理
13、 当前运行的命名空间和新进程p的命名空间不相同时,重新设置retval的值为ns_cgroup_clone(p, pid),失败,则返回错误
14、 设置p的子进程的创建和释放iangde属性tid
15、 当CLONE_PTRACE取消时,关闭系统调用
16、 设置当前进程的id为父进程id
17、 设置进程最后部分,在可能情况下运行cgroup callbacks,确保其可用,但是不唤醒
18、 用写锁锁上tasklist_list
19、 将当前进程的值赋值给p,锁住当前进程的siglock,当前进程的标志不为TIF_SIGPENGIND时, 报错返回
20、 clone_flags中有CLONE_THREAD标志时,复制当前进程的线程给p
21、 如果p不是idle时,设置p的兄弟进程,通知当前的子进程p已经创建成功正在使用中
22、 如果p是线程组的头一个线程时,如果标签中有CLONE_NEWPID标记,则设置p->nsproxy->pid_ns->child_reaper为p。将当前进程的部分属性复制给p,并将p加入rcu队列。将p加入哈希序列,nr_threads加1
23、 total_forks加1,解除自旋锁和写锁,连接p,在p加入运行队列后调用一个新task
do_group_exit()退出属于current线程组的所有进程,接受进程的终止代码作为参数
1、 当所有线程的except ->group_exit_task有SIGKILL信号时,设置exit_code为sig->group_exit_code
2、 或者dangerous当前线程组为空时,定义一个sighand_struct *const类型的 sighand为current->sighand,锁住其siglock,如果当前进程的signal的except ->group_exit_task有SIGKILL信号时,设置exit_code的值为sig->group_exit_code,否则,设置sig->group_exit_code为 exit_code,并将sig的标签设置成 SIGNAL_GROUP_EXIT。杀死当前线程组中的其他进程
3、 解除自旋锁
4、 调用do_exit并传递进程的exit_code
do_exit()从内核数据结构中删除对终止进程的引用
1、 当前进程没有PF_EXITING时,设置PF_EXITING标签,尝试关闭进程上下文,设置当前的状态为不可中断,重新调度
2、 设置PF_EXITING给当前进程
3、 解除自旋锁
4、 更新task_struct 中的累积的时间和内存管理模块
5、 tsk->signal->live减1,并将结果传给group_dead,不为0时,尝试释放tty、hrtimer、itimers
6、 释放信号量、task->files、task->fs,退出线程,cgroup、线程锁、模块,通知相应的进程,并且在pid释放之后再检查链表和状态缓存,并清空。
7、 设置tsk标志为PF_EXITPIDONE,退出进程的i/o上下文,管道信息。关闭优先级,设置tsk的状态为TASK_DEAD
8、 调用schedule()调度程序运行