翼度科技»论坛 云主机 LINUX 查看内容

do_fork-->copy_process(二)

6

主题

6

帖子

18

积分

新手上路

Rank: 1

积分
18
 
  1.   1 /*
  2.   2  * This creates a new process as a copy of the old one,
  3.   3  * but does not actually start it yet.
  4.   4  *
  5.   5  * It copies the registers, and all the appropriate
  6.   6  * parts of the process environment (as per the clone
  7.   7  * flags). The actual kick-off is left to the caller.
  8.   8  */
  9.   9 struct task_struct *copy_process(unsigned long clone_flags,
  10. 10                  unsigned long stack_start,
  11. 11                  struct pt_regs *regs,
  12. 12                  unsigned long stack_size,
  13. 13                  int __user *parent_tidptr,
  14. 14                  int __user *child_tidptr)
  15. 15 {
  16. 16     int retval;
  17. 17     struct task_struct *p = NULL;
  18. 18
  19. 19     if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))
  20. 20         return ERR_PTR(-EINVAL);
  21. 21
  22. 22     /*
  23. 23      * Thread groups must share signals as well, and detached threads
  24. 24      * can only be started up within the thread group.
  25. 25      */
  26. 26     if ((clone_flags & CLONE_THREAD) && !(clone_flags & CLONE_SIGHAND))
  27. 27         return ERR_PTR(-EINVAL);
  28. 28
  29. 29     /*
  30. 30      * Shared signal handlers imply shared VM. By way of the above,
  31. 31      * thread groups also imply shared VM. Blocking this case allows
  32. 32      * for various simplifications in other code.
  33. 33      */
  34. 34     if ((clone_flags & CLONE_SIGHAND) && !(clone_flags & CLONE_VM))
  35. 35         return ERR_PTR(-EINVAL);
  36. 36
  37. 37     /*
  38. 38      * CLONE_DETACHED must match CLONE_THREAD: it's a historical
  39. 39      * thing.
  40. 40      */
  41. 41     if (!(clone_flags & CLONE_DETACHED) != !(clone_flags & CLONE_THREAD)) {
  42. 42         /* Warn about the old no longer supported case so that we see it */
  43. 43         if (clone_flags & CLONE_THREAD) {
  44. 44             static int count;
  45. 45             if (count < 5) {
  46. 46                 count++;
  47. 47                 printk(KERN_WARNING "%s trying to use CLONE_THREAD without CLONE_DETACH\n", current->comm);
  48. 48             }
  49. 49         }
  50. 50         return ERR_PTR(-EINVAL);
  51. 51     }
  52. 52
  53. 53     retval = security_task_create(clone_flags);
  54. 54     if (retval)
  55. 55         goto fork_out;
  56. 56
  57. 57     retval = -ENOMEM;
  58. 58     p = dup_task_struct(current);
  59. 59     if (!p)
  60. 60         goto fork_out;
  61. 61
  62. 62     retval = -EAGAIN;
  63. 63     if (atomic_read(&p->user->processes) >=
  64. 64             p->rlim[RLIMIT_NPROC].rlim_cur) {
  65. 65         if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) &&
  66. 66                 p->user != &root_user)
  67. 67             goto bad_fork_free;
  68. 68     }
  69. 69
  70. 70     atomic_inc(&p->user->__count);
  71. 71     atomic_inc(&p->user->processes);
  72. 72
  73. 73     /*
  74. 74      * If multiple threads are within copy_process(), then this check
  75. 75      * triggers too late. This doesn't hurt, the check is only there
  76. 76      * to stop root fork bombs.
  77. 77      */
  78. 78     if (nr_threads >= max_threads)
  79. 79         goto bad_fork_cleanup_count;
  80. 80
  81. 81     if (!try_module_get(p->thread_info->exec_domain->module))
  82. 82         goto bad_fork_cleanup_count;
  83. 83
  84. 84     if (p->binfmt && !try_module_get(p->binfmt->module))
  85. 85         goto bad_fork_cleanup_put_domain;
  86. 86
  87. 87 #ifdef CONFIG_PREEMPT
  88. 88     /*
  89. 89      * schedule_tail drops this_rq()->lock so we compensate with a count
  90. 90      * of 1.  Also, we want to start with kernel preemption disabled.
  91. 91      */
  92. 92     p->thread_info->preempt_count = 1;
  93. 93 #endif
  94. 94     p->did_exec = 0;
  95. 95     p->state = TASK_UNINTERRUPTIBLE;
  96. 96
  97. 97     copy_flags(clone_flags, p);
  98. 98     if (clone_flags & CLONE_IDLETASK)
  99. 99         p->pid = 0;
  100. 100     else {
  101. 101         p->pid = alloc_pidmap();
  102. 102         if (p->pid == -1)
  103. 103             goto bad_fork_cleanup;
  104. 104     }
  105. 105     retval = -EFAULT;
  106. 106     if (clone_flags & CLONE_PARENT_SETTID)
  107. 107         if (put_user(p->pid, parent_tidptr))
  108. 108             goto bad_fork_cleanup;
  109. 109
  110. 110     p->proc_dentry = NULL;
  111. 111
  112. 112     INIT_LIST_HEAD(&p->run_list);
  113. 113
  114. 114     INIT_LIST_HEAD(&p->children);
  115. 115     INIT_LIST_HEAD(&p->sibling);
  116. 116     INIT_LIST_HEAD(&p->posix_timers);
  117. 117     init_waitqueue_head(&p->wait_chldexit);
  118. 118     p->vfork_done = NULL;
  119. 119     spin_lock_init(&p->alloc_lock);
  120. 120     spin_lock_init(&p->switch_lock);
  121. 121     spin_lock_init(&p->proc_lock);
  122. 122
  123. 123     clear_tsk_thread_flag(p, TIF_SIGPENDING);
  124. 124     init_sigpending(&p->pending);
  125. 125
  126. 126     p->it_real_value = p->it_virt_value = p->it_prof_value = 0;
  127. 127     p->it_real_incr = p->it_virt_incr = p->it_prof_incr = 0;
  128. 128     init_timer(&p->real_timer);
  129. 129     p->real_timer.data = (unsigned long) p;
  130. 130
  131. 131     p->leader = 0;        /* session leadership doesn't inherit */
  132. 132     p->tty_old_pgrp = 0;
  133. 133     p->utime = p->stime = 0;
  134. 134     p->cutime = p->cstime = 0;
  135. 135     p->array = NULL;
  136. 136     p->lock_depth = -1;        /* -1 = no lock */
  137. 137     p->start_time = get_jiffies_64();
  138. 138     p->security = NULL;
  139. 139     p->io_context = NULL;
  140. 140
  141. 141     retval = -ENOMEM;
  142. 142     if ((retval = security_task_alloc(p)))
  143. 143         goto bad_fork_cleanup;
  144. 144     /* copy all the process information */
  145. 145     if ((retval = copy_semundo(clone_flags, p)))
  146. 146         goto bad_fork_cleanup_security;
  147. 147     if ((retval = copy_files(clone_flags, p)))
  148. 148         goto bad_fork_cleanup_semundo;
  149. 149     if ((retval = copy_fs(clone_flags, p)))
  150. 150         goto bad_fork_cleanup_files;
  151. 151     if ((retval = copy_sighand(clone_flags, p)))
  152. 152         goto bad_fork_cleanup_fs;
  153. 153     if ((retval = copy_signal(clone_flags, p)))
  154. 154         goto bad_fork_cleanup_sighand;
  155. 155     if ((retval = copy_mm(clone_flags, p)))
  156. 156         goto bad_fork_cleanup_signal;
  157. 157     if ((retval = copy_namespace(clone_flags, p)))
  158. 158         goto bad_fork_cleanup_mm;
  159. 159     retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);
  160. 160     if (retval)
  161. 161         goto bad_fork_cleanup_namespace;
  162. 162
  163. 163     p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
  164. 164     /*
  165. 165      * Clear TID on mm_release()?
  166. 166      */
  167. 167     p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr: NULL;
  168. 168
  169. 169     /*
  170. 170      * Syscall tracing should be turned off in the child regardless
  171. 171      * of CLONE_PTRACE.
  172. 172      */
  173. 173     clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE);
  174. 174
  175. 175     /* Our parent execution domain becomes current domain
  176. 176        These must match for thread signalling to apply */
  177. 177        
  178. 178     p->parent_exec_id = p->self_exec_id;
  179. 179
  180. 180     /* ok, now we should be set up.. */
  181. 181     p->exit_signal = (clone_flags & CLONE_THREAD) ? -1 : (clone_flags & CSIGNAL);
  182. 182     p->pdeath_signal = 0;
  183. 183
  184. 184     /*
  185. 185      * Share the timeslice between parent and child, thus the
  186. 186      * total amount of pending timeslices in the system doesn't change,
  187. 187      * resulting in more scheduling fairness.
  188. 188      */
  189. 189     local_irq_disable();
  190. 190         p->time_slice = (current->time_slice + 1) >> 1;
  191. 191     /*
  192. 192      * The remainder of the first timeslice might be recovered by
  193. 193      * the parent if the child exits early enough.
  194. 194      */
  195. 195     p->first_time_slice = 1;
  196. 196     current->time_slice >>= 1;
  197. 197     p->timestamp = sched_clock();
  198. 198     if (!current->time_slice) {
  199. 199         /*
  200. 200           * This case is rare, it happens when the parent has only
  201. 201           * a single jiffy left from its timeslice. Taking the
  202. 202          * runqueue lock is not a problem.
  203. 203          */
  204. 204         current->time_slice = 1;
  205. 205         preempt_disable();
  206. 206         scheduler_tick(0, 0);
  207. 207         local_irq_enable();
  208. 208         preempt_enable();
  209. 209     } else
  210. 210         local_irq_enable();
  211. 211     /*
  212. 212      * Ok, add it to the run-queues and make it
  213. 213      * visible to the rest of the system.
  214. 214      *
  215. 215      * Let it rip!
  216. 216      */
  217. 217     p->tgid = p->pid;
  218. 218     p->group_leader = p;
  219. 219     INIT_LIST_HEAD(&p->ptrace_children);
  220. 220     INIT_LIST_HEAD(&p->ptrace_list);
  221. 221
  222. 222     /* Need tasklist lock for parent etc handling! */
  223. 223     write_lock_irq(&tasklist_lock);
  224. 224     /*
  225. 225      * Check for pending SIGKILL! The new thread should not be allowed
  226. 226      * to slip out of an OOM kill. (or normal SIGKILL.)
  227. 227      */
  228. 228     if (sigismember(&current->pending.signal, SIGKILL)) {
  229. 229         write_unlock_irq(&tasklist_lock);
  230. 230         retval = -EINTR;
  231. 231         goto bad_fork_cleanup_namespace;
  232. 232     }
  233. 233
  234. 234     /* CLONE_PARENT re-uses the old parent */
  235. 235     if (clone_flags & CLONE_PARENT)
  236. 236         p->real_parent = current->real_parent;
  237. 237     else
  238. 238         p->real_parent = current;
  239. 239     p->parent = p->real_parent;
  240. 240
  241. 241     if (clone_flags & CLONE_THREAD) {
  242. 242         spin_lock(&current->sighand->siglock);
  243. 243         /*
  244. 244          * Important: if an exit-all has been started then
  245. 245          * do not create this new thread - the whole thread
  246. 246          * group is supposed to exit anyway.
  247. 247          */
  248. 248         if (current->signal->group_exit) {
  249. 249             spin_unlock(&current->sighand->siglock);
  250. 250             write_unlock_irq(&tasklist_lock);
  251. 251             retval = -EAGAIN;
  252. 252             goto bad_fork_cleanup_namespace;
  253. 253         }
  254. 254         p->tgid = current->tgid;
  255. 255         p->group_leader = current->group_leader;
  256. 256
  257. 257         if (current->signal->group_stop_count > 0) {
  258. 258             /*
  259. 259              * There is an all-stop in progress for the group.
  260. 260              * We ourselves will stop as soon as we check signals.
  261. 261              * Make the new thread part of that group stop too.
  262. 262              */
  263. 263             current->signal->group_stop_count++;
  264. 264             set_tsk_thread_flag(p, TIF_SIGPENDING);
  265. 265         }
  266. 266
  267. 267         spin_unlock(&current->sighand->siglock);
  268. 268     }
  269. 269
  270. 270     SET_LINKS(p);
  271. 271     if (p->ptrace & PT_PTRACED)
  272. 272         __ptrace_link(p, current->parent);
  273. 273
  274. 274     attach_pid(p, PIDTYPE_PID, p->pid);
  275. 275     if (thread_group_leader(p)) {
  276. 276         attach_pid(p, PIDTYPE_TGID, p->tgid);
  277. 277         attach_pid(p, PIDTYPE_PGID, process_group(p));
  278. 278         attach_pid(p, PIDTYPE_SID, p->session);
  279. 279         if (p->pid)
  280. 280             __get_cpu_var(process_counts)++;
  281. 281     } else
  282. 282         link_pid(p, p->pids + PIDTYPE_TGID, &p->group_leader->pids[PIDTYPE_TGID].pid);
  283. 283
  284. 284     nr_threads++;
  285. 285     write_unlock_irq(&tasklist_lock);
  286. 286     retval = 0;
  287. 287
  288. 288 fork_out:
  289. 289     if (retval)
  290. 290         return ERR_PTR(retval);
  291. 291     return p;
  292. 292
  293. 293 bad_fork_cleanup_namespace:
  294. 294     exit_namespace(p);
  295. 295 bad_fork_cleanup_mm:
  296. 296     exit_mm(p);
  297. 297 bad_fork_cleanup_signal:
  298. 298     exit_signal(p);
  299. 299 bad_fork_cleanup_sighand:
  300. 300     exit_sighand(p);
  301. 301 bad_fork_cleanup_fs:
  302. 302     exit_fs(p); /* blocking */
  303. 303 bad_fork_cleanup_files:
  304. 304     exit_files(p); /* blocking */
  305. 305 bad_fork_cleanup_semundo:
  306. 306     exit_sem(p);
  307. 307 bad_fork_cleanup_security:
  308. 308     security_task_free(p);
  309. 309 bad_fork_cleanup:
  310. 310     if (p->pid > 0)
  311. 311         free_pidmap(p->pid);
  312. 312     if (p->binfmt)
  313. 313         module_put(p->binfmt->module);
  314. 314 bad_fork_cleanup_put_domain:
  315. 315     module_put(p->thread_info->exec_domain->module);
  316. 316 bad_fork_cleanup_count:
  317. 317     atomic_dec(&p->user->processes);
  318. 318     free_uid(p->user);
  319. 319 bad_fork_free:
  320. 320     free_task(p);
  321. 321     goto fork_out;
  322. 322 }
复制代码
 
17行:struct task_struct 结构体包含了进程相关的所有属性和信息(也叫进程控制块, Process Control Block, PCB)。包含:进程属性相关信息,进程间关系,进程调度信息,内存管理信息,文件管理信息,信号处理相关信息,资源限制相关信息。
19,26,34,41行:检查flags标记位, clone_flags 是在调用do_fork时的入参,不同的函数调用,参数不同。(通常对应的是不同的系统调用,fork,vfork)


53行:安全性检查,询问Linux Security Moudule(LSM)看当前任务是否可以创建一个新任务。
58行:为进程分配物理页面。其中调用 (alloc_task_struct,alloc_thread_info再调用__get_free_pages申请物理页面)
63,64行:检查进程资源限制。user指针指向user_struct 结构体,一共用户通常有多个进程,共享一个结构体。rlim指向资源限制结构体。



97行:复制flags, CLONE_IDLETASK代表0号进程。如果不是0号进程,申请pid。
101行:pid循环使用,使用pid位图来管理。默认pid最大值是32767,在64位系统中,用户可以通过写/proc/sys/kernel/pid_max文件,扩展到4194303。
142行:LSM Linux安全模块(后续学习)
145行:复制IPC信息。通过get_undo_list申请IPC结构体内存空间(是一个链表,并将链表放入undo_list中,将支持ipc的进程链接到一起。不支持ipc则设置为NULL.)

147行:复制已打开文件的控制结构,只有在CLONE_FILES标记位为0时才进行,否则共享父进程的结构。共享和复制的区别在于,如果是共享,子进程对文件操作会影响到父进程(比如lseek())。
149行:复制进程目录,权限等信息。(与copy_files() 类似)
151,153行:复制信号相关的数据。
155行:复制内存相关的数据。(内存相关的比较复杂,后续需要深究。)
157行:复制命名空间。(参考:https://cloud.tencent.com/developer/article/2129136)
159行:拷贝进程堆栈。
163,167行:set_child_tid 指向子进程的pid.当新进程执行时,将该进程pid。

178行:parent_exec_id 是父进程的执行域, self_exec_id 是本进程的执行域。
181,182行:exit_signal 是当前进程退出时向父进程发出的信号,pdeath_signal是父进程退出时,向子进程发出的信号。
190,196行:time_slice 是时间片。将当前进程的时间片分成两份,一份给当前进程,一份给子进程。
197行:获取进程时间戳。
217-220行:将进程链接到一起,加入到进程队列中。
235-239行:设置父进程,考虑到被调试的情况,需要parent 和 real_parent。
270行:将子进程的task_struct 链入到内核的进程队列中。
274-282行:处理进程关系(还没搞清楚)
 

来源:https://www.cnblogs.com/atest/p/17941382
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具