程序编程代码大全 c代码检查工具( 二 )


创建进程时,内存地址空间里常常包含数十 MB 的数据,如果每创建一次进程,就拷贝一次数据,开销显然是非常大的 。
fork() 函数 Linux 中的 fork() 函数其实是基于 clone() 实现的,clone() 函数可以通过一系列参数标志指定父子进程需要共享的资源,在 Linux 中输入 man 命令可以查看 clone() 函数的C语言原型:
clone() 函数的C语言原型
以及相关的参数标志:
相关的参数标志
在Linux中,fork() 函数最终调用了 do_fork() 函数,它的C语言代码如下,请看(do_fork() 函数的C语言代码比较长,下面面只列出了一部分):
do_fork() 函数的C语言代码
do_fork() 函数完成了进程创建的大部分工作,从相关的C语言源代码可以看出,它调用了 copy_process() 函数,copy_process() 函数的C语言源代码如下,请看:
copy_process() 函数的C语言源代码
copy_process() 函数的代码也是比较长的,在我手上的Linux系统中,达到了近 400 行,不过代码的整体逻辑是清晰的:
(1)copy_process() 函数首先检查了一些标志位,接着调用 dup_task_struct() 函数为新进程创建内核栈,以及上一节提到的 thread_info 和 task_struct 结构:
调用 dup_task_struct() 函数为新进程创建内核栈
创建后,接下来的 arch_dup_task_struct() 函数会将 orig 结构拷贝给新创建的结构,查看相关C语言代码,这一过程是清晰的:
拷贝给新创建的结构
此时子进程和父进程的描述符是完全相同的 。
(2)接下来,需要检查一些标志位和统计信息,相关的C语言代码如下,请看:
检查一些标志位和统计信息
【程序编程代码大全 c代码检查工具】(3)将一些统计量清零,以及初始化一些区别成员,此时虽然新进程的 task_struct 结构体大多成员未被修改,但是父子进程已经有所区别 。这一过程的相关C语言代码片段如下,请看:
将一些统计量清零,以及初始化一些区别成员
(4)将新创建的子进程状态设置为 TASK_UNINTERRUUPTIBLE,确保其暂时不会被投入运行,这一过程的C语言代码相对简单 。
(5)调用 alloc_pid() 函数为新进程分配一个独一无二的 pid,相关C语言代码如下,请看:
为新进程分配一个独一无二的 pid
(6)根据 clone() 函数的参数标志位,拷贝或共享已经打开的文件、文件系统、信号处理函数、进程地址空间等资源,例如下面这段C语言代码:
拷贝或共享已经打开的资源
(7)将为新进程创建的 task_struct 结构体的指针返回给调用者,也即 do_fork() 函数 。此时新创建的进程还没有被投入运行 。
现在回到 do_fork() 函数 。如果调用 clone() 函数时,没有传递 CLONE_STOPPED 参数,新创建的进程将被唤醒,并投入运行,这一过程的C语言代码如下:

猜你喜欢