Linux創(chuàng)建進程的坎坷之路

需要打上這么多斷點辨嗽,do_fork世落、copy_process、sys_clone糟需、copy_thread屉佳、dup_task_struct等。

  • 在執(zhí)行fork之后洲押,可以發(fā)現(xiàn)武花,停在了syd_clone處,顯然是因為前面的#ifdef CONFIG_CLONE_BACKWARDS生效了诅诱。
  • 當然髓堪,實際執(zhí)行的還是do_fork
  • 因為我們關注的是進程的創(chuàng)建,這其中比較關鍵的一個地方是copy_process娘荡,那么就跟蹤進去看看究竟如何干旁。
    前面進行了一大堆的參數(shù)檢查,直到dup_task_struct

跟蹤dup_task_struct進去看

  • alloc_task_struct_node開辟進程內(nèi)存炮沐,如果開辟成功争群,則繼續(xù)向下進行,否則直接返回空(這個有些像我們用的malloc函數(shù))大年。
  • alloc_thread_info_node為thread分配內(nèi)存
  • 關鍵的一步又來了换薄,arch_dup_task_struct玉雾,最主要的工作是*dst = *src;
  • 接下來setup_thread_stack設置thread_stack
  • 略過我們不關心的這些步驟辣苏,接著執(zhí)行返回創(chuàng)建好的task_struct(p)到copy_process晚胡,做好參數(shù)判斷之后函似,
  • 接下來的很長的一段代碼都是根據(jù)特定的環(huán)境設置剛剛我們復制出來的task_struct(p)仔沿,有關于跟蹤調(diào)試的档玻,有關于中斷的译荞。背犯。脆烟。

  • copy_files凡恍、copy_fs志秃、copy_mm、copy_signial等等嚼酝,這種種拷貝表明浮还,子進程和父進程的很多東西是一樣的。
    當運行到copy_thread的時候闽巩,系統(tǒng)停了下來钧舌。可以看到又官,該函數(shù)對p的sp以及sp0進行設置延刘。對cpu的其他一些寄存器進行設置。

  • copy_thread中有下面一片代碼六敬,其中碘赖,p->thread.ip = (unsigned long) ret_from_kernel_thread;這也是很關鍵的一句,可能是從父進程返回外构?
    下面的unlikely只是為了編譯器優(yōu)化(表明if的語句塊執(zhí)行的可能性衅张荨),將后面這段二進制代碼不放在前面的代碼之后审编。之所以會有這樣的優(yōu)化是因為撼班,系統(tǒng)啟動的時候,do_fork就會被調(diào)用垒酬,自認會有從kernel_thread返回的時候砰嘁,但是這也僅限于系統(tǒng)剛啟動,為了以后在創(chuàng)建新進程時候的執(zhí)行速度能夠加快勘究,在系統(tǒng)剛剛啟動的時候有一些性能損失沒什么矮湘。
143         if (unlikely(p->flags & PF_KTHREAD)) {
144                 /* kernel thread */
145                 memset(childregs, 0, sizeof(struct pt_regs));
146                 p->thread.ip = (unsigned long) ret_from_kernel_thread;
147                 task_user_gs(p) = __KERNEL_STACK_CANARY;
148                 childregs->ds = __USER_DS;
149                 childregs->es = __USER_DS;
150                 childregs->fs = __KERNEL_PERCPU;
151                 childregs->bx = sp;     /* function */
152                 childregs->bp = arg;
153                 childregs->orig_ax = -1;
154                 childregs->cs = __KERNEL_CS | get_kernel_rpl();
155                 childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_FIXED;
156                 p->thread.io_bitmap_ptr = NULL;
157                 return 0;
158         }

當然,如果上述語句塊未執(zhí)行到口糕,那么會執(zhí)行下面的:

159         *childregs = *current_pt_regs();
160         childregs->ax = 0;
161         if (sp)
162                 childregs->sp = sp;
163 
164         p->thread.ip = (unsigned long) ret_from_fork;
165         task_user_gs(p) = get_user_gs(current_pt_regs());

最后是設置子進程的返回值為0缅阳,thread的ip為ret_from_fork,這也就是我們子進程返回的執(zhí)行點景描。
process_32.c中有如下定義十办,顯然是嵌入式匯編秀撇,入口在entry_32.S中。

 58 asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
 59 asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread");
  • entry_32.S中有這樣的東東:
290 ENTRY(ret_from_fork)
291         CFI_STARTPROC
292         pushl_cfi %eax
293         call schedule_tail
294         GET_THREAD_INFO(%ebp)
295         popl_cfi %eax
296         pushl_cfi $0x0202               # Reset kernel eflags
297         popfl_cfi
298         jmp syscall_exit
299         CFI_ENDPROC
300 END(ret_from_fork)
301 
302 ENTRY(ret_from_kernel_thread)
303         CFI_STARTPROC
304         pushl_cfi %eax
305         call schedule_tail
306         GET_THREAD_INFO(%ebp)
307         popl_cfi %eax
308         pushl_cfi $0x0202               # Reset kernel eflags
309         popfl_cfi
310         movl PT_EBP(%esp),%eax
311         call *PT_EBX(%esp)
312         movl $0,PT_EAX(%esp)
313         jmp syscall_exit
314         CFI_ENDPROC
315 ENDPROC(ret_from_kernel_thread)
  • schedule_tail的實現(xiàn)向族,具體原理暫不深究
2305 /**
2306  * schedule_tail - first thing a freshly forked thread must call.
2307  * @prev: the thread we just switched away from.
2308  */
2309 asmlinkage __visible void schedule_tail(struct task_struct *prev)
2310         __releases(rq->lock)
2311 {
2312         struct rq *rq = this_rq();
2313 
2314         finish_task_switch(rq, prev);
2315 
2316         /*
2317          * FIXME: do we need to worry about rq being invalidated by the
2318          * task_switch?
2319          */
2320         post_schedule(rq);
2321 
2322         if (current->set_child_tid)
2323                 put_user(task_pid_vnr(current), current->set_child_tid);
2324 }
  • copy_process之后呵燕,如果沒有錯誤,那么wake_up_new_task將會第一次喚醒新創(chuàng)建的任務(也就是做一些調(diào)度統(tǒng)計管理炸枣,然后將這個任務放到運行隊列中)虏等,如下面代碼弄唧。顯然适肠,當子進程獲得cpu的使用權之后,系統(tǒng)就會從ret_from_fork處返回執(zhí)行候引。
    這里面有很多奇怪的編譯器指令或者是宏侯养,待有時間再深究。
1657         if (!IS_ERR(p)) {
1658                 struct completion vfork;
1659                 struct pid *pid;
1660 
1661                 trace_sched_process_fork(current, p);
1662 
1663                 pid = get_task_pid(p, PIDTYPE_PID);
1664                 nr = pid_vnr(pid);
1665 
1666                 if (clone_flags & CLONE_PARENT_SETTID)
1667                         put_user(nr, parent_tidptr);
1668 
1669                 if (clone_flags & CLONE_VFORK) {
1670                         p->vfork_done = &vfork;
1671                         init_completion(&vfork);
1672                         get_task_struct(p);
1673                 }
1674 
1675                 wake_up_new_task(p);
1676 
1677                 /* forking complete and child started to run, tell ptracer */
1678                 if (unlikely(trace))
1679                         ptrace_event_pid(trace, pid);
1680 
1681                 if (clone_flags & CLONE_VFORK) {
1682                         if (!wait_for_vfork_done(p, &vfork))
1683                                 ptrace_event_pid(PTRACE_EVENT_VFORK_DONE, pid);
1684                 }
1685 
1686                 put_pid(pid);
1687         } else {
1688                 nr = PTR_ERR(p);
1689         }
1690         return nr;
  • 很明顯nr = pid_vnr(pid);這一語句獲取了進程的pid澄干,在do_fork的最后返回逛揩。

  • 很顯然,當do_fork返回之后麸俘,一切戛然而止辩稽,返回的nr就是子進程的pid,內(nèi)核通過這種方式來區(qū)分父子進程从媚,真是奇妙逞泄。

  • 其實在fork系統(tǒng)調(diào)用的執(zhí)行過程中,你會發(fā)現(xiàn)拜效,究竟是子進程先返回還是父進程先返回喷众,這是不一定的。作為程序員也不能假定返回的時刻紧憾。如果設置好子進程的一切(我理解是wake_up_new_task(p);執(zhí)行完成)到千,調(diào)度點發(fā)生在do_fork返回之前,那么子進程先返回赴穗;如果是do_fork返回之后憔四,調(diào)度點才到,父進程先返回般眉,奇妙的很了赵。

  • 至于子進程的返回過程,分析如下:

  • 在copy_process中煤篙,乃至其中的copy_thread都對子進程的各種狀態(tài)信息做了充分的設置斟览。我們關注ip以及eax的保存。

  • 調(diào)度點到了之后辑奈,系統(tǒng)會恢復eax為0苛茂,將ip恢復為ret_from_fork已烤,首先保存eax,然后做一些必要的準備工作妓羊,重置內(nèi)核eflags胯究,最后跳轉(zhuǎn)到syscall_exit,

你看躁绸,這樣裕循,這樣,然后再這樣净刮,Linux就把進程創(chuàng)建出來了剥哑。

那么問題來了,為什么子進程的syscall_exit之后淹父,就能返回到fork的下面一句代碼執(zhí)行呢株婴?

思考中。暑认。困介。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蘸际,隨后出現(xiàn)的幾起案子座哩,更是在濱河造成了極大的恐慌,老刑警劉巖粮彤,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件根穷,死亡現(xiàn)場離奇詭異,居然都是意外死亡驾诈,警方通過查閱死者的電腦和手機缠诅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來乍迄,“玉大人管引,你說我怎么就攤上這事〈沉剑” “怎么了褥伴?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長漾狼。 經(jīng)常有香客問我重慢,道長,這世上最難降的妖魔是什么逊躁? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任似踱,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘核芽。我一直安慰自己囚戚,他們只是感情好,可當我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布轧简。 她就那樣靜靜地躺著驰坊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪哮独。 梳的紋絲不亂的頭發(fā)上拳芙,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天,我揣著相機與錄音皮璧,去河邊找鬼舟扎。 笑死,一個胖子當著我的面吹牛恶导,可吹牛的內(nèi)容都是我干的浆竭。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼惨寿,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了删窒?” 一聲冷哼從身側(cè)響起裂垦,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎肌索,沒想到半個月后蕉拢,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡诚亚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年晕换,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片站宗。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡闸准,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出梢灭,到底是詐尸還是另有隱情夷家,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布敏释,位于F島的核電站库快,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏钥顽。R本人自食惡果不足惜义屏,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧闽铐,春花似錦膀曾、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至察迟,卻和暖如春斩狱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背扎瓶。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工所踊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人概荷。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓秕岛,卻偏偏與公主長得像,于是被迫代替她去往敵國和親误证。 傳聞我的和親對象是個殘疾皇子继薛,可洞房花燭夜當晚...
    茶點故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容

  • 進程的描述 進程控制塊PCB -- task_struct 操作系統(tǒng)的三大核心功能:1、進程管理2愈捅、內(nèi)存管理3遏考、文...
    _Iridescent閱讀 1,995評論 0 1
  • 此文僅用于MOOCLinux內(nèi)核分析作業(yè)張依依+原創(chuàng)作品轉(zhuǎn)載請注明出處+《Linux內(nèi)核分析》MOOC課程http...
    uglyyouth閱讀 2,271評論 0 4
  • 安大大 + 原創(chuàng)作品轉(zhuǎn)載請注明出處 + 《Linux操作系統(tǒng)分析》MOOC課程 進程控制塊PCB——task_st...
    夏天的籃球閱讀 949評論 0 1
  • 又來到了一個老生常談的問題,應用層軟件開發(fā)的程序員要不要了解和深入學習操作系統(tǒng)呢蓝谨? 今天就這個問題開始灌具,來談談操...
    tangsl閱讀 4,104評論 0 23
  • 今天被自己蠢死啦~ 本來約著阿楚周末一起看我的少女時代,結(jié)果買錯票譬巫。還不能退咖楣。應該是明天上午四節(jié)課,后天上午考試芦昔。...
    葛瑞斯閱讀 135評論 0 0