首先声明分析的源码版本是Linux2.6.11.12的fork()函数和vfork()调用do_fork()函数,我们使用的fork工作是通过do_fork()执行。do_fork()函数:进入后,先去寻找新的pidalloc_pidmap();copy_process通过搜索pidmap_array位图复制子进程所需的进程描述符。如果所有必要的资源都可用,则此函数返回新创建的task_struct描述符的地址。通过调用copy_process()函数复制父进程的资源。这里使用了写时复制技术。如果一个页面中的数据没有被改变,则父子进程共享一个资源页面。一旦有一点变化,哪怕是一个字Section的变化,都会把这个页面从头到尾复制到子进程中。这一步也是创建流程的关键。复制过程();然后调用dup_task_struct获取子进程的进程描述符dup_task_struct();然后进行一系列的安全检查,检查系统中的进程数(nr_threads)是否超过max_threads,max_threads的默认值由系统内存容量决定。总的原则是:所有thread_info描述符和内核栈占用的空间不能超过物理内存的1/8。但是,系统管理员可以通过写入/proc/sys/kernel/thread-max文件来更改此值。对子进程的描述符进行一系列的初始化,如果是vfork则分配pid,然后保护父进程然后挂起父进程让子进程继续执行;如果不是,则调整父子进程的调度参数,如果父子进程运行在同一个CPU上,不能共享同一套页表(CLONE_VM标志位清0)。然后,将子进程插入到父进程运行队列中。并且子进程插入在父进程之前。这样做的目的是:如果子进程在创建后执行新的程序,可以通过写时复制机制避免不必要的页面复制。否则,如果运行在不同的CPU上,或者父子进程共享同一套页表,则将子进程插入到父进程运行队列的尾部。fork出来的子进程,基本上除了进程号,父进程的所有东西都有一份,基本意思不是全部。接下来我们要说的是子进程从父进程继承什么,不继承什么。还有一点需要注意的是,子进程得到的只是父进程的一份拷贝,并不是父进程资源本身。子进程从父进程继承:进程资格(真实(real)/有效(effective)/保存(saved)用户ID(UIDs)和组ID(GIDs))环境(environment)栈内存打开文件描述符(注相应文件的位置在父进程和子进程之间共享,这会导致歧义)执行时的close-on-exec标志,POSIX.1要求在调用exec函数时必须关闭所有目??录流。详见《UNIX环境高级编程》W.R.Stevens,1993,游金元等译。(以下简称《高级编程》)3.13节和8.9节)信号(signal)控制设置nice值(译者注:nice值由nice函数设置决定,这个值表示进程的优先级,值越小,优先级越高)Scheduler类有不同的优先级。根据进程调度类别和nice值,进程调度器可以计算出每个进程的全局优先级(Globalprocessprority),优先级高的进程优先执行)进程组号会话ID(SessionID)(译者注:译文取自《高级编程》,指的是:进程所属会话的ID。一个会话包含一个或多个进程组。详见《高级编程》的9.5节)进程的根目录当前工作目录(译者注:根目录不一定是“/”,可以通过chroot函数改变)文件模式创建掩码(umask)文件的默认掩码字)资源限制控制终端子进程唯一:parentprocessIDwithadifferentprocessIDfunctiongets)自己的文件描述符和一份目录流(译者注:目录流是由opendir函数创建的,因为是顺序读取的,顾名思义就是“目录流”)子进程不继承父进程的进程,文本(text)、数据等锁定内存(memorylocks)2.2版本,1999,3.4.2节)tms结构时间中的系统时间,包括:用户时间,系统时间,用户每个子进程的总时间,系统每个子进程的总时间)资源利用率(resourceutilizations)设置为0,阻塞信号集初始化为空集(译者注:此处原文看不清楚,翻译根据fork函数的manpage稍作修改)不继承timer_create函数创建的定时器不继承异步输入输出参考:http://blog.csdn.net/日eone10...
