linux进程创造 - 创建进程API及过程

来源:互联网 发布:淘宝联盟链接转换工具 编辑:程序博客网 时间:2024/05/17 23:24

1. 创建进程函数API


1.1 创建进程fork()

fork的翻译为“叉子,分叉”,其实在unix编程中,我们来创建进程的时候是深有体会的,感觉创建一个进程就像是走到了一个岔路口,父进程和子进程在叉路口分道扬镳,所以我想这就是前辈为什么要用fork来表示创建一个进程的缘由吧。

通过fork(),除了task_struct和堆栈,子进程和父进程共享所有的资源,相当于复制了一个父进程,但是由于linux采用了写时复制技术,复制工作不是立即就执行,提高了效率。在unix编程中,调用fork实际上相当于创建了一个进程。

(kernel/fork.c)

SYSCALL_DEFINE0(fork){#ifdef CONFIG_MMU    return _do_fork(SIGCHLD, 0, 0, NULL, NULL, 0);#else    /* can not support in nommu mode */    return -EINVAL;#endif}

1.2 创建进程vfork()

vfork类似于fork,但并不创建父进程数据的副本,相反,父子进程之间共享数据,这节省了大量CPU时间。

vfork设计用于子进程形成后立即执行execve加载新程序的情形。在子进程退出或开始新程序之前,内核保证父进程处于阻塞状态。但是由于fork使用了写时复制技术,vfork速度方面不再有优势,因此应该避免使用它。

(kernel/fork.c)

SYSCALL_DEFINE0(vfork){    return _do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0,            0, NULL, NULL, 0);}

1.3 创建线程clone()

clone翻译为“克隆”,从字面理解就是照着父进程的样子重新生成一个子进程,但是子进程是一个新的个体,和父进程已经少了许多关系。

clone产生线程,可以对父子进程之间的共享、复制进行精确控制。

(kernel/fork.c)

#ifdef CONFIG_CLONE_BACKWARDSSYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,         int __user *, parent_tidptr,         unsigned long, tls,         int __user *, child_tidptr)#elif defined(CONFIG_CLONE_BACKWARDS2)SYSCALL_DEFINE5(clone, unsigned long, newsp, unsigned long, clone_flags,         int __user *, parent_tidptr,         int __user *, child_tidptr,         unsigned long, tls)#elif defined(CONFIG_CLONE_BACKWARDS3)SYSCALL_DEFINE6(clone, unsigned long, clone_flags, unsigned long, newsp,        int, stack_size,        int __user *, parent_tidptr,        int __user *, child_tidptr,        unsigned long, tls)#elseSYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,         int __user *, parent_tidptr,         int __user *, child_tidptr,         unsigned long, tls)#endif{    return _do_fork(clone_flags, newsp, 0, parent_tidptr, child_tidptr, tls);}

1.4 进程创建部分标志的含义

flags description CLONE_VM 共享内存描述符和所有的页表 CLONE_FS 共享根目录和当前工作目录所在的表 CLONE_FILES 共享打开文件表 CLONE_SIGHAND 共享信号处理程序的表、阻塞信号表和挂起信号表 CLONE_VFORK vfork使用的标志 CLONE_PARENT 设置子进程的父进程为调用进程的父进程 CLONE_THREAD 创建线程使用的标志 CLONE_PARENT_SETTID 把子进程的PID写入有ptid参数所指向的父进程的用户态变量 CLONE_CHILD_SETTID 把子进程的PID写入有ctid参数所指向的子进程的用户态变量 CLONE_NEWNS 当clone需要自己的命名空间时设置这个标志

2. _do_fork


上述创建进程的API最后调用的函数都是_do_fork,下面来介绍此函数的工作

(kernel/fork.c)

long _do_fork(unsigned long clone_flags,unsigned long stack_start,unsigned long stack_size,int __user *parent_tidptr,int __user *child_tidptr,unsigned long tls){    struct task_struct *p;    int trace = 0;    long nr;    /*     * Determine whether and which event to report to ptracer.  When     * called from kernel_thread or CLONE_UNTRACED is explicitly     * requested, no event is reported; otherwise, report if the event     * for the type of forking is enabled.     */    if (!(clone_flags & CLONE_UNTRACED)) {        if (clone_flags & CLONE_VFORK)            trace = PTRACE_EVENT_VFORK;        else if ((clone_flags & CSIGNAL) != SIGCHLD)            trace = PTRACE_EVENT_CLONE;        else            trace = PTRACE_EVENT_FORK;        if (likely(!ptrace_event_enabled(current, trace)))            trace = 0;    }    p = copy_process(clone_flags, stack_start, stack_size,----------------复制父进程的一些数据             child_tidptr, NULL, trace, tls);    /*     * Do this prior waking up the new thread - the thread pointer     * might get invalid after that point, if the thread exits quickly.     */    if (!IS_ERR(p)) {        struct completion vfork;        struct pid *pid;        trace_sched_process_fork(current, p);        pid = get_task_pid(p, PIDTYPE_PID);        nr = pid_vnr(pid);        if (clone_flags & CLONE_PARENT_SETTID)            put_user(nr, parent_tidptr);        if (clone_flags & CLONE_VFORK) {            p->vfork_done = &vfork;            init_completion(&vfork);            get_task_struct(p);        }        wake_up_new_task(p);-----------------------------------------------使进程加入运行队列,被调度        /* forking complete and child started to run, tell ptracer */        if (unlikely(trace))            ptrace_event_pid(trace, pid);        if (clone_flags & CLONE_VFORK) {-----------------------------------如果有标志CLONE_VFORK,就等待让子进程先运行            if (!wait_for_vfork_done(p, &vfork))                ptrace_event_pid(PTRACE_EVENT_VFORK_DONE, pid);        }        put_pid(pid);    } else {        nr = PTR_ERR(p);    }    return nr;}

3. copy_process


static struct task_struct *copy_process(unsigned long clone_flags,                    unsigned long stack_start,                    unsigned long stack_size,                    int __user *child_tidptr,                    struct pid *pid,                    int trace,                    unsigned long tls)

copy_process的流程图如下所示,其中代码细节部分会在文章系列的子部分详细说明:

这里写图片描述

change log


date content linux kernel 2016.11.20 原始写作 4.6.3
1 0