Linux2.6内核进程创建过程分析

 

使用版本: linux-2.6.22.9

Fork的系统调用代码在linux/arch/i386/kernel/process.c中:

asmlinkage int sys_fork(struct pt_regs regs)

{

return do_fork(SIGCHLD, regs.esp, ®s, 0, NULL, NULL);

}

Sys_fork系统调用通过 do_fork()函数实现,通过对do_fork()函数传递不同的clone_flags来实现fork,clone,vfork。

Syn_clone和syn_vfork的系统调用代码如下:

asmlinkage int sys_clone(struct pt_regs regs)

{

unsigned long clone_flags;

unsigned long newsp;

int __user *parent_tidptr, *child_tidptr;

clone_flags = regs.ebx;

newsp = regs.ecx;

parent_tidptr = (int __user *)regs.edx;

child_tidptr = (int __user *)regs.edi;

if (!newsp)

newsp = regs.esp;

return do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr);

}

asmlinkage int sys_vfork(struct pt_regs regs)

{

return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, ®s, 0, NULL, NULL);

}

其中clone_flas在include/linux/sched.h中定义

/*

* cloning flags:

*/

#define CSIGNAL 0x000000ff /* 进程退出时需要传递的信号*/

#define CLONE_VM 0x00000100 /* 父子进程共享地址空间 */

#define CLONE_FS 0x00000200 /* 父子进程共享文件系统信息 */

#define CLONE_FILES 0x00000400 /* 父子进程共享已打开的文件 */

#define CLONE_SIGHAND 0x00000800 /* 父子进程共享信号处理 */

#define CLONE_PTRACE 0x00002000 /* 继续调试子进程 */

#define CLONE_VFORK 0x00004000 /* 调用vfork(),父进程休眠*/

#define CLONE_PARENT 0x00008000 /* 设置一个共有的父进程 */

#define CLONE_THREAD 0x00010000 /* 父子进程在同一个线程组 */

#define CLONE_NEWNS 0x00020000 /* 为子进程创建一个新的命名空间 */

#define CLONE_SYSVSEM 0x00040000 /* 父子进程共享system V SEM_UNDO */

#define CLONE_SETTLS 0x00080000 /* 为子进程创建新的TLS */

#define CLONE_PARENT_SETTID 0x00100000 /* 设置父进程TID */

#define CLONE_CHILD_CLEARTID 0x00200000 /* 清除子进程TID */

#define CLONE_DETACHED 0x00400000 /* Unused, ignored */

#define CLONE_UNTRACED 0x00800000 /* 不允许调试子进程 */

#define CLONE_CHILD_SETTID 0x01000000 /* 设置子进程TID */

#define CLONE_STOPPED 0x02000000 /* 设置进程停止状态 */

#define CLONE_NEWUTS 0x04000000 /* 创建新的utsname组 */

#define CLONE_NEWIPC 0x08000000 /* 创建新的IPC */

Do_fork()在kernel/fork.c中定义,代码如下:

/*

* Ok, this is the main fork-routine.

*

* It copies the process, and if successful kick-starts

* it and waits for it to finish using the VM if required.

*/

long do_fork(unsigned long clone_flags,

unsigned long stack_start,

struct pt_regs *regs,

unsigned long stack_size,

int __user *parent_tidptr,

int __user *child_tidptr)

{

struct task_struct *p;

int trace = 0;

struct pid *pid = alloc_pid();

long nr;

if (!pid)

return -EAGAIN;

nr = pid->nr;

if (unlikely(current->ptrace)) {

trace = fork_traceflag (clone_flags);

if (trace)

clone_flags |= CLONE_PTRACE;

}

p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, pid);

/*

* 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;

if (clone_flags & CLONE_VFORK) {

p->vfork_done = &vfork;

init_completion(&vfork);

}

if ((p->ptrace & PT_PTRACED) || (clone_flags & CLONE_STOPPED)) {

/*

* We'll start up with an immediate SIGSTOP.

*/

sigaddset(&p->pending.signal, SIGSTOP);

set_tsk_thread_flag(p, TIF_SIGPENDING);

}

if (!(clone_flags & CLONE_STOPPED))

wake_up_new_task(p, clone_flags);

else

p->state = TASK_STOPPED;

if (unlikely (trace)) {

current->ptrace_message = nr;

ptrace_notify ((trace << 8) | SIGTRAP);

}

if (clone_flags & CLONE_VFORK) {

freezer_do_not_count();

wait_for_completion(&vfork);

freezer_count();

if (unlikely (current->ptrace & PT_TRACE_VFORK_DONE)) {

current->ptrace_message = nr;

ptrace_notify ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP);

}

}

} else {

free_pid(pid);

nr = PTR_ERR(p);

}

return nr;

}

Do_fork()函数的核心是copy_process()函数,该函数完成了进程创建的绝大部分工作并且也在fork.c定义,copy_process函数较长,逐段往下看:

static struct task_struct *copy_process(unsigned long clone_flags,

unsigned long stack_start,

struct pt_regs *regs,

unsigned long stack_size,

int __user *parent_tidptr,

int __user *child_tidptr,

struct pid *pid)

{

int retval;

struct task_struct *p = NULL;

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;

retval = -ENOMEM;

p = dup_task_struct(current);

if (!p)

goto fork_out;

rt_mutex_init_task(p);

#ifdef CONFIG_TRACE_IRQFLAGS

DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled);

DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);

#endif

这段代码首先对传入的clone_flag进行检查,接着调用了dup_task_struct()函数,该函数的主要作用是:为子进程创建一个新的内核栈,复制task_struct结构和thread_info结构,这里只是对结构完整的复制,所以子进程的进程描述符跟父进程完全一样。跟进dup_task_struct()函数看代码:

static struct task_struct *dup_task_struct(struct task_struct *orig)

{

struct task_struct *tsk;

struct thread_info *ti;

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;

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);

atomic_set(&tsk->fs_excl, 0);

#ifdef CONFIG_BLK_DEV_IO_TRACE

tsk->btrace_seq = 0;

#endif

tsk->splice_pipe = NULL;

return tsk;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值