fork, vfork, clone,pthread_create,kernel_thread

fork, vfork, clone,pthread_create,kernel_thread 

fork,vfork,clone,都是系统调用,以前还以为是前面两个是clone的封装,实际上前三个都是系统调用,pthread_create是对clone的封装,kernel_thread用于创建内核线程
fork 在内核中调用
do_fork(SIGCHLD, regs.esp, &regs, 0, NULL, NULL)

vfork:
do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, &regs, 0, NULL, NULL)

clone:
do_fork(clone_flags, newsp, &regs, 0, parent_tidptr, child_tidptr)
其中 clone_flags = regs.ebx;
newsp = regs.ecx;
parent_tidptr = (int __user *)regs.edx;
child_tidptr = (int __user *)regs.edi;

pthread_create:
  pid = __clone(__pthread_manager_event,
(void **) __pthread_manager_thread_tos,
CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
(void *)(long)manager_pipe[0]);   
kernel_thread:
do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL)
在执行这个函数之前,在栈中对regs作了初始化,把自己的参数塞进起,并设regs.eip=kernel_thread_helper,具体流程参见前一篇文章。
可见他们的不同主要在于flag的不同,为什么前两个都有SIGCHLD,把保护用户态寄存器的地址传递是为什么?进程的到底是怎么切换的?
先看do_fork,首先分配一个PID,调用copy_process()进行具体的拷贝,如果flag里有CLONE_VFORK,将父进程放入一个等待队列,所以子进程先运行。

copy_process()
This creates a new process as a copy of the old one, but does not actually start it yet.It copies the registers, and all the appropriate parts of the process environment.
p = dup_task_struct(current);   为子进程分配task_struct和内核stack.
然后copy_files(),copy_fs()进行拷贝。
copy_thread,把用户传进来的通用寄存器进行拷贝给子进程并设置,这儿很关键

childregs = task_pt_regs(p);
*childregs = *regs;
childregs->eax = 0;
childregs->esp = esp;

p->thread.esp = (unsigned long) childregs;
p->thread.esp0 = (unsigned long) (childregs+1);

p->thread.eip = (unsigned long) ret_from_fork;
可见传入的用户态通用寄存器附给了子进程,并置eax=0所以返回的pid是0,估计是pt_regs里没有esp,所以单独赋值了。task_struct的thread字段记录了进程特定于cpu的信息,但切换到子进程的时候,就把thread中esp,eip弹出,所以子进程就可以通过ret_from_fork返回运行了。
而ret_from_fork
asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
不明白。
至于前面说道的SIGCHLD,估计是设置子进程挂了的时候给父进程发个SIGCHLD信号。也没看到在哪儿设。
所谓创建一个进程,就是创建task_struct和内核stack,并把stack里的pt_regs设置下,返回的时候好恢复到调用点,并选择性的继承父进程的资源。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Linux的`clone()`系统调用是用于创建一个新的进程或线程的,其原型定义如下: ```c int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ... /* pid_t *ptid, void *newtls, pid_t *ctid */ ); ``` 其中,`fn`参数是一个函数指针,指向新进程或线程要执行的函数;`child_stack`参数是新进程或线程使用的栈空间;`flags`参数是一个标志位,用于指定新进程或线程的属性;`arg`参数是传递给新进程或线程的参数;`ptid`参数返回新线程的线程ID;`newtls`参数指向新线程的TLS(Thread Local Storage)指针;`ctid`参数返回新进程的进程ID。 `clone()`系统调用的标志位参数`flags`可以指定以下常量: - `CLONE_VM`:共享虚拟内存空间; - `CLONE_FS`:共享文件系统信息; - `CLONE_FILES`:共享文件描述符表; - `CLONE_SIGHAND`:共享信号处理函数; - `CLONE_PTRACE`:允许被跟踪; - `CLONE_VFORK`:创建一个子进程,但是子进程与父进程共享内存空间; - `CLONE_NEWPID`:创建一个新的PID命名空间; - `CLONE_NEWUTS`:创建一个新的UTS命名空间; - `CLONE_NEWNS`:创建一个新的Mount命名空间; - `CLONE_NEWIPC`:创建一个新的IPC命名空间; - `CLONE_NEWNET`:创建一个新的网络命名空间; - `CLONE_NEWUSER`:创建一个新的用户命名空间。 `clone()`系统调用的返回值为: - 在父进程中,返回新进程或线程的进程ID或线程ID; - 在子进程或线程中,返回0; - 出错时,返回-1,并设置errno变量。 需要注意的是,`clone()`系统调用是非常底层的系统调用,通常情况下我们不会直接使用它来创建新的进程或线程,而是使用更高层次的API,如`fork()`、`pthread_create()`等。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值