本系列文章由張同浩編寫,轉載請註明出處:http://blog.csdn.net/muge0913/article/details/7479451
在上次的文章中詳細的介紹了幾個系統調用,它們最終都是調用了do_fork來實現進程的創建。do_fork主要完成了進程描述符的創建和pid的創建,以及進程描述符的拷貝。
本系列文章所用源碼均來自2.6.38.
源碼分析如下:
- /*
- * Ok, this is the main fork-routine.
- *
- * It copies the process, and if successful kick-starts
- * it and waits for it to finish using the VM if required.
- */
- /*這部分代碼是在2.6.38中實現的*/
- /*參數clone_flags由兩部分組成,最低的一個字節爲信號掩碼,用於指定子進程退出時
- *子進程向父進程發出的信號,通過sys_fork和sys_vfork知道它們的信號就是SIGCHLD,而
- *clone由用戶自己決定。對於第二部分表示資源和特性標誌位,fork爲0,vfork爲CLONE_VFORK和CLONE_VM
- *而clone由用戶自己定義。
- */
- long do_fork(unsigned long clone_flags,
- unsigned long stack_start,
- struct pt_regs *regs,
- unsigned long stack_size,
- int __user *parent_tidptr,
- int __user *child_tidptr)
- {
- /*定義一個進程描述符*/
- struct task_struct *p;
- int trace = 0;
- long nr;//子進程號
- /*
- * Do some preliminary argument and permissions checking before we
- * actually start allocating stuff
- */
- /*
- *一些必要的檢查工作,我們會發現在sys_fork,sys_vfork,kernel_thread中都沒有傳遞CLONE_NEWUSER可見
- *以下這些代碼沒有執行,這個檢查主要是爲sys_clone使用的。
- */
- if (clone_flags & CLONE_NEWUSER) {
- if (clone_flags & CLONE_THREAD)//跟蹤標誌被設置,出錯。
- return -EINVAL;
- /* hopefully this check will go away when userns support is
- * complete
- */
- if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SETUID) ||
- !capable(CAP_SETGID))
- return -EPERM;
- }
- /*
- * We hope to recycle these flags after 2.6.26
- */
- /*這些代碼也是就一些檢查工作*/
- if (unlikely(clone_flags & CLONE_STOPPED)) {
- static int __read_mostly count = 100;
- if (count > 0 && printk_ratelimit()) {
- char comm[TASK_COMM_LEN];
- count--;
- printk(KERN_INFO "fork(): process `%s' used deprecated "
- "clone flags 0x%lx\n",
- get_task_comm(comm, current),
- clone_flags & CLONE_STOPPED);
- }
- }
- /*
- * When called from kernel_thread, don't do user tracing stuff.
- */
- if (likely(user_mode(regs)))
- trace = tracehook_prepare_clone(clone_flags);
- /*copy_process來完成具體進程的創建,在系統資源豐富的條件下,來完成進程描述符的拷貝,當然進程號不同*/
- p = copy_process(clone_flags, stack_start, regs, stack_size,
- child_tidptr, NULL, trace);
- /*
- *調用完copy_process後如果沒有指定CLONE_STOPPED就會調用下面的wake_up_new_task把新建的進程放到
- *運行隊列中。如果父子進程在同一個cpu中運行,且在沒有設置CLONE_VM標誌,則會採用寫實複製技術,把子進程放到
- *父進程的前面,如果子進程調用了exec就會避免一系列不必要的複製操作。
- */
- /*
- * Do this prior waking up the new thread - the thread pointer
- * might get invalid after that point, if the thread exits quickly.
- */
- /*IS_ERR()判斷p是否正確*/
- if (!IS_ERR(p)) {
- /*進程描述符創建成功後,根據clone_flags來設置進程狀態*/
- struct completion vfork;
- trace_sched_process_fork(current, p);
- nr = task_pid_vnr(p);
- /*
- *在sys_fork,sys_vfork,kernel_thread中沒有CLONE_PARENT_SETTID且parent_tidptr=NULL
- *爲sys_clone使用
- */
- if (clone_flags & CLONE_PARENT_SETTID)
- put_user(nr, parent_tidptr);
- /*
- *sys_fork 或 sys_clone檢查的,如果設置了就把父進程放進等待隊列中
- */
- if (clone_flags & CLONE_VFORK) {
- p->vfork_done = &vfork;
- init_completion(&vfork);
- }
- audit_finish_fork(p);
- tracehook_report_clone(regs, clone_flags, nr, p);
- /*
- * We set PF_STARTING at creation in case tracing wants to
- * use this to distinguish a fully live task from one that
- * hasn't gotten to tracehook_report_clone() yet. Now we
- * clear it and set the child going.
- */
- p->flags &= ~PF_STARTING;
- if (unlikely(clone_flags & CLONE_STOPPED)) {
- /*
- * We'll start up with an immediate SIGSTOP.
- */
- sigaddset(&p->pending.signal, SIGSTOP);
- set_tsk_thread_flag(p, TIF_SIGPENDING);
- __set_task_state(p, TASK_STOPPED);
- } else {
- wake_up_new_task(p, clone_flags);
- }
- tracehook_report_clone_complete(trace, regs,
- clone_flags, nr, p);
- if (clone_flags & CLONE_VFORK) {
- freezer_do_not_count();
- wait_for_completion(&vfork);//等待隊列
- freezer_count();
- tracehook_report_vfork_done(p, nr);
- }
- } else {
- nr = PTR_ERR(p);
- }
- return nr;
- }