fork()的底层实现

 

  • fork之后父进程与子进程的区别
  1. 进程ID不同;(父进程的返回值是子进程的ID)
  2. 子进程中tms_utime  tms_stime  tms_cutime和tms_ustime的值设为0;
  3. 子进程不继承父进程设置的文件锁(子进程继承了父进程中的所有互斥锁、读写锁和条件变量(包括他们的状态),在多线程中,另做处理);
  4. 子进程的未处理闹钟会被清除;
  5. 子进程的未处理信号集设置为空集;
  • 子进程会继承父进程的
  1. 堆栈
  2. 内存;
  3. 打开文件的描述符;
  4. Nice值;(该值表示优先级,数值越小,优先级越高);
  5. 进程组号;
  6. 当前工作目录;
  • fork()源码剖析

Fork()底层调用do_fork实现。

在do_fork()中:(1)定义PCB指针struct task_struct *p;(2)分配PID(用cat /proc/sys/kernel/pid_max命令可以查看一个系统支持的最大进程数,进程数的范围0--32768);(3)调用copy_process方法,复制进程描述符;

 

通过pidmap_arry位图,为子进程分配新的pid参数

调用dup_task_struct为子进程获取进程描述符。

分配PCB,继承父进程的PCB值,只是将特有的信息改过来。每个进程都有task_thread。thread_info结构体保存的是进程上下文的信息。要修改thread_info *info,子进程的task_struct的成员struct thread_info *info指向自己的struct thread_info,而且struct thread_info结构体成员struct task_struct *p指向子进程自己的struct task_struct.

 

接下来就是对父进程信息的复制比如:copy_files复制父进程打开的文件描述符;copy_fs,copy_mm,copy_namespace;重点看了copy_mm;

 

Copy_mm是复制地址空间。

通过建立新进程的所有页表和内存描述符来创建进程的地址空间,通常每个进程都有自己的地址空间,但是轻量级进程共享同一地址空间,即允许他们对同一组页进行寻址,其中还会调用dup_mmap复制线性区和页表,设置mm的一些属性,改变父进程的私有,可写的页为只读,以使写时拷贝技术生效。

 

调用copy_thread()复制父进程的内核栈。

调用copy_thread,用发出clone系统调用时CPU寄存器的值(他们保存在父进程的内核栈中)来初始化子进程的内核。不过,copy_thread把eax寄存器对应字段的值(这是fork和clone系统调用在子进程中的返回值)强行置为0.子进程描述符的thread.esp字段初始化为子进程内核栈的基地址。Ret_from_fork的地址存放在thread.eip中。如果父进程使用IO权限位图。则子进程获取该位图的一个拷贝。最后,如果CLONE_SETTLs标志被置位,则子进程获取由CLONE系统调用的参数tls指向的用户态数据结构所表示的tls段。

猜你喜欢

转载自blog.csdn.net/m0_37962600/article/details/81407494
今日推荐