摘要: mqy + 原创做品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000node
操做系统的三大功能:进程管理,内层管理,文件系统linux
最核心:进程管理编程
进程控制块PCB——task_struct数据结构
为了管理进程,内核必须对每一个进程进行清晰的描述,进程描述符提供了内核所需了解的进程信息。框架






进程的pid标示某一进程函数

进程的父子关系管理this
作调试用:操作系统

fork一个子进程的代码3d
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- int main(int argc, char * argv[])
- {
- int pid;
- /* fork another process */
- pid = fork();//fork在用户态用于建立一个子进程的系统调用
- if (pid < 0)
- {
- /* error occurred */
- fprintf(stderr,"Fork Failed!");
- exit(-1);
- }
- else if (pid == 0)
- {
- /* child process */
- printf("This is Child Process!\n");
- }
- else
- {
- /* parent process */
- printf("This is Parent Process!\n");
- /* parent will wait for the child to complete*/
- wait(NULL);
- printf("Child Complete!\n");
- }
- }
fork系统调用在父进程和子进程各返回一次调试
建立一个新进程在内核中的执行过程
- fork、vfork和clone三个系统调用均可以建立一个新进程,并且都是经过调用do_fork来实现进程的建立;
- Linux经过复制父进程来建立一个新进程,那么这就给咱们理解这一个过程提供一个想象的框架:
- 复制一个PCB——task_struct
- err = arch_dup_task_struct(tsk, orig);
- 要给新进程分配一个新的内核堆栈
- ti = alloc_thread_info_node(tsk, node);
- tsk->stack = ti;
- setup_thread_stack(tsk, orig); //这里只是复制thread_info,而非复制内核堆栈
- 要修改复制过来的进程数据,好比pid、进程链表等等都要改改吧,见copy_process内部。
- 从用户态的代码看fork();函数返回了两次,即在父子进程中各返回一次,父进程从系统调用中返回比较容易理解,子进程从系统调用中返回,那它在系统调用处理过程当中的哪里开始执行的呢?这就涉及子进程的内核堆栈数据状态和task_struct中thread记录的sp和ip的一致性问题,这是在哪里设定的?copy_thread in copy_process
- *childregs = *current_pt_regs(); //复制内核堆栈
- childregs->ax = 0; //为何子进程的fork返回0,这里就是缘由!
-
- p->thread.sp = (unsigned long) childregs; //调度到子进程时的内核栈顶
- p->thread.ip = (unsigned long) ret_from_fork; //调度到子进程时的第一条指令地址
进程穿件概览及fork一个进程的用户态代码
理解进程建立过程复杂代码的方法
建立新进程是经过复制当前进程来实现的
系统调用内核处理函数sys_fork,sys_clone,sys-vfork

拷贝内核堆栈数据和指定进程的第一条指令进程
Int指令和SAVE_ALL压到内核栈的内容
实验:分析linux内核建立一个新进程的过程
过程同上次相似,首先更新MenuOS


gdb调试fork

设置断点并调试

linux如何建立一个新进程:Linux经过复制父进程来建立一个新进程,经过调用do_ fork来实现并为每一个新建立的进程动态地分配一个task_ struct结构