在内核的_do_fork()函数中经过前面的一系列操作后调用 wake_up_new_task(p); 将子线程放入运行队列中开始运行,那么在后面的 wait_for_vfork_done(p, &vfork) 函数不应该是父线程和子线程都会运行一遍该函数,将父线程和子线程的 struct task_struct current 都创建等待队列来进行休眠吗?怎么最后只休眠了父线程啊?求解!
当copyProcess之后新的 process已经独立出来了。copy_thread的时候会给它设定新的起始点(也就是他的PC 寄存器的值)。
当 你wake_up_new_task的时候。新的process or thread会从设定的起始位置开始运行。而不是跟 主进程一样。顺着跑起来的。所以后面的wait_for_vfork_done, 只有父进程会跑到。。子进程是跑不到的。
好的,谢谢,另外对于上图pc指针的初始化是这样的吧
copy_process
->copy_thread_tls
->copy_thread
->ret_from_fork
->asmlinkage void ret_from_fork(void) asm("ret_from_fork");
最后跳转到汇编,pc指针将指向调度函数使该线程返回到用户态
在 Linux 内核中,do_fork() 函数用于创建一个新的进程或线程(任务)。如果在创建子线程时使用了 vfork,它是一种特殊的 fork,会阻塞父进程,直到子进程调用 exec 系列函数或 _exit 函数。这是因为 vfork 的目的是在子进程中执行一个新的程序,子进程会与父进程共享地址空间,因此父进程需要等待子进程完成。
在 do_fork() 中,当创建子线程时,确实会有一些处理来保证父线程等待子线程的完成,但是并不会通过 wait_for_vfork_done() 函数来进行父线程和子线程都等待的处理。
这是因为 wait_for_vfork_done() 是在 vfork 的子进程中调用的,用于通知父进程子进程已经准备好继续执行了。父进程的等待是通过 vfork_done 标志来完成的。父进程会在 _exit 或者 exec 系列函数调用时被唤醒,然后继续执行。
总之,vfork 通过共享地址空间的方式来实现效率高的创建子进程,但是在子进程执行新程序之前,会阻塞父进程。所以在内核实现中,并不需要父线程和子线程都进入休眠等待状态。子线程执行时会通知父线程,而父线程会在适当的时候恢复执行。