张潇月+《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
进程描述符task_struct数据结构
进程描述符提供了内核所需要了解的内核信息。task_struct数据结构十分庞大。
Linux的进程状态和与操作系统原理中描述的进程状态似乎有所不同。本质上是一样的,就绪态,运行态,阻塞态。
所有的进程状态
进程标识符
进程的链表
它是一个双向链表,把所有的进程连接起来。链表是可以独立进行操作的,
每个进程有自己独立的进程地址空间。
父子关系
这就是进程中父子关系的管理
ptraced是调试用的。
进程的创建
fork系统调用在父进程和子进程各返回一次,这样就变成了两个进程。通过这个fork()系统调用就可以在用户态创建一个进程。
正常的系统调用:
调用fork()的时候
父进程还是和一般正常调用一般返回,而fork产生的子进程在内核里面返回。
fork、vfork、clone都可以创建新的进程,而且都是通过调用do_fork来实现进程的创建。
创建新进程是通过复制当前进程来实现的。
Linux通过复制父进程来创建一个新进程,那么为我们理解这个过程提供一个理想的框架:
系统调用内核处理函数sys_fork、sys_vfork、sys_clone。
dup task struct——复制task struct。
子进程
子进程是从return_from_fork开始执行的,然后挑战到syscall_exit,到系统调用中返回。
实验
启动MenuOS
在新窗口中启动调试gdb
设置断点
在MenuOS中执行fork,就会发现fork函数停在了父进程中
继续执行之后,停在了do_fork的位置。然后n单步执行,依次进入copy_process、dup_task_struct。按s进入该函数,可以看到dst = src(也就是复制父进程的struct)
在copy_thread中,可以看到把task_pg_regs(p)也就是内核堆栈特定的地址找到并初始化
到了159、160行的代码就是把压入的代码再放到子进程中:
*children = *current_pt_regs();
childregs->ax = 0;
164行,是确定返回地址
p->thread.ip = (unsigned long) ret_from_fork;