Linux内核对进程管理是操作系统的重要任务之一。此次实验就是了解内核创建一个新进程的大致过程。为了简单,使用fork再用户态创建一个进程。代码如下:#include
#include
#include
int main(int argc, char * argv[])
{
int pid;
/* fork another process */
pid = fork();
if (pid
{
/* 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");
}
}
在虚拟机环境中运行情况如下图:
以下使用gdb调试一下,在进程创建过程中的几个关键函数出设置断点。
在系统启动过程走了些弯路,设置断点的这几个函数都是系统创建进程所必须的关键部分,所以启动过程中do_fork,copy_process,copy_thread不断的多次出现,我只好暂时使断点失效,才让menuos顺利启动到命令提示符。disable breakpoints 1 2 3 4 5 6.
执行fork命令,停在了断点SyS_clone处,单步执行,定在了断点do_fork处。经过几行代码,
p = copy_process(clone_flags, stack_start,stack_size,chile_tidptr, NULL,trace);
停在断点copy_process.在执行几行代码,如下:
p = dup_task_struct(current);
继续执行,断点arch_dup_task_struct停住。
连续n命令后可以看到子进程的初始化过程:
程序执行断在copy_thread后如下:
执行finish,及continue命令,进入了子进程执行的起点ret_from_fork.
执行c命令,主要过程基本结束。
总结,创建一个新进程在内核中的执行过程大致如下
1.使用系统调用SyS_clone(或fork,vfork)系统调用创建一个新进程,而且都是通过调用do_fork来实现进程的创建;
2.Linux通过复制父进程PCB--task_struct来创建一个新进程,要给新进程分配一个新的内核堆栈;
3.要修改复制过来的进程数据,比如pid、进程链表等等执行copy_process和copy_thread
4.p->thread.sp = (unsigned long) childregs; //调度到子进程时的内核栈顶
p->thread.ip = (unsigned long) ret_from_fork; //调度到子进程时的第一条指令地址