fork系统调用分析(3)–copy_process()

2010年12月12日 由 edsionte 留言 »

copy_process()分析

通过上面的分析我们得知do_fork()主要完成以下的工作:为子进程定义了一个进程描述符并申请pid;调用copy_process()复制子进程;再通过clone_flags标志做一些复制后的辅助工作。copy_process()函数主要用来创建子进程的描述符以及与子进程相关数据结构。这个函数内部实现较为复杂,在短时间内,对于内部详细代码原理和实现并不能全部理解。因此,接下来的分析侧重于copy_process()的执行流程。

1. 定义返回值变量和新的进程描述符。

        int retval;
        struct task_struct *p = NULL;

2. 对clone_flags所传递的标志组合进行合法性检查。当出现以下三种情况时,返回出错代号:

(1). CLONE_NEWNS和CLONE_FS同时被设置。

前者标志表示子进程需要自己的命名空间,而后者标志则代表子进程共享父进程的根目录和当前工作目录,两者不可兼容。
传统的Unix系统中,整个系统只有一个已经安装的文件系统树。每个进程从系统的根文件系统开始,通过合法的路径可以访问任何文件。在2.6版本中的内核中,每个进程都可以拥有属于自己的已安装文件系统树,也被称为命名空间。通常大多数进程都共享init进程所使用的已安装文件系统树,只有在clone_flags中设置了CLONE_NEWNS标志时,才会为此新进程开辟一个新的命名空间。

(2). CLONE_THREAD被设置,但CLONE_SIGHAND未被设置。

如果子进程和父进程属于同一个线程组(CLONE_THREAD被设置),那么子进程必须共享父进程的信号(CLONE_SIGHAND被设置)。

(3). CLONE_SIGHAND被设置,但CLONE_VM未被设置。

如果子进程共享父进程的信号,那么必须同时共享父进程的内存描述符和所有的页表(CLONE_VM被设置)。

3. 通过调用security_task_create()和后面的security_task_alloc()执行所有附加的安全性检查。

4. 通过dup_task_struct()为子进程分配一个内核栈、thread_info结构和task_struct结构。

p = dup_task_struct(current);

注意,这里将当前进程描述符指针作为参数传递到此函数中。该函数内部的具体过程如下:

首先,该函数分别定义了指向task_struct和thread_inof结构体的指针。

static struct task_struct *dup_task_struct(struct task_struct *orig)
{
	struct task_struct *tsk;
	struct thread_info *ti;

接着,为正式的分配进程描述符做一些准备工作。主要是将一些必要的寄存器的值保存到父进程的thread_info结构中。这些值会在稍后被复制到子进程的thread_info结构中。

	prepare_to_copy(orig);

执行alloc_task_struct宏,该宏负责为子进程的进程描述符分配空间,将该片内存的首地址赋值给tsk;随后检查这片内存是否分配正确。

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

执行alloc_thread_info宏,为子进程获取一块空闲的内存区,用来存放子进程的内核栈和thread_info结构,并将此会内存区的首地址赋值给ti变量;随后检查是否分配正确。

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

上面已经说明过orig是指向当前进程描述符的指针。因此,先将当前进程的thread_info结构中的内容复制到ti变量;再将当前进程task_struct结构中的内容复制到tsk变量;让子进程描述符中的thread_info字段指向ti变量;最后让子进程thread_info结构中的task字段指向tsk变量。

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

将子进程描述符的使用计数器设置为2,表示该进程描述符正在被使用并且处于活动状态。

	atomic_set(&tsk->usage,2);

最后返回指向刚刚创建的子进程描述符内存区的指针。

        return tsk;
}

通过上述代码可以看到,当这个函数成功操作之后,子进程和父进程的描述符中的内容是完全相同的。在稍后的代码中,我们将会看到子进程逐步与父进程区分开来。

5. 更新当前用户的user_struct结构。当前进程的用户如果没有root权限,并且所拥有的进程数大于所规定的进程数时,就返回错误代码。

接着对该user_struct结构的引用计数加1;对该用户所拥有的进程总数量加1。

        atomic_inc(&p->user->__count);
           atomic_inc(&p->user->processes);

6. 检测系统中进程的总数量是否超过了max_threads所规定的进程最大数。

         if (nr_threads >= max_threads)
                 goto bad_fork_cleanup_count;

7. 将从do_fork()传递来的的clone_flags和pid分别赋值给子进程描述符中的对应字段。

         copy_flags(clone_flags, p);
             p->pid = pid;

8. 逐步初始化子进程描述符中字段,使得子进程和父进程逐渐区别出来。这部分工作包含初始化双联表、互斥锁和描述进程属性的字段等。它在copy_process函数中占据了相当长的一段的代码,不过考虑到task_struct结构本身的复杂性,也就不足为奇了。

9. 根据clone_flags的具体取值,通过诸如copy_semundo()和copy_files()等这样的函数来为子进程拷贝或共享父进程的某些数据结构。

10. 通过copy_threads()函数更新子进程的内核栈和寄存器中的值。在之前的dup_task_struct()中只是为子进程创建一个内核栈,至此才是真正的赋予它有意义的值。

当父进程发出clone系统调用时,内核会将那个时候CPU中寄存器的值保存在父进程的内核栈中。这里就是使用父进程内核栈中的值来更新子进程寄存器中的值。特别的,内核将子进程eax寄存器中的值强制赋值为0,这也就是为什么使用fork()时子进程返回值是0。而在do_fork函数中则返回的是子进程的pid,这一点在上述内容中我们已经有所分析。另外,子进程的对应的thread_info结构中的esp字段会被初始化为子进程内核栈的基址。

11. 调用sched_fork函数,使得子进程的进程状态为TASK_RUNNING。并禁止内核抢占。并且,为了不对其他进程的调度产生影响,此时子进程共享父进程的时间片。

12. 根据clone_flags的值继续更新子进程的某些属性。

13. 将 nr_threads加一,表明新进程已经被加入到进程集合中。将total_forks加一,以记录被创建进程数量。

        nr_threads++;
           total_forks++;

14. 如果上述过程中某一步出现了错误,则通过goto语句跳到相应的错误代码处;如果成功执行完毕,则返回子进程的描述符p。

至此,copy_proces()的大致执行过程分析完毕。

do_fork()执行完毕后,虽然子进程处于可运行状态,但是它并没有立刻运行。至于子进程合适执行这完全取决于调度程序,也就是schedule(),本文并不涉及涉及此函数的分析。

广告位

2 条评论

  1. zhaogejuan说道:

    学长分析的很细致阿,我先前大致的分析了一下,看了你的分析对一些细节问题有很大的收益。期待续集……

    [回复一下]

    edsionte 回复:

    @zhaogejuan, 我也是初次分析,有什么不妥的地方互相讨论哦。谢谢啦。

    [回复一下]

发表回复

windows 7 ultimate product key

windows 7 ultimate product key

winrar download free

winrar download free

winzip registration code

winzip registration code

winzip free download

winzip free download

winzip activation code

winzip activation code

windows 7 key generator

windows 7 key generator

winzip freeware

winzip freeware

winzip free download full version

winzip free download full version

free winrar download

free winrar download

free winrar

free winrar

windows 7 crack

windows 7 crack

windows xp product key

windows xp product key

windows 7 activation crack

windows7 activation crack

free winzip

free winzip

winrar free download

winrar free download

winrar free

winrar free

download winrar free

download winrar free

windows 7 product key

windows 7 product key