进程的创建,执行和消亡。 (clone kernel_thread)

本文深入解析Linux系统中进程创建机制,包括fork(), clone(), vfork()等系统调用的内部实现原理,以及特殊函数kernel_thread()的工作流程。文章还探讨了不同系统调用之间的区别及其应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


Linux把进程的创建与目标程序的执行分为两步,一步为从已经存在的父进程中复制出子进 
 
程,主要是通过fork(),clone(),vfork()。第二步是目标程序的执行,linux系统提供exe 
 
cve()让进程执行以文件形式存在的一个可执行程序的映象。 
有个函数例外,kernel_thread(),它看起来不是创建执行两步走,而是通俗意义上所说的 
 
“一揽子”创建执行一起来的,它实际上是对clone()的封装,它并不象调用execve()时那 
 
样执行一个可执行映象文件,而只是执行内核中某个函数。 
/* 
 * Create a kernel thread 
 */ 
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) 

    long retval, d0; 
 
    __asm__ __volatile__( 
        /*  
          * 这里采取一种比较特别的比较区别父子进程的方法 
          * 它将返回时的堆栈指针和保存在寄存器esi的父进程 
          * 堆栈指针进行比较,由于每个内核线程都有自己的系统 
          * 空间堆栈,子进程的堆栈指针必然和父进程不同,这也 
          * 导致了该方法只适合对内核线程适用,因为普通的进程 
          * 都在用户空间,根本不知道其系统空间堆栈在哪里 
          */ 
 
        /*将父进程的堆栈指针存放在esi寄存器中*/ 
        "movl %%esp,%%esi/n/t" 
        /*系统调用,通过eax传递系统调用号*/ 
        "int $0x80/n/t"        /* Linux/i386 system call */ 
        "cmpl %%esp,%%esi/n/t"    /* child or parent? */ 
        "je 1f/n/t"        /* parent - jump */ 
        /* Load the argument into eax, and push it.  That way, it does 
         * not matter whether the called function is compiled with 
         * -mregparm or not.  */ 
        "movl %4,%%eax/n/t" 
        "pushl %%eax/n/t"         
        "call *%5/n/t"        /* call fn */ 
        /*再次装入系统调用号__NR_exit*/ 
        "movl %3,%0/n/t"    /* exit */ 
        /*系统调用*/ 
        "int $0x80/n" 
        "1:/t" 
        :"=&a" (retval), "=&S" (d0) 
        /* 
          * 在输入段将eax寄存器存放了__NR_clone,也就是第一个系统调用 
          * 为何会系统调用clone()函数的缘故. 
          * fn为被子进程调用执行的内核中的某个函数指针     
          */ 
        :"0" (__NR_clone), "i" (__NR_exit), 
         "r" (arg), "r" (fn), 
         "b" (flags | CLONE_VM) 
        : "memory"); 
    return retval; 

 
系统调用fork(),__clone(),vfork() 
__clone()是有选择的复制父进程的资源,fork()是完全全面的复制,vfork()除了task_s 
 
truct()和系统空间堆栈外的资源全部是通过数据结构指针的复制遗传的,三个系统调用都 
 
是通过do_fork()实现的。 
 
int do_fork(unsigned long clone_flags, unsigned long stack_start, 
        struct pt_regs *regs, unsigned long stack_size) 

    int retval; 
    unsigned long flags; 
    struct task_struct *p; 
    struct completion vfork; 
 
    /*为什么如果flag位clone_fs或clone_newns置为1则返回参数错误???*/ 
    if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS)) 
        return -EINVAL; 
 
    retval = -EPERM; 
 
    /*  
     * CLONE_PID is only allowed for the initial SMP swapper 
     * calls 
     */ 
     /* __clone()调用时,如果标志位CLONE_PID为1时表明父子进程使用 
       * 同一个进程号,但只有0号进程才可以这样调用__clone() 
       */ 
    if (clone_flags & CLONE_PID) { 
        if (current->pid) 
            goto fork_out; 
    } 
 
    retval = -ENOMEM; 
    /* 
      * 分配两个连续的物理页面,存放task_struct()和系统空间内存 
      * 有关这个昨天的日志曾详细讲过的,^_^ 
      */ 
    p = alloc_task_struct(); 
    if (!p) 
        goto fork_out; 
 
    /*整个数据结构赋值,父进程的整个task_struct被复制*/ 
    *p = *current; 
    p->tux_info = NULL; 
 
    retval = -EAGAIN; 
    /* 
     * Check if we are over our maximum process limit, but be sure to 
     * exclude root. This is needed to make it possible for login and 
     * friends to set the per-user process limit to something lower 
     * than the amount of processes root is running. -- Rik 
     */ 
     /* 该用户进程数目是否大于用户进程的RLIMINT_NPROC所允许的最大数目*/ 
    if (atomic_read(&p->user->processes) >= p->rlim[RLIMIT_NPROC].rlim_cur 
                  && !capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE)) 
        goto bad_fork_free; 
 
    /* __cout++;process++  --princeC*/ 
    atomic_inc(&p->user->__count); 
    atomic_inc(&p->user->processes); 
 
    /* 
     * Counter increases are protected by 
     * the kernel lock so nr_threads can't 
     * increase under us (but it may decrease). 
     */ 
     /*checked for kernel thread  --princeC*/ 
    if (nr_threads >= max_threads) 
        goto bad_fork_cleanup_count; 
 
    /*该进程所涉及到的模块计数器加1*/ 
    get_exec_domain(p->exec_domain); 
 
    /* 同理,每个进程所执行的程序属于某种可执行映象格式 
      * 如a.out格式,elf格式,java虚拟机格式,对于这些不同格式的支持 
      * 往往是通过动态安装的驱动模块来实现的,这里将有关该 
      * 模块的计数器加一 
      */ 
    if (p->binfmt && p->binfmt->module) 
        __MOD_INC_USE_COUNT(p->binfmt->mod 
 
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值