分享

linux 系统调用fork vfork clone

 astrotycoon 2013-09-02

fork:通过fork创建新进程
vfork:主要用于马上执行exec的情况,因为马上就exec装入新的程序,所以可以去掉fork中分配新的地址空间等操作,进而加速进程创建
clone:功能更强,参数更多;主要用于创建线程/父子进程资源共享等,可以通过设置相应的参数实现fork、vfork的功能

 

I.系统调用
i.系统调用

  1. arch/x86/kernel/syscall_table_32.S  
  2.   1 ENTRY(sys_call_table)  
  3.   4         .long ptregs_fork       /* 3 */  
  4. 122         .long ptregs_clone      /* 120 */  
  5. 192         .long ptregs_vfork      /* 190 */  
  6.   
  7. arch/x86/kernel/entry_32.S  
  8.  709 /* 
  9.  710  * System calls that need a pt_regs pointer. 
  10.  711  */  
  11.  712 #define PTREGSCALL(name) \  
  12.  713         ALIGN; \  
  13.  714 ptregs_##name: \  
  14.  715         leal 4(%esp),%eax; \  
  15.  716         jmp sys_##name;  
  16.  717   
  17.  718 PTREGSCALL(iopl)  
  18.  719 PTREGSCALL(fork)  
  19.  720 PTREGSCALL(clone)  
  20.  721 PTREGSCALL(vfork)  
  21.   
  22. arch/x86/kernel/process.c  
  23. 217 int sys_fork(struct pt_regs *regs)  
  24. 218 {  
  25. 219         return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL);  
  26. 220 }  
  27. 221   
  28. 222 /* 
  29. 223  * This is trivial, and on the face of it looks like it 
  30. 224  * could equally well be done in user mode. 
  31. 225  * 
  32. 226  * Not so, for quite unobvious reasons - register pressure. 
  33. 227  * In user mode vfork() cannot have a stack frame, and if 
  34. 228  * done by calling the "clone()" system call directly, you 
  35. 229  * do not have enough call-clobbered registers to hold all 
  36. 230  * the information you need. 
  37. 231  */  
  38. 232 int sys_vfork(struct pt_regs *regs)  
  39. 233 {  
  40. 234         return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs, 0,  
  41. 235                        NULL, NULL);  
  42. 236 }  
  43.   
  44. arch/x86/kernel/process_32.c  
  45. 432 int sys_clone(struct pt_regs *regs)  
  46. 433 {  
  47. 434         unsigned long clone_flags;  
  48. 435         unsigned long newsp;  
  49. 436         int __user *parent_tidptr, *child_tidptr;  
  50. 437   
  51. 438         clone_flags = regs->bx;  
  52. 439         newsp = regs->cx;  
  53. 440         parent_tidptr = (int __user *)regs->dx;  
  54. 441         child_tidptr = (int __user *)regs->di;  
  55. 442         if (!newsp)  
  56. 443                 newsp = regs->sp;  
  57. 444         return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr);  
  58. 445 }  

可以看出fork,vfork,clone都是通过do_fork实现,只是传入参数不同而已

 

ii.do_fork

  1. kernel/fork.c  
  2. 1363  *  Ok, this is the main fork-routine.  
  3. 1364  *  
  4. 1365  * It copies the process, and if successful kick-starts  
  5. 1366  * it and waits for it to finish using the VM if required.  
  6. 1367  */  
  7. 1368 long do_fork(unsigned long clone_flags,  
  8. 1369               unsigned long stack_start,  
  9. 1370               struct pt_regs *regs,  
  10. 1371               unsigned long stack_size,  
  11. 1372               int __user *parent_tidptr,  
  12. 1373               int __user *child_tidptr)  
  13. 1374 {  
  14. 1375         struct task_struct *p;  
  15. 1376         int trace = 0;  
  16. 1377         long nr;  
  17. 1378   
  18. 1379         /* 
  19. 1380          * Do some preliminary argument and permissions checking before we 
  20. 1381          * actually start allocating stuff 
  21. 1382          */  
  22. 1383         if (clone_flags & CLONE_NEWUSER) {  
  23. 1384                 if (clone_flags & CLONE_THREAD)  
  24. 1385                         return -EINVAL;  
  25. 1386                 /* hopefully this check will go away when userns support is 
  26. 1387                  * complete 
  27. 1388                  */  
  28. 1389                 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SETUID) ||  
  29. 1390                                 !capable(CAP_SETGID))  
  30. 1391                         return -EPERM;  
  31. 1392         }  
  32. 1393   
  33. 1394         /* 
  34. 1395          * We hope to recycle these flags after 2.6.26 
  35. 1396          */  
  36. 1397         if (unlikely(clone_flags & CLONE_STOPPED)) {  
  37. 1398                 static int __read_mostly count = 100;  
  38. 1399   
  39. 1400                 if (count > 0 && printk_ratelimit()) {  
  40. 1401                         char comm[TASK_COMM_LEN];  
  41. 1402   
  42. 1403                         count--;  
  43. 1404                         printk(KERN_INFO "fork(): process `%s' used deprecated "  
  44. 1405                                         "clone flags 0x%lx\n",  
  45. 1406                                 get_task_comm(comm, current),  
  46. 1407                                 clone_flags & CLONE_STOPPED);  
  47. 1408                 }  
  48. 1409         }  
  49. 1410   
  50. 1411         /* 
  51. 1412          * When called from kernel_thread, don't do user tracing stuff. 
  52. 1413          */  
  53. 1414         if (likely(user_mode(regs)))  
  54. 1415                 trace = tracehook_prepare_clone(clone_flags);  
  55. 1416   
  56. 1417         p = copy_process(clone_flags, stack_start, regs, stack_size,  
  57. 1418                          child_tidptr, NULL, trace);  
  58. 1419         /* 
  59. 1420          * Do this prior waking up the new thread - the thread pointer 
  60. 1421          * might get invalid after that point, if the thread exits quickly. 
  61. 1422          */  
  62. 1423         if (!IS_ERR(p)) {  
  63. 1424                 struct completion vfork;  
  64. 1425   
  65. 1426                 trace_sched_process_fork(current, p);  
  66. 1427   
  67. 1428                 nr = task_pid_vnr(p);  
  68. 1429   
  69. 1430                 if (clone_flags & CLONE_PARENT_SETTID)  
  70. 1431                         put_user(nr, parent_tidptr);  
  71. 1432   
  72. 1433                 if (clone_flags & CLONE_VFORK) {  
  73. 1434                         p->vfork_done = &vfork;  
  74. 1435                         init_completion(&vfork);  
  75. 1436                 }  
  76. 1437   
  77. 1438                 audit_finish_fork(p);  
  78. 1439                 tracehook_report_clone(regs, clone_flags, nr, p);  
  79. 1440   
  80. 1441                 /* 
  81. 1442                  * We set PF_STARTING at creation in case tracing wants to 
  82. 1443                  * use this to distinguish a fully live task from one that 
  83. 1444                  * hasn't gotten to tracehook_report_clone() yet.  Now we 
  84. 1445                  * clear it and set the child going. 
  85. 1446                  */  
  86. 1447                 p->flags &= ~PF_STARTING;  
  87. 1449                 if (unlikely(clone_flags & CLONE_STOPPED)) {  
  88. 1450                         /* 
  89. 1451                          * We'll start up with an immediate SIGSTOP. 
  90. 1452                          */  
  91. 1453                         sigaddset(&p->pending.signal, SIGSTOP);  
  92. 1454                         set_tsk_thread_flag(p, TIF_SIGPENDING);  
  93. 1455                         __set_task_state(p, TASK_STOPPED);  
  94. 1456                 } else {  
  95. 1457                         wake_up_new_task(p, clone_flags);  
  96. 1458                 }  
  97. 1459   
  98. 1460                 tracehook_report_clone_complete(trace, regs,  
  99. 1461                                                 clone_flags, nr, p);  
  100. 1462   
  101. 1463                 if (clone_flags & CLONE_VFORK) {  
  102. 1464                         freezer_do_not_count();  
  103. 1465                         wait_for_completion(&vfork);  
  104. 1466                         freezer_count();  
  105. 1467                         tracehook_report_vfork_done(p, nr);  
  106. 1468                 }  
  107. 1469         } else {  
  108. 1470                 nr = PTR_ERR(p);  
  109. 1471         }  
  110. 1472         return nr;  
  111. 1473 }  

1.输入参数及权限检查
2.复制进程
3.取子进程id
4.如果设置CLONE_PARENT_SETTID,则将子进程id放入parent_tidptr中
5.如果是vfork系统调用/带CLONE_VFORK标识的clone,初始化completion;用于暂停父进程在vfork/clone中,在子进程执行exec/exit后父进程再继续执行
6.唤醒子进程,在copy_thread中设置子进程的运行环境;子进程从ret_from_fork执行,内核堆栈与父进程刚进入fork/vfork/clone的内核堆栈相同(返回值ax设置成0,sp设置成新的用户堆栈),直接退出系统调用即可。
7.如果是vfork系统调用/带CLONE_VFORK标识的clone,等待子进程执行exec/exit


II.复制进程copy_process

  1. kernel/fork.c  
  2.  973 /* 
  3.  974  * This creates a new process as a copy of the old one, 
  4.  975  * but does not actually start it yet. 
  5.  976  * 
  6.  977  * It copies the registers, and all the appropriate 
  7.  978  * parts of the process environment (as per the clone 
  8.  979  * flags). The actual kick-off is left to the caller. 
  9.  980  */  
  10.  981 static struct task_struct *copy_process(unsigned long clone_flags,  
  11.  982                                         unsigned long stack_start,  
  12.  983                                         struct pt_regs *regs,  
  13.  984                                         unsigned long stack_size,  
  14.  985                                         int __user *child_tidptr,  
  15.  986                                         struct pid *pid,  
  16.  987                                         int trace)  
  17.  988 {  
  18.  989         int retval;  
  19.  990         struct task_struct *p;  
  20.  991         int cgroup_callbacks_done = 0;  
  21.  992   
  22.  993         if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))  
  23.  994                 return ERR_PTR(-EINVAL);  
  24.  995   
  25.  996         /* 
  26.  997          * Thread groups must share signals as well, and detached threads 
  27.  998          * can only be started up within the thread group. 
  28.  999          */  
  29. 1000         if ((clone_flags & CLONE_THREAD) && !(clone_flags & CLONE_SIGHAND))  
  30. 1001                 return ERR_PTR(-EINVAL);  
  31. 1002   
  32. 1003         /* 
  33. 1004          * Shared signal handlers imply shared VM. By way of the above, 
  34. 1005          * thread groups also imply shared VM. Blocking this case allows 
  35. 1006          * for various simplifications in other code. 
  36. 1007          */  
  37. 1008         if ((clone_flags & CLONE_SIGHAND) && !(clone_flags & CLONE_VM))  
  38. 1009                 return ERR_PTR(-EINVAL);  
  39. 1010   
  40. 1011         /* 
  41. 1012          * Siblings of global init remain as zombies on exit since they are 
  42. 1013          * not reaped by their parent (swapper). To solve this and to avoid 
  43. 1014          * multi-rooted process trees, prevent global and container-inits 
  44. 1015          * from creating siblings. 
  45. 1016          */  
  46. 1017         if ((clone_flags & CLONE_PARENT) &&  
  47. 1018                                 current->signal->flags & SIGNAL_UNKILLABLE)  
  48. 1019                 return ERR_PTR(-EINVAL);  
  49. 1020   
  50. 1021         retval = security_task_create(clone_flags);  
  51. 1022         if (retval)  
  52. 1023                 goto fork_out;  
  53. 1024   
  54. 1025         retval = -ENOMEM;  
  55. 1026         p = dup_task_struct(current);  
  56. 1027         if (!p)  
  57. 1028                 goto fork_out;  
  58. 1029   
  59. 1030         ftrace_graph_init_task(p);  
  60. 1031   
  61. 1032         rt_mutex_init_task(p);  
  62. 1033   
  63. 1034 #ifdef CONFIG_PROVE_LOCKING  
  64. 1035         DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled);  
  65. 1036         DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);  
  66. 1037 #endif  
  67. 1038         retval = -EAGAIN;  
  68. 1039         if (atomic_read(&p->real_cred->user->processes) >=  
  69. 1040                         p->signal->rlim[RLIMIT_NPROC].rlim_cur) {  
  70. 1041                 if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) &&  
  71. 1042                     p->real_cred->user != INIT_USER)  
  72. 1043                         goto bad_fork_free;  
  73. 1044         }  
  74. 1045   
  75. 1046         retval = copy_creds(p, clone_flags);  
  76. 1047         if (retval < 0)  
  77. 1048                 goto bad_fork_free;  
  78. 1049   
  79. 1050         /* 
  80. 1051          * If multiple threads are within copy_process(), then this check 
  81. 1052          * triggers too late. This doesn't hurt, the check is only there 
  82. 1053          * to stop root fork bombs. 
  83. 1054          */  
  84. 1055         retval = -EAGAIN;  
  85. 1056         if (nr_threads >= max_threads)  
  86. 1057                 goto bad_fork_cleanup_count;  
  87. 1058   
  88. 1059         if (!try_module_get(task_thread_info(p)->exec_domain->module))  
  89. 1060                 goto bad_fork_cleanup_count;  
  90. 1061   
  91. 1062         p->did_exec = 0;  
  92. 1063         delayacct_tsk_init(p);  /* Must remain after dup_task_struct() */  
  93. 1064         copy_flags(clone_flags, p);  
  94. 1065         INIT_LIST_HEAD(&p->children);  
  95. 1066         INIT_LIST_HEAD(&p->sibling);  
  96. 1067         rcu_copy_process(p);  
  97. 1068         p->vfork_done = NULL;  
  98. 1069         spin_lock_init(&p->alloc_lock);  
  99. 1070   
  100. 1071         init_sigpending(&p->pending);  
  101. 1072   
  102. 1073         p->utime = cputime_zero;  
  103. 1074         p->stime = cputime_zero;  
  104. 1075         p->gtime = cputime_zero;  
  105. 1076         p->utimescaled = cputime_zero;  
  106. 1077         p->stimescaled = cputime_zero;  
  107. 1078         p->prev_utime = cputime_zero;  
  108. 1079         p->prev_stime = cputime_zero;  
  109. 1080   
  110. 1081         p->default_timer_slack_ns = current->timer_slack_ns;  
  111. 1082   
  112. 1083         task_io_accounting_init(&p->ioac);  
  113. 1084         acct_clear_integrals(p);  
  114. 1085   
  115. 1086         posix_cpu_timers_init(p);  
  116. 1087   
  117. 1088         p->lock_depth = -1;             /* -1 = no lock */  
  118. 1089         do_posix_clock_monotonic_gettime(&p->start_time);  
  119. 1090         p->real_start_time = p->start_time;  
  120. 1091         monotonic_to_bootbased(&p->real_start_time);  
  121. 1092         p->io_context = NULL;  
  122. 1093         p->audit_context = NULL;  
  123. 1094         cgroup_fork(p);  
  124. 1095 #ifdef CONFIG_NUMA  
  125. 1096         p->mempolicy = mpol_dup(p->mempolicy);  
  126. 1097         if (IS_ERR(p->mempolicy)) {  
  127. 1098                 retval = PTR_ERR(p->mempolicy);  
  128. 1099                 p->mempolicy = NULL;  
  129. 1100                 goto bad_fork_cleanup_cgroup;  
  130. 1101         }  
  131. 1102         mpol_fix_fork_child_flag(p);  
  132. 1103 #endif  
  133. 1104 #ifdef CONFIG_TRACE_IRQFLAGS  
  134. 1105         p->irq_events = 0;  
  135. 1106 #ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW  
  136. 1107         p->hardirqs_enabled = 1;  
  137. 1108 #else  
  138. 1109         p->hardirqs_enabled = 0;  
  139. 1110 #endif  
  140. 1111         p->hardirq_enable_ip = 0;  
  141. 1112         p->hardirq_enable_event = 0;  
  142. 1113         p->hardirq_disable_ip = _THIS_IP_;  
  143. 1114         p->hardirq_disable_event = 0;  
  144. 1115         p->softirqs_enabled = 1;  
  145. 1116         p->softirq_enable_ip = _THIS_IP_;  
  146. 1117         p->softirq_enable_event = 0;  
  147. 1118         p->softirq_disable_ip = 0;  
  148. 1119         p->softirq_disable_event = 0;  
  149. 1120         p->hardirq_context = 0;  
  150. 1121         p->softirq_context = 0;  
  151. 1122 #endif  
  152. 1123 #ifdef CONFIG_LOCKDEP  
  153. 1124         p->lockdep_depth = 0; /* no locks held yet */  
  154. 1125         p->curr_chain_key = 0;  
  155. 1126         p->lockdep_recursion = 0;  
  156. 1127 #endif  
  157. 1128   
  158. 1129 #ifdef CONFIG_DEBUG_MUTEXES  
  159. 1130         p->blocked_on = NULL; /* not blocked yet */  
  160. 1131 #endif  
  161. 1132   
  162. 1133         p->bts = NULL;  
  163. 1134   
  164. 1135         /* Perform scheduler related setup. Assign this task to a CPU. */  
  165. 1136         sched_fork(p, clone_flags);  
  166. 1137   
  167. 1138         retval = perf_event_init_task(p);  
  168. 1139         if (retval)  
  169. 1140                 goto bad_fork_cleanup_policy;  
  170. 1141   
  171. 1142         if ((retval = audit_alloc(p)))  
  172. 1143                 goto bad_fork_cleanup_policy;  
  173. 1144         /* copy all the process information */  
  174. 1145         if ((retval = copy_semundo(clone_flags, p)))  
  175. 1146                 goto bad_fork_cleanup_audit;  
  176. 1147         if ((retval = copy_files(clone_flags, p)))  
  177. 1148                 goto bad_fork_cleanup_semundo;  
  178. 1149         if ((retval = copy_fs(clone_flags, p)))  
  179. 1150                 goto bad_fork_cleanup_files;  
  180. 1151         if ((retval = copy_sighand(clone_flags, p)))  
  181. 1152                 goto bad_fork_cleanup_fs;  
  182. 1153         if ((retval = copy_signal(clone_flags, p)))  
  183. 1154                 goto bad_fork_cleanup_sighand;  
  184. 1155         if ((retval = copy_mm(clone_flags, p)))  
  185. 1156                 goto bad_fork_cleanup_signal;  
  186. 1157         if ((retval = copy_namespaces(clone_flags, p)))  
  187. 1158                 goto bad_fork_cleanup_mm;  
  188. 1159         if ((retval = copy_io(clone_flags, p)))  
  189. 1160                 goto bad_fork_cleanup_namespaces;  
  190. 1161         retval = copy_thread(clone_flags, stack_start, stack_size, p, regs);  
  191. 1162         if (retval)  
  192. 1163                 goto bad_fork_cleanup_io;  
  193. 1164   
  194. 1165         if (pid != &init_struct_pid) {  
  195. 1166                 retval = -ENOMEM;  
  196. 1167                 pid = alloc_pid(p->nsproxy->pid_ns);  
  197. 1168                 if (!pid)  
  198. 1169                         goto bad_fork_cleanup_io;  
  199. 1170   
  200. 1171                 if (clone_flags & CLONE_NEWPID) {  
  201. 1172                         retval = pid_ns_prepare_proc(p->nsproxy->pid_ns);  
  202. 1173                         if (retval < 0)  
  203. 1174                                 goto bad_fork_free_pid;  
  204. 1175                 }  
  205. 1176         }  
  206. 1177   
  207. 1178         p->pid = pid_nr(pid);  
  208. 1179         p->tgid = p->pid;  
  209. 1180         if (clone_flags & CLONE_THREAD)  
  210. 1181                 p->tgid = current->tgid;  
  211. 1182   
  212. 1183         if (current->nsproxy != p->nsproxy) {  
  213. 1184                 retval = ns_cgroup_clone(p, pid);  
  214. 1185                 if (retval)  
  215. 1186                         goto bad_fork_free_pid;  
  216. 1187         }  
  217. 1188   
  218. 1189         p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;  
  219. 1190         /* 
  220. 1191          * Clear TID on mm_release()? 
  221. 1192          */  
  222. 1193         p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr: NULL;  
  223. 1194 #ifdef CONFIG_FUTEX  
  224. 1195         p->robust_list = NULL;  
  225. 1196 #ifdef CONFIG_COMPAT  
  226. 1197         p->compat_robust_list = NULL;  
  227. 1198 #endif  
  228. 1199         INIT_LIST_HEAD(&p->pi_state_list);  
  229. 1200         p->pi_state_cache = NULL;  
  230. 1201 #endif  
  231. 1202         /* 
  232. 1203          * sigaltstack should be cleared when sharing the same VM 
  233. 1204          */  
  234. 1205         if ((clone_flags & (CLONE_VM|CLONE_VFORK)) == CLONE_VM)  
  235. 1206                 p->sas_ss_sp = p->sas_ss_size = 0;  
  236. 1207   
  237. 1208         /* 
  238. 1209          * Syscall tracing should be turned off in the child regardless 
  239. 1210          * of CLONE_PTRACE. 
  240. 1211          */  
  241. 1212         clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE);  
  242. 1213 #ifdef TIF_SYSCALL_EMU  
  243. 1214         clear_tsk_thread_flag(p, TIF_SYSCALL_EMU);  
  244. 1215 #endif  
  245. 1216         clear_all_latency_tracing(p);  
  246. 1217   
  247. 1218         /* ok, now we should be set up.. */  
  248. 1219         p->exit_signal = (clone_flags & CLONE_THREAD) ? -1 : (clone_flags & CSIGNAL);  
  249. 1220         p->pdeath_signal = 0;  
  250. 1221         p->exit_state = 0;  
  251. 1222   
  252. 1223         /* 
  253. 1224          * Ok, make it visible to the rest of the system. 
  254. 1225          * We dont wake it up yet. 
  255. 1226          */  
  256. 1227         p->group_leader = p;  
  257. 1228         INIT_LIST_HEAD(&p->thread_group);  
  258. 1229   
  259. 1230         /* Now that the task is set up, run cgroup callbacks if 
  260. 1231          * necessary. We need to run them before the task is visible 
  261. 1232          * on the tasklist. */  
  262. 1233         cgroup_fork_callbacks(p);  
  263. 1234         cgroup_callbacks_done = 1;  
  264. 1235   
  265. 1236         /* Need tasklist lock for parent etc handling! */  
  266. 1237         write_lock_irq(&tasklist_lock);  
  267. 1238   
  268. 1239         /* CLONE_PARENT re-uses the old parent */  
  269. 1240         if (clone_flags & (CLONE_PARENT|CLONE_THREAD)) {  
  270. 1241                 p->real_parent = current->real_parent;  
  271. 1242                 p->parent_exec_id = current->parent_exec_id;  
  272. 1243         } else {  
  273. 1244                 p->real_parent = current;  
  274. 1245                 p->parent_exec_id = current->self_exec_id;  
  275. 1246         }  
  276. 1247   
  277. 1248         spin_lock(?t->sighand->siglock);  
  278. 1249   
  279. 1250         /* 
  280. 1251          * Process group and session signals need to be delivered to just the 
  281. 1252          * parent before the fork or both the parent and the child after the 
  282. 1253          * fork. Restart if a signal comes in before we add the new process to 
  283. 1254          * it's process group. 
  284. 1255          * A fatal signal pending means that current will exit, so the new 
  285. 1256          * thread can't slip out of an OOM kill (or normal SIGKILL). 
  286. 1257          */  
  287. 1258         recalc_sigpending();  
  288. 1259         if (signal_pending(current)) {  
  289. 1260                 spin_unlock(?t->sighand->siglock);  
  290. 1261                 write_unlock_irq(&tasklist_lock);  
  291. 1262                 retval = -ERESTARTNOINTR;  
  292. 1263                 goto bad_fork_free_pid;  
  293. 1264         }  
  294. 1265   
  295. 1266         if (clone_flags & CLONE_THREAD) {  
  296. 1267                 atomic_inc(?t->signal->count);  
  297. 1268                 atomic_inc(?t->signal->live);  
  298. 1269                 p->group_leader = current->group_leader;  
  299. 1270                 list_add_tail_rcu(&p->thread_group, &p->group_leader->thread_group);  
  300. 1271         }  
  301. 1272   
  302. 1273         if (likely(p->pid)) {  
  303. 1274                 list_add_tail(&p->sibling, &p->real_parent->children);  
  304. 1275                 tracehook_finish_clone(p, clone_flags, trace);  
  305. 1276   
  306. 1277                 if (thread_group_leader(p)) {  
  307. 1278                         if (clone_flags & CLONE_NEWPID)  
  308. 1279                                 p->nsproxy->pid_ns->child_reaper = p;  
  309. 1280   
  310. 1281                         p->signal->leader_pid = pid;  
  311. 1282                         tty_kref_put(p->signal->tty);  
  312. 1283                         p->signal->tty = tty_kref_get(current->signal->tty);  
  313. 1284                         attach_pid(p, PIDTYPE_PGID, task_pgrp(current));  
  314. 1285                         attach_pid(p, PIDTYPE_SID, task_session(current));  
  315. 1286                         list_add_tail_rcu(&p->tasks, &init_task.tasks);  
  316. 1287                         __get_cpu_var(process_counts)++;  
  317. 1288                 }  
  318. 1289                 attach_pid(p, PIDTYPE_PID, pid);  
  319. 1290                 nr_threads++;  
  320. 1291         }  
  321. 1292   
  322. 1293         total_forks++;  
  323. 1294         spin_unlock(?t->sighand->siglock);  
  324. 1295         write_unlock_irq(&tasklist_lock);  
  325. 1296         proc_fork_connector(p);  
  326. 1297         cgroup_post_fork(p);  
  327. 1298         perf_event_fork(p);  
  328. 1299         return p;  
  329. 1300   
  330. 1301 bad_fork_free_pid:  
  331. 1302         if (pid != &init_struct_pid)  
  332. 1303                 free_pid(pid);  
  333. 1304 bad_fork_cleanup_io:  
  334. 1305         if (p->io_context)  
  335. 1306                 exit_io_context(p);  
  336. 1307 bad_fork_cleanup_namespaces:  
  337. 1308         exit_task_namespaces(p);  
  338. 1309 bad_fork_cleanup_mm:  
  339. 1310         if (p->mm)  
  340. 1311                 mmput(p->mm);  
  341. 1312 bad_fork_cleanup_signal:  
  342. 1313         if (!(clone_flags & CLONE_THREAD))  
  343. 1314                 __cleanup_signal(p->signal);  
  344. 1315 bad_fork_cleanup_sighand:  
  345. 1316         __cleanup_sighand(p->sighand);  
  346. 1317 bad_fork_cleanup_fs:  
  347. 1318         exit_fs(p); /* blocking */  
  348. 1319 bad_fork_cleanup_files:  
  349. 1320         exit_files(p); /* blocking */  
  350. 1321 bad_fork_cleanup_semundo:  
  351. 1322         exit_sem(p);  
  352. 1323 bad_fork_cleanup_audit:  
  353. 1324         audit_free(p);  
  354. 1325 bad_fork_cleanup_policy:  
  355. 1326         perf_event_free_task(p);  
  356. 1327 #ifdef CONFIG_NUMA  
  357. 1328         mpol_put(p->mempolicy);  
  358. 1329 bad_fork_cleanup_cgroup:  
  359. 1330 #endif  
  360. 1331         cgroup_exit(p, cgroup_callbacks_done);  
  361. 1332         delayacct_tsk_free(p);  
  362. 1333         module_put(task_thread_info(p)->exec_domain->module);  
  363. 1334 bad_fork_cleanup_count:  
  364. 1335         atomic_dec(&p->cred->user->processes);  
  365. 1336         exit_creds(p);  
  366. 1337 bad_fork_free:  
  367. 1338         free_task(p);  
  368. 1339 fork_out:  
  369. 1340         return ERR_PTR(retval);  
  370. 1341 }  

i.clone_flags共存标识检查
ii.复制进程描述符dup_task_struct
iii.检查用户当前进程数未超限
iv.复制凭证copy_creds
v.检查当前系统范围内进程数未超限;max_threads在fork_init中初始化,=可用内存/内核椎栈大小/8(每个进程都有自己的内核椎栈,每个椎栈大小是4k或8k),即内核堆栈大小不能超过可用内存的1/8
vi.初始化子进程进程描述符,即与父进程不同的地方复制成新值;清空子进程链表、清空pending的信号、设置时间等
vii.初始化进程调度信息sched_fork
viii.复制信号量撤销链表copy_semundo
ix.复制打开文件信息copy_files
x.复制文件系统信息copy_fs
xi.复制信号处理描述符copy_sighand
xii.复制信号描述符copy_signal
xiii.复制地址空间信息copy_mm
xiv.复制命名空间copy_namespaces
xv.复制子进程运行环境copy_thread
xvi.分配子进程id,并设置相应的进程号pid、线程组长号tgid、线程组长group_leader、父进程real_parent
xvii.将进程链入父进程的子进程链表、进程组成员链表、会话组成员链表、进程链表

ii.dup_task_struct

  1. kernel/fork.c  
  2.  222 static struct task_struct *dup_task_struct(struct task_struct *orig)  
  3.  223 {  
  4.  224         struct task_struct *tsk;  
  5.  225         struct thread_info *ti;  
  6.  226         unsigned long *stackend;  
  7.  227   
  8.  228         int err;  
  9.  229   
  10.  230         prepare_to_copy(orig);  
  11.  231   
  12.  232         tsk = alloc_task_struct();  
  13.  233         if (!tsk)  
  14.  234                 return NULL;  
  15.  235   
  16.  236         ti = alloc_thread_info(tsk);  
  17.  237         if (!ti) {  
  18.  238                 free_task_struct(tsk);  
  19.  239                 return NULL;  
  20.  240         }  
  21.  241   
  22.  242         err = arch_dup_task_struct(tsk, orig);  
  23.  243         if (err)  
  24.  244                 goto out;  
  25.  245   
  26.  246         tsk->stack = ti;  
  27.  247   
  28.  248         err = prop_local_init_single(&tsk->dirties);  
  29.  249         if (err)  
  30.  250                 goto out;  
  31.  251   
  32.  252         setup_thread_stack(tsk, orig);  
  33.  253         stackend = end_of_stack(tsk);  
  34.  254         *stackend = STACK_END_MAGIC;    /* for overflow detection */  
  35.  255   
  36.  256 #ifdef CONFIG_CC_STACKPROTECTOR  
  37.  257         tsk->stack_canary = get_random_int();  
  38.  258 #endif  
  39.  259   
  40.  260         /* One for us, one for whoever does the "release_task()" (usually parent) */  
  41.  261         atomic_set(&tsk->usage,2);  
  42.  262         atomic_set(&tsk->fs_excl, 0);  
  43.  263 #ifdef CONFIG_BLK_DEV_IO_TRACE  
  44.  264         tsk->btrace_seq = 0;  
  45.  265 #endif  
  46.  266         tsk->splice_pipe = NULL;  
  47.  267   
  48.  268         account_kernel_stack(ti, 1);  
  49.  269   
  50.  270         return tsk;  
  51.  271   
  52.  272 out:  
  53.  273         free_thread_info(ti);  
  54.  274         free_task_struct(tsk);  
  55.  275         return NULL;  
  56.  276 }  

  1.分配进程描述符
  2.分配thread_info及内核堆栈
  3.复制父进程描述符信息
  4.进程描述符与内核堆栈关联起来
  5.复制thread_info信息
  6.内核堆栈设置幻数,以防堆栈越界
  7.设置进程描述符引用计数

 

iv.copy_creds

  1. kernel/cred.c  
  2. 427 /* 
  3. 428  * Copy credentials for the new process created by fork() 
  4. 429  * 
  5. 430  * We share if we can, but under some circumstances we have to generate a new 
  6. 431  * set. 
  7. 432  * 
  8. 433  * The new process gets the current process's subjective credentials as its 
  9. 434  * objective and subjective credentials 
  10. 435  */  
  11. 436 int copy_creds(struct task_struct *p, unsigned long clone_flags)  
  12. 437 {  
  13. 438 #ifdef CONFIG_KEYS  
  14. 439         struct thread_group_cred *tgcred;  
  15. 440 #endif  
  16. 441         struct cred *new;  
  17. 442         int ret;  
  18. 443   
  19. 444         mutex_init(&p->cred_guard_mutex);  
  20. 445   
  21. 446         p->replacement_session_keyring = NULL;  
  22. 447   
  23. 448         if (  
  24. 449 #ifdef CONFIG_KEYS  
  25. 450                 !p->cred->thread_keyring &&  
  26. 451 #endif  
  27. 452                 clone_flags & CLONE_THREAD  
  28. 453             ) {  
  29. 454                 p->real_cred = get_cred(p->cred);  
  30. 455                 get_cred(p->cred);  
  31. 456                 alter_cred_subscribers(p->cred, 2);  
  32. 457                 kdebug("share_creds(%p{%d,%d})",  
  33. 458                        p->cred, atomic_read(&p->cred->usage),  
  34. 459                        read_cred_subscribers(p->cred));  
  35. 460                 atomic_inc(&p->cred->user->processes);  
  36. 461                 return 0;  
  37. 462         }  
  38. 463   
  39. 464         new = prepare_creds();  
  40. 465         if (!new)  
  41. 466                 return -ENOMEM;  
  42. 467   
  43. 468         if (clone_flags & CLONE_NEWUSER) {  
  44. 469                 ret = create_user_ns(new);  
  45. 470                 if (ret < 0)  
  46. 471                         goto error_put;  
  47. 472         }  
  48. 473   
  49. 474 #ifdef CONFIG_KEYS  
  50. 475         /* new threads get their own thread keyrings if their parent already 
  51. 476          * had one */  
  52. 477         if (new->thread_keyring) {  
  53. 478                 key_put(new->thread_keyring);  
  54. 479                 new->thread_keyring = NULL;  
  55. 480                 if (clone_flags & CLONE_THREAD)  
  56. 481                         install_thread_keyring_to_cred(new);  
  57. 482         }  
  58. 483   
  59. 484         /* we share the process and session keyrings between all the threads in 
  60. 485          * a process - this is slightly icky as we violate COW credentials a 
  61. 486          * bit */  
  62. 487         if (!(clone_flags & CLONE_THREAD)) {  
  63. 488                 tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);  
  64. 489                 if (!tgcred) {  
  65. 490                         ret = -ENOMEM;  
  66. 491                         goto error_put;  
  67. 492                 }  
  68. 493                 atomic_set(&tgcred->usage, 1);  
  69. 494                 spin_lock_init(&tgcred->lock);  
  70. 495                 tgcred->process_keyring = NULL;  
  71. 496                 tgcred->session_keyring = key_get(new->tgcred->session_keyring);  
  72. 497   
  73. 498                 release_tgcred(new);  
  74. 499                 new->tgcred = tgcred;  
  75. 500         }  
  76. 501 #endif  
  77. 502   
  78. 503         atomic_inc(&new->user->processes);  
  79. 504         p->cred = p->real_cred = get_cred(new);  
  80. 505         alter_cred_subscribers(new, 2);  
  81. 506         validate_creds(new);  
  82. 507         return 0;  
  83. 508   
  84. 509 error_put:  
  85. 510         put_cred(new);  
  86. 511         return ret;  
  87. 512 }             

  子进程的主/客体凭证复制自父进程的主体凭证
  1.如果是创建线程
    父进程的主体凭证引用计数器加1,将子进程的主/客体凭证指向父进程的主体凭证即可
  2.如果是创建进程
    a.分配凭证描述符并初始化,复制父进程主体凭证、引用计数器置1等
    b.子进程主/客体凭证指向新的凭证描述符
  用户进程数计数器加1

viii.copy_semundo

  1. /* ipc/sem.c */  
  2. 1244 /* If CLONE_SYSVSEM is set, establish sharing of SEM_UNDO state between 
  3. 1245  * parent and child tasks. 
  4. 1246  */  
  5. 1247   
  6. 1248 int copy_semundo(unsigned long clone_flags, struct task_struct *tsk)  
  7. 1249 {  
  8. 1250         struct sem_undo_list *undo_list;  
  9. 1251         int error;  
  10. 1252   
  11. 1253         if (clone_flags & CLONE_SYSVSEM) {  
  12. 1254                 error = get_undo_list(&undo_list);  
  13. 1255                 if (error)  
  14. 1256                         return error;  
  15. 1257                 atomic_inc(&undo_list->refcnt);  
  16. 1258                 tsk->sysvsem.undo_list = undo_list;  
  17. 1259         } else  
  18. 1260                 tsk->sysvsem.undo_list = NULL;  
  19. 1261   
  20. 1262         return 0;  
  21. 1263 }  

  1.如果与父进程共享信号量,将子进程的信号量撤销链表指向父进程的撤销链表
  2.如果不与父进程共享信号量,清空子进程的信号量撤销链表 
 
ix.copy_files

  1. /* kernel/fork.c */  
  2.  748 static int copy_files(unsigned long clone_flags, struct task_struct * tsk)  
  3.  749 {  
  4.  750         struct files_struct *oldf, *newf;  
  5.  751         int error = 0;  
  6.  752   
  7.  753         /* 
  8.  754          * A background process may not have any files ... 
  9.  755          */  
  10.  756         oldf = current->files;  
  11.  757         if (!oldf)  
  12.  758                 goto out;  
  13.  759   
  14.  760         if (clone_flags & CLONE_FILES) {  
  15.  761                 atomic_inc(&oldf->count);  
  16.  762                 goto out;  
  17.  763         }  
  18.  764   
  19.  765         newf = dup_fd(oldf, &error);  
  20.  766         if (!newf)  
  21.  767                 goto out;  
  22.  768   
  23.  769         tsk->files = newf;  
  24.  770         error = 0;  
  25.  771 out:  
  26.  772         return error;  
  27.  773 }  
  28.    
  29. /* fs/file.c */  
  30. 289 /* 
  31. 290  * Allocate a new files structure and copy contents from the 
  32. 291  * passed in files structure. 
  33. 292  * errorp will be valid only when the returned files_struct is NULL. 
  34. 293  */  
  35. 294 struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)  
  36. 295 {  
  37. 296         struct files_struct *newf;  
  38. 297         struct file **old_fds, **new_fds;  
  39. 298         int open_files, size, i;  
  40. 299         struct fdtable *old_fdt, *new_fdt;  
  41. 300   
  42. 301         *errorp = -ENOMEM;  
  43. 302         newf = kmem_cache_alloc(files_cachep, GFP_KERNEL);  
  44. 303         if (!newf)  
  45. 304                 goto out;  
  46. 305   
  47. 306         atomic_set(&newf->count, 1);  
  48. 307   
  49. 308         spin_lock_init(&newf->file_lock);  
  50. 309         newf->next_fd = 0;  
  51. 310         new_fdt = &newf->fdtab;  
  52. 311         new_fdt->max_fds = NR_OPEN_DEFAULT;  
  53. 312         new_fdt->close_on_exec = (fd_set *)&newf->close_on_exec_init;  
  54. 313         new_fdt->open_fds = (fd_set *)&newf->open_fds_init;  
  55. 314         new_fdt->fd = &newf->fd_array[0];  
  56. 315         INIT_RCU_HEAD(&new_fdt->rcu);  
  57. 316         new_fdt->next = NULL;  
  58. 317   
  59. 318         spin_lock(&oldf->file_lock);  
  60. 319         old_fdt = files_fdtable(oldf);  
  61. 320         open_files = count_open_files(old_fdt);  
  62. 321   
  63. 322         /* 
  64. 323          * Check whether we need to allocate a larger fd array and fd set. 
  65. 324          */  
  66. 325         while (unlikely(open_files > new_fdt->max_fds)) {  
  67. 326                 spin_unlock(&oldf->file_lock);  
  68. 327   
  69. 328                 if (new_fdt != &newf->fdtab) {  
  70. 329                         free_fdarr(new_fdt);  
  71. 330                         free_fdset(new_fdt);  
  72. 331                         kfree(new_fdt);  
  73. 332                 }  
  74. 333   
  75. 334                 new_fdt = alloc_fdtable(open_files - 1);  
  76. 335                 if (!new_fdt) {  
  77. 336                         *errorp = -ENOMEM;  
  78. 337                         goto out_release;  
  79. 338                 }  
  80. 339   
  81. 340                 /* beyond sysctl_nr_open; nothing to do */  
  82. 341                 if (unlikely(new_fdt->max_fds < open_files)) {  
  83. 342                         free_fdarr(new_fdt);  
  84. 343                         free_fdset(new_fdt);  
  85. 344                         kfree(new_fdt);  
  86. 345                         *errorp = -EMFILE;  
  87. 346                         goto out_release;  
  88. 347                 }  
  89. 348   
  90. 349                 /* 
  91. 350                  * Reacquire the oldf lock and a pointer to its fd table 
  92. 351                  * who knows it may have a new bigger fd table. We need 
  93. 352                  * the latest pointer. 
  94. 353                  */  
  95. 354                 spin_lock(&oldf->file_lock);  
  96. 355                 old_fdt = files_fdtable(oldf);  
  97. 356                 open_files = count_open_files(old_fdt);  
  98. 357         }  
  99. 358   
  100. 359         old_fds = old_fdt->fd;  
  101. 360         new_fds = new_fdt->fd;  
  102. 361   
  103. 362         memcpy(new_fdt->open_fds->fds_bits,  
  104. 363                 old_fdt->open_fds->fds_bits, open_files/8);  
  105. 364         memcpy(new_fdt->close_on_exec->fds_bits,  
  106. 365                 old_fdt->close_on_exec->fds_bits, open_files/8);  
  107. 366   
  108. 367         for (i = open_files; i != 0; i--) {  
  109. 368                 struct file *f = *old_fds++;  
  110. 369                 if (f) {  
  111. 370                         get_file(f);  
  112. 371                 } else {  
  113. 372                         /* 
  114. 373                          * The fd may be claimed in the fd bitmap but not yet 
  115. 374                          * instantiated in the files array if a sibling thread 
  116. 375                          * is partway through open().  So make sure that this 
  117. 376                          * fd is available to the new process. 
  118. 377                          */  
  119. 378                         FD_CLR(open_files - i, new_fdt->open_fds);  
  120. 379                 }  
  121. 380                 rcu_assign_pointer(*new_fds++, f);  
  122. 381         }  
  123. 382         spin_unlock(&oldf->file_lock);  
  124. 383   
  125. 384         /* compute the remainder to be cleared */  
  126. 385         size = (new_fdt->max_fds - open_files) * sizeof(struct file *);  
  127. 386   
  128. 387         /* This is long word aligned thus could use a optimized version */  
  129. 388         memset(new_fds, 0, size);  
  130. 389   
  131. 390         if (new_fdt->max_fds > open_files) {  
  132. 391                 int left = (new_fdt->max_fds-open_files)/8;  
  133. 392                 int start = open_files / (8 * sizeof(unsigned long));  
  134. 393   
  135. 394                 memset(&new_fdt->open_fds->fds_bits[start], 0, left);  
  136. 395                 memset(&new_fdt->close_on_exec->fds_bits[start], 0, left);  
  137. 396         }  
  138. 397   
  139. 398         rcu_assign_pointer(newf->fdt, new_fdt);  
  140. 399   
  141. 400         return newf;  
  142. 401   
  143. 402 out_release:  
  144. 403         kmem_cache_free(files_cachep, newf);  
  145. 404 out:  
  146. 405         return NULL;  
  147. 406 }  

  1.如果共享打开文件,将父进程打开文件描述符引用计数器加1
  2.如果不共享,复制父进程打开文件描述符;
    A.分配打开文件描述符
    B.初始化打开文件描述符
      a.打开文件描述符引用计数器置1
      b.将打开文件描述符表指向预分配的文件描述符表,并初始化描述符表的打开文件位图、exec关闭文件位图、file数组指向预分配结构
    C.如果预分配的文件描述符表小于父进程已经打开的文件,则重新分配打开文件描述符表
    D.复制父进程打开文件位图、exec关闭文件位图信息
    E.将父进程打开的文件引用计数器加1,并添加到子进程打开文件描述符表中
    F.将文件描述符表中多出的file数组、打开文件位图、exec关闭文件位图清空
    G.将打开文件描述符中的fdt指向文件描述符表
下图表示files_struct与file之间的关系:

x.copy_fs
  1. /* kernel/fork.c */  
  2.  728 static int copy_fs(unsigned long clone_flags, struct task_struct *tsk)  
  3.  729 {  
  4.  730         struct fs_struct *fs = current->fs;  
  5.  731         if (clone_flags & CLONE_FS) {  
  6.  732                 /* tsk->fs is already what we want */  
  7.  733                 write_lock(&fs->lock);  
  8.  734                 if (fs->in_exec) {  
  9.  735                         write_unlock(&fs->lock);  
  10.  736                         return -EAGAIN;  
  11.  737                 }  
  12.  738                 fs->users++;  
  13.  739                 write_unlock(&fs->lock);  
  14.  740                 return 0;  
  15.  741         }  
  16.  742         tsk->fs = copy_fs_struct(fs);  
  17.  743         if (!tsk->fs)  
  18.  744                 return -ENOMEM;  
  19.  745         return 0;  
  20.  746 }  

1.如果CLONE_FS,文件系统描述符引用计数器加1
2.复制文件系统描述符,包含当前目录及根目录信息

 

xi.copy_sighand

  1. /* kernel/fork.c */  
  2.  800 static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk)  
  3.  801 {  
  4.  802         struct sighand_struct *sig;  
  5.  803   
  6.  804         if (clone_flags & CLONE_SIGHAND) {  
  7.  805                 atomic_inc(?t->sighand->count);  
  8.  806                 return 0;  
  9.  807         }  
  10.  808         sig = kmem_cache_alloc(sighand_cachep, GFP_KERNEL);  
  11.  809         rcu_assign_pointer(tsk->sighand, sig);  
  12.  810         if (!sig)  
  13.  811                 return -ENOMEM;  
  14.  812         atomic_set(&sig->count, 1);  
  15.  813         memcpy(sig->action, current->sighand->action, sizeof(sig->action));  
  16.  814         return 0;  
  17.  815 }  

  1.如果共享信号处理,父进程信号处理描述符引用计数器加1即可
  2.分配信号处理描述符,复制父进程信号处理描述符表;新的信号处理描述符表引用计数器置1,并与子进程关联
 
xii.copy_signal

  1. /* kernel/fork.c */  
  2.  857 static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)  
  3.  858 {  
  4.  859         struct signal_struct *sig;  
  5.  860   
  6.  861         if (clone_flags & CLONE_THREAD)  
  7.  862                 return 0;  
  8.  863   
  9.  864         sig = kmem_cache_alloc(signal_cachep, GFP_KERNEL);  
  10.  865         tsk->signal = sig;  
  11.  866         if (!sig)  
  12.  867                 return -ENOMEM;  
  13.  868   
  14.  869         atomic_set(&sig->count, 1);  
  15.  870         atomic_set(&sig->live, 1);  
  16.  871         init_waitqueue_head(&sig->wait_chldexit);  
  17.  872         sig->flags = 0;  
  18.  873         if (clone_flags & CLONE_NEWPID)  
  19.  874                 sig->flags |= SIGNAL_UNKILLABLE;  
  20.  875         sig->group_exit_code = 0;  
  21.  876         sig->group_exit_task = NULL;  
  22.  877         sig->group_stop_count = 0;  
  23.  878         sig->curr_target = tsk;  
  24.  879         init_sigpending(&sig->shared_pending);  
  25.  880         INIT_LIST_HEAD(&sig->posix_timers);  
  26.  881   
  27.  882         hrtimer_init(&sig->real_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);  
  28.  883         sig->it_real_incr.tv64 = 0;  
  29.  884         sig->real_timer.function = it_real_fn;  
  30.  885   
  31.  886         sig->leader = 0;        /* session leadership doesn't inherit */  
  32.  887         sig->tty_old_pgrp = NULL;  
  33.  888         sig->tty = NULL;  
  34.  889   
  35.  890         sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero;  
  36.  891         sig->gtime = cputime_zero;  
  37.  892         sig->cgtime = cputime_zero;  
  38.  893 #ifndef CONFIG_VIRT_CPU_ACCOUNTING  
  39.  894         sig->prev_utime = sig->prev_stime = cputime_zero;  
  40.  895 #endif  
  41.  896         sig->nvcsw = sig->nivcsw = sig->cnvcsw = sig->cnivcsw = 0;  
  42.  897         sig->min_flt = sig->maj_flt = sig->cmin_flt = sig->cmaj_flt = 0;  
  43.  898         sig->inblock = sig->oublock = sig->cinblock = sig->coublock = 0;  
  44.  899         sig->maxrss = sig->cmaxrss = 0;  
  45.  900         task_io_accounting_init(&sig->ioac);  
  46.  901         sig->sum_sched_runtime = 0;  
  47.  902         taskstats_tgid_init(sig);  
  48.  903   
  49.  904         task_lock(current->group_leader);  
  50.  905         memcpy(sig->rlim, current->signal->rlim, sizeof sig->rlim);  
  51.  906         task_unlock(current->group_leader);  
  52.  907   
  53.  908         posix_cpu_timers_init_group(sig);  
  54.  909   
  55.  910         acct_init_pacct(&sig->pacct);  
  56.  911   
  57.  912         tty_audit_fork(sig);  
  58.  913   
  59.  914         sig->oom_adj = current->signal->oom_adj;  
  60.  915   
  61.  916         return 0;  
  62.  917 }  

  1.如果创建线程,跳过
  2.分配信号描述符
  3.初始化信号描述符,引用计数器置1、清空共享信号pending
 
xiii.copy_mm

  1. /* kernel/fork.c */  
  2.  681 static int copy_mm(unsigned long clone_flags, struct task_struct * tsk)  
  3.  682 {  
  4.  683         struct mm_struct * mm, *oldmm;  
  5.  684         int retval;  
  6.  685   
  7.  686         tsk->min_flt = tsk->maj_flt = 0;  
  8.  687         tsk->nvcsw = tsk->nivcsw = 0;  
  9.  688 #ifdef CONFIG_DETECT_HUNG_TASK  
  10.  689         tsk->last_switch_count = tsk->nvcsw + tsk->nivcsw;  
  11.  690 #endif  
  12.  691   
  13.  692         tsk->mm = NULL;  
  14.  693         tsk->active_mm = NULL;  
  15.  694   
  16.  695         /* 
  17.  696          * Are we cloning a kernel thread? 
  18.  697          * 
  19.  698          * We need to steal a active VM for that.. 
  20.  699          */  
  21.  700         oldmm = current->mm;  
  22.  701         if (!oldmm)  
  23.  702                 return 0;  
  24.  703   
  25.  704         if (clone_flags & CLONE_VM) {  
  26.  705                 atomic_inc(&oldmm->mm_users);  
  27.  706                 mm = oldmm;  
  28.  707                 goto good_mm;  
  29.  708         }  
  30.  709   
  31.  710         retval = -ENOMEM;  
  32.  711         mm = dup_mm(tsk);  
  33.  712         if (!mm)  
  34.  713                 goto fail_nomem;  
  35.  714   
  36.  715 good_mm:  
  37.  716         /* Initializing for Swap token stuff */  
  38.  717         mm->token_priority = 0;  
  39.  718         mm->last_interval = 0;  
  40.  719   
  41.  720         tsk->mm = mm;  
  42.  721         tsk->active_mm = mm;  
  43.  722         return 0;  
  44.  723   
  45.  724 fail_nomem:  
  46.  725         return retval;  
  47.  726 }  

1.分配地址空间描述符mm_struct
2.复制父进程地址空间描述符信息
3.初始化子进程地址空间描述符,覆盖从父进程地址空间描述符那里复制的部分;如引用数、map读写信号等
4.可执行文件引用计数器加1,以便在父进程退出后可执行文件也不会关闭
5.复制地址空间的映射区
  遍历地址空间段
  A.分配地址空间段描述符
  B.复制地址空间段描述符信息
  C.初始化地址空间段描述符,如将描述符从父进程链表&红黑树中删除、指向子进程的地址空间描述符等
  D.如果是文件映射;文件引用计数器加1等
  E.将地址空间段描述符添加到描述符链表及描述符红黑树中
  F.映射区计数加1
  G.复制页表copy_page_range
    修改可写页表项,添加页保护标志,当往该页写数据时产生缺页异常,缺页异常处理会为进程分配新的页帧,这就是COW(copy on write)技术,这样做即加速了fork过程并且又节省了内存;而只读页帧会在进程间共享,如代码段
    dup_mm->dup_mmap->copy_page_range->copy_pud_range->copy_pmd_range->copy_pte_range->copy_one_pte->ptep_set_wrprotect&pte_wrprotect
  H.回调地址空间的open函数

 

xiv.copy_namespaces

  1. /* kernel/nsproxy.c */  
  2. 103 /* 
  3. 104  * called from clone.  This now handles copy for nsproxy and all 
  4. 105  * namespaces therein. 
  5. 106  */  
  6. 107 int copy_namespaces(unsigned long flags, struct task_struct *tsk)  
  7. 108 {  
  8. 109         struct nsproxy *old_ns = tsk->nsproxy;  
  9. 110         struct nsproxy *new_ns;  
  10. 111         int err = 0;  
  11. 112   
  12. 113         if (!old_ns)  
  13. 114                 return 0;  
  14. 115   
  15. 116         get_nsproxy(old_ns);  
  16. 117   
  17. 118         if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |  
  18. 119                                 CLONE_NEWPID | CLONE_NEWNET)))  
  19. 120                 return 0;  
  20. 121   
  21. 122         if (!capable(CAP_SYS_ADMIN)) {  
  22. 123                 err = -EPERM;  
  23. 124                 goto out;  
  24. 125         }  
  25. 126   
  26. 127         /* 
  27. 128          * CLONE_NEWIPC must detach from the undolist: after switching 
  28. 129          * to a new ipc namespace, the semaphore arrays from the old 
  29. 130          * namespace are unreachable.  In clone parlance, CLONE_SYSVSEM 
  30. 131          * means share undolist with parent, so we must forbid using 
  31. 132          * it along with CLONE_NEWIPC. 
  32. 133          */  
  33. 134         if ((flags & CLONE_NEWIPC) && (flags & CLONE_SYSVSEM)) {  
  34. 135                 err = -EINVAL;  
  35. 136                 goto out;  
  36. 137         }  
  37. 138   
  38. 139         new_ns = create_new_namespaces(flags, tsk, tsk->fs);  
  39. 140         if (IS_ERR(new_ns)) {  
  40. 141                 err = PTR_ERR(new_ns);  
  41. 142                 goto out;  
  42. 143         }  
  43. 144   
  44. 145         tsk->nsproxy = new_ns;  
  45. 146   
  46. 147 out:  
  47. 148         put_nsproxy(old_ns);  
  48. 149         return err;  
  49. 150 }  

  1.如果clone_flags没有使用新命名空间标识,直接返回
  2.根据clone_flags中使用新命名空间标识,创建新的命名空间;修改子进程的命名空间nsproxy为新命名空间

 

xv.复制子进程运行环境copy_thread

  1. /* arch/x86/kernel/process_32.c */  
  2. 242 int copy_thread(unsigned long clone_flags, unsigned long sp,  
  3. 243         unsigned long unused,  
  4. 244         struct task_struct *p, struct pt_regs *regs)  
  5. 245 {  
  6. 246         struct pt_regs *childregs;  
  7. 247         struct task_struct *tsk;  
  8. 248         int err;  
  9. 249   
  10. 250         childregs = task_pt_regs(p);  
  11. 251         *childregs = *regs;  
  12. 252         childregs->ax = 0;  
  13. 253         childregs->sp = sp;  
  14. 254   
  15. 255         p->thread.sp = (unsigned long) childregs;  
  16. 256         p->thread.sp0 = (unsigned long) (childregs+1);  
  17. 257   
  18. 258         p->thread.ip = (unsigned long) ret_from_fork;  
  19. 259   
  20. 260         task_user_gs(p) = get_user_gs(regs);  
  21. 261   
  22. 262         tsk = current;  
  23. 263         if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) {  
  24. 264                 p->thread.io_bitmap_ptr = kmemdup(tsk->thread.io_bitmap_ptr,  
  25. 265                                                 IO_BITMAP_BYTES, GFP_KERNEL);  
  26. 266                 if (!p->thread.io_bitmap_ptr) {  
  27. 267                         p->thread.io_bitmap_max = 0;  
  28. 268                         return -ENOMEM;  
  29. 269                 }  
  30. 270                 set_tsk_thread_flag(p, TIF_IO_BITMAP);  
  31. 271         }  
  32. 272   
  33. 273         err = 0;  
  34. 274   
  35. 275         /* 
  36. 276          * Set a new TLS for the child thread? 
  37. 277          */  
  38. 278         if (clone_flags & CLONE_SETTLS)  
  39. 279                 err = do_set_thread_area(p, -1,  
  40. 280                         (struct user_desc __user *)childregs->si, 0);  
  41. 281   
  42. 282         if (err && p->thread.io_bitmap_ptr) {  
  43. 283                 kfree(p->thread.io_bitmap_ptr);  
  44. 284                 p->thread.io_bitmap_max = 0;  
  45. 285         }  
  46. 286   
  47. 287         clear_tsk_thread_flag(p, TIF_DS_AREA_MSR);  
  48. 288         p->thread.ds_ctx = NULL;  
  49. 289   
  50. 290         clear_tsk_thread_flag(p, TIF_DEBUGCTLMSR);  
  51. 291         p->thread.debugctlmsr = 0;  
  52. 292   
  53. 293         return err;  
  54. 294 }  

  1.将父进程内核堆栈中保存的寄存器值,复制到子进程的内核堆栈中;以便子进程在fork返回时与原进程状态一致
  2.设置子进程fork/vfork/clone返回值为0(系统调用返回值放在ax中)
  3.设置子进程用户空间的堆栈;fork、vfork的父进程与子进程的堆栈值一样,因为他们使用不同的进程地址空间,所以不会存在冲突;
  4.设置子进程的内核堆栈,因为子进程直接从fork返回,所以将栈顶设置成保存寄存器的起始位置
  5.设置子进程被调用后从ret_from_fork开始执行
dup_task_struct及copy_thread之后进程描述符及内核堆栈,如下图所示:


xvi.alloc_pid

  1. /* kernel/pid.c */  
  2. 245 struct pid *alloc_pid(struct pid_namespace *ns)  
  3. 246 {  
  4. 247         struct pid *pid;  
  5. 248         enum pid_type type;  
  6. 249         int i, nr;  
  7. 250         struct pid_namespace *tmp;  
  8. 251         struct upid *upid;  
  9. 252   
  10. 253         pid = kmem_cache_alloc(ns->pid_cachep, GFP_KERNEL);  
  11. 254         if (!pid)  
  12. 255                 goto out;  
  13. 256   
  14. 257         tmp = ns;  
  15. 258         for (i = ns->level; i >= 0; i--) {  
  16. 259                 nr = alloc_pidmap(tmp);  
  17. 260                 if (nr < 0)  
  18. 261                         goto out_free;  
  19. 262   
  20. 263                 pid->numbers[i].nr = nr;  
  21. 264                 pid->numbers[i].ns = tmp;  
  22. 265                 tmp = tmp->parent;  
  23. 266         }  
  24. 267   
  25. 268         get_pid_ns(ns);  
  26. 269         pid->level = ns->level;  
  27. 270         atomic_set(&pid->count, 1);  
  28. 271         for (type = 0; type < PIDTYPE_MAX; ++type)  
  29. 272                 INIT_HLIST_HEAD(&pid->tasks[type]);  
  30. 273   
  31. 274         spin_lock_irq(&pidmap_lock);  
  32. 275         for (i = ns->level; i >= 0; i--) {  
  33. 276                 upid = &pid->numbers[i];  
  34. 277                 hlist_add_head_rcu(&upid->pid_chain,  
  35. 278                                 &pid_hash[pid_hashfn(upid->nr, upid->ns)]);  
  36. 279         }  
  37. 280         spin_unlock_irq(&pidmap_lock);  
  38. 281   
  39. 282 out:  
  40. 283         return pid;  
  41. 284   
  42. 285 out_free:  
  43. 286         while (++i <= ns->level)  
  44. 287                 free_pidmap(pid->numbers + i);  
  45. 288   
  46. 289         kmem_cache_free(ns->pid_cachep, pid);  
  47. 290         pid = NULL;  
  48. 291         goto out;  
  49. 292 }  

1.分配pid,从pidmap中查找空闲id,并赋给pid
2.将pid链入pid哈希表中,方便根据id打到进程描述符
pid分配如下图所示:


xvii.attach_pid

  1. /* kernel/pid.c */  
  2. 315 /* 
  3. 316  * attach_pid() must be called with the tasklist_lock write-held. 
  4. 317  */  
  5. 318 void attach_pid(struct task_struct *task, enum pid_type type,  
  6. 319                 struct pid *pid)  
  7. 320 {  
  8. 321         struct pid_link *link;  
  9. 322   
  10. 323         link = &task->pids[type];  
  11. 324         link->pid = pid;  
  12. 325         hlist_add_head_rcu(&link->node, &pid->tasks[type]);  
  13. 326 }  

1.取进程描述符中类型为type的pid_link
2.将link->pid置成pid
3.将link链入相应的pid中

下图表示进程添加到相应的进程、进程组、会话组后的关系:

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多