Linux_进程创建

进程创建

1、linux创建进程的方式是先通过调用fork创建一个和调用进程基本一样的子进程,二者之间的区别在于PID和PPID不同。然后子进程调用exec函数装载一个新的进程到地址空间执行。
其他的操作系统产生子进程的方式是spawn:在新的地址空间中创建进程,然后载入可执行文件执行。
2、传统的fork是将所有的资源都复制给新的进程,但linux使用了COW(copy-on-write)技术,只有在需要写入的时候才复制整个地址空间。这样做的好处就是当子进程产生之后如果立刻调用exec就不必复制了。
3、fork,vfork,__clone都是通过传给clone不同的参数来实现的。clone调用do_fork来实现进程的创建。

do_fork函数
①调用copy_process来完成进程的复制

p = copy_process(clone_flags, stack_start, regs, stack_size,child_tidptr, NULL, trace);

②调用wake_up_new_task让子进程先执行

wake_up_new_task(p, clone_flags);

③返回新创建进程的pid

copy_process函数
①根据clone_flags执行一些检查

if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))
        return ERR_PTR(-EINVAL);
    if ((clone_flags & CLONE_THREAD) && !(clone_flags & CLONE_SIGHAND))
        return ERR_PTR(-EINVAL);
    if ((clone_flags & CLONE_SIGHAND) && !(clone_flags & CLONE_VM))
        return ERR_PTR(-EINVAL);
    if ((clone_flags & CLONE_PARENT) &&
                current->signal->flags & SIGNAL_UNKILLABLE)
        return ERR_PTR(-EINVAL);

    retval = security_task_create(clone_flags);
    if (retval)
        goto fork_out;

    retval = -ENOMEM;

②调用dup_task_struck函数复制进程描述符和thread_info,此时父子进程完全一样

p = dup_task_struct(current);
    if (!p)
        goto fork_out;

③执行检查判断是否超出给他分配的资源的限制

if (atomic_read(&p->real_cred->user->processes) >=
            p->signal->rlim[RLIMIT_NPROC].rlim_cur) {
        if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) &&
            p->real_cred->user != INIT_USER)
            goto bad_fork_free;
    }

④初始化子进程描述符中的各个值,包括:

  • 将进程的state设置为TASK_UNINTERRUPTIBLE
  • 为子进程分配一个pid
  • 初始化进程描述符内的各个指针
  • 父子进程平分时间片

⑤返回进程描述符

dup_task_struck函数
①调用alloc_task_struct分配一块进程描述符的空间

tsk = alloc_task_struct();
    if (!tsk)
        return NULL;

②调用alloc_thread_info分配一个thread_info

ti = alloc_thread_info(tsk);
    if (!ti) {
        free_task_struct(tsk);
        return NULL;
    }

③将父进程的进程描述符和thread_info赋值给新创建的进程描述符与thread_info

*ti = *orig->thread_info;
    *tsk = *orig;
    tsk->thread_info = ti;
    ti->task = tsk;

你可能感兴趣的:(Linux_进程创建)