在通过fork系统调用创建进程时,最终会进入内核的do_fork函数,这个函数的大部分工作都是进程的复制,就是把大部分工作都委托给函数copy_process函数来完成。本博文主要讨论进程的复制工作。 下面分成几个段,所在代码包含了整个copy_process函数 一,标志检查 [cpp] static struct task_struct *copy_process(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size, int __user *child_tidptr, struct pid *pid) { int retval; struct task_struct *p; int cgroup_callbacks_done = 0; if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS)) return ERR_PTR(-EINVAL); /* * Thread groups must share signals as well, and detached threads * can only be started up within the thread group. */ if ((clone_flags & CLONE_THREAD) && !(clone_flags & CLONE_SIGHAND)) return ERR_PTR(-EINVAL); /* * Shared signal handlers imply shared VM. By way of the above, * thread groups also imply shared VM. Blocking this case allows * for various simplifications in other code. */ if ((clone_flags & CLONE_SIGHAND) && !(clone_flags & CLONE_VM)) return ERR_PTR(-EINVAL); retval = security_task_create(clone_flags); if (retval) goto fork_out; 这是函数的开始部分,先进行传入的参数检查,主要是: 如果创建进程的时候,要求创建一个新的命名空间(CLONE_NEWNS),并且同时要求与父进程共享所有的文件系统信息(CLONE_FS),这是不允许的。此时是要求共享其文件系统。 在用CLONE_THREAD标志时,必须使用CLONE_SIGHAND标志,后者表示共享相同的信号处理表。 在使用CLONE_SIGHAND标志时,必须使用CLONE_VM标志,后者表示子进程和你进程共享虚拟地址空间,也只有这个时候,才能提供共享的信号处理程序。 二,建立副本 [cpp] retval = -ENOMEM; p = dup_task_struct(current); <span> </span>if (!p) <span> </span>goto fork_out; dup_task_struct用来建立父进程的副本,函数如下: [cpp] static struct task_struct *dup_task_struct(struct task_struct *orig) { struct task_struct *tsk; struct thread_info *ti; int err; prepare_to_copy(orig); tsk = alloc_task_struct(); if (!tsk) return NULL; ti = alloc_thread_info(tsk); if (!ti) { free_task_struct(tsk); return NULL; } *tsk = *orig;//将父进程的内容填充新的进程 tsk->stack = ti; err = prop_local_init_single(&tsk->dirties); if (err) { free_thread_info(ti); free_task_struct(tsk); return NULL; } setup_thread_stack(tsk, orig); #ifdef CONFIG_CC_STACKPROTECTOR tsk->stack_canary = get_random_int(); #endif /* One for us, one for whoever does the “release_task()” (usually parent) */ atomic_set(&tsk->usage,2);//使用计数器置为2,表示当前进程描述符处于活动状态。 atomic_set(&tsk->fs_excl, 0); #ifdef CONFIG_BLK_DEV_IO_TRACE tsk->btrace_seq = 0; #endif tsk->splice_pipe = NULL; return tsk; } 调用alloc_task_struct为新进程分配进程结构,返回tsk指针。 为新的进程分配一个核心态栈,也就是tsk->stack.栈和thread_info一同保存在一个联合结构中。thread_info用于保存进程所需的特定于处理器的底层信息,定义如下: [cpp] struct thread_info { struct task_struct *task; /* 不前的主进程 */ unsigned long flags; struct exec_domain *exec_domain; /* 执行区间 */ int preempt_count; /* 内核抢占所需的一个计数器*/ __u32 cpu; /* 进程正在其上执行的CPU数目 */ struct restart_block restart_block;//用于实现信号机制 }; 而进程的栈和thread_info的联合体定义如下: [cpp] union thread_union { struct thread_info thread_info; unsigned long stack[THREAD_SIZE/sizeof(long)]; };[1] [2] [3] [4] [5] 下一页 |