Linux fork()一个进程内核态的变化
Posted FireLightning
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux fork()一个进程内核态的变化相关的知识,希望对你有一定的参考价值。
【前言】用户态的变化,耳熟能详不在赘述。现在支持读时共享,写时复制。
一、内核态的变化
1、fork一个子进程代码
#include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(int argc, char * argv[]) { int pid; /* fork another process */ pid = 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"); } }
2、创建一个新进程在内核中的执行过程
fork、vfork和clone三个系统调用都可以创建一个新进程,而且都是通过调用do_fork来实现进程的创建;
3、Linux通过复制父进程来创建一个新进程,那么这就给我们理解这一个过程提供一个想象的框架:
(1)复制一个PCB——task_struct
err = arch_dup_task_struct(tsk, orig);
(2)要给新进程分配一个新的内核堆栈
(注意,是内核栈,不是用户堆栈,用户态的是复制的)
ti = alloc_thread_info_node(tsk, node); tsk->stack = ti; setup_thread_stack(tsk, orig); //这里只是复制thread_info,而非复制内核堆栈
(3)要修改复制过来的进程数据,比如pid、进程链表等等都要改改吧,见copy_process内部。
4、从用户态的代码看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; //调度到子进程时的第一条指令地址
以上是关于Linux fork()一个进程内核态的变化的主要内容,如果未能解决你的问题,请参考以下文章
结合中断上下文切换和进程上下文切换分析Linux内核的一般执行过程
结合中断上下文切换和进程上下文切换分析Linux内核的一般执行过程