Linux系統(tǒng)創(chuàng)建一個新進程(下)

瀏覽創(chuàng)建進程的相關(guān)關(guān)鍵代碼

看一下do_fork????? /linux-3.18.6/kernel/fork.c#do_fork

1651	p = copy_process(clone_flags, stack_start, stack_size,      // 創(chuàng)建進程的主要代碼
1652			 child_tidptr, NULL, trace);

看一下copye_process????? /linux-3.18.6/kernel/fork.c#copy_process

1240	p = dup_task_struct(current);      // 復制PCB

看一下dup_task_struct????? /linux-3.18.6/kernel/fork.c#dup_task_struct

320	err = arch_dup_task_struct(tsk, orig);      // 執(zhí)行復制双抽,orig 當前進程
316	ti = alloc_thread_info_node(tsk, node);      // 實際就是alloc一個內(nèi)核堆棧

324 tsk->stack = ti; // 把alloc后返回的地址賦給stack

看一下arch_dup_task_struct???? /linux-3.18.6/kernel/fork.c#arch_dup_task_struct

290int __weak arch_dup_task_struct(struct task_struct *dst,
291					       struct task_struct *src)
292{
293	*dst = *src;      // 就是把數(shù)據(jù)結(jié)構(gòu)加*,原來它是數(shù)據(jù)結(jié)構(gòu)的指針八堡,加*夺姑,表示它的值
294	return 0;
295}

看一下alloc_thread_info_node???? /linux-3.18.6/kernel/fork.c#alloc_thread_info_node

150static struct thread_info *alloc_thread_info_node(struct task_struct *tsk,
151						  int node)
152{
153	struct page *page = alloc_kmem_pages_node(node, THREADINFO_GFP,
154						  THREAD_SIZE_ORDER);
155
156	return page ? page_address(page) : NULL;
157}

做了實際分配內(nèi)核堆棿冈辏空間的效果涯呻,實際的代碼是alloc_kmem_pages_node,創(chuàng)建了一定大小的頁面面徽,頁面有一部分用來存放thread_info蟆技,另一部分從高地址向低地址就是內(nèi)核堆棧

回到dup_task_struct,現(xiàn)在已經(jīng)把父進程的PCB斗忌,也就是task_struct數(shù)據(jù)結(jié)構(gòu)復制過來了,也就是由p所指向的子進程的PCB(進程描述符)

1240	p = dup_task_struct(current);      // 復制PCB

往后的代碼旺聚,有大量地修改子進程內(nèi)容的代碼织阳,做初始化,這些都可以抽象掉

1375	retval = copy_files(clone_flags, p);

1378	retval = copy_fs(clone_flags, p);      // 初始化文件系統(tǒng)

1381	retval = copy_sighand(clone_flags, p);

1384	retval = copy_signal(clone_flags, p);      // 初始化信號

1387	retval = copy_mm(clone_flags, p);      // 初始化內(nèi)存

1390	retval = copy_namespaces(clone_flags, p);

1393	retval = copy_io(clone_flags, p);      // 初始化IO

1396 retval = copy_thread(clone_flags, stack_start, stack_size, p); // 關(guān)鍵的內(nèi)容

看一下copy_thread??? /linux-3.18.6/arch/x86/kernel/process_32.c#132

135	struct pt_regs *childregs = task_pt_regs(p);

從這里可以看到砰粹,從子進程的pid唧躲,也就是內(nèi)核堆棧的位置,找到了椉盍В空間弄痹,SAVE_ALL的一些內(nèi)容,SAVE_ALL的地址

139	p->thread.sp = (unsigned long) childregs;      // 調(diào)度到子進程時的內(nèi)核棧底

把棧底賦上

拷貝內(nèi)核堆棧數(shù)據(jù)和指定新進程的第一條指令地址

159	*childregs = *current_pt_regs();      // 復制內(nèi)核堆棧

當前進程嵌器,也就是父進程肛真,因為我們這個執(zhí)行過程還在父進程的執(zhí)行上下文當中。父進程的內(nèi)核堆棧的棧底爽航,也就是SAVE_ALL的內(nèi)容蚓让,把它拷貝過來,這個地方實際就是做內(nèi)核堆棧里已有數(shù)據(jù)的拷貝

值得注意的是:在復制內(nèi)核堆棧的時候讥珍,只復制了與SAVE_ALL相關(guān)的那一部分历极,只復制了struct pt_regs

看一下struct pt_regs數(shù)據(jù)結(jié)構(gòu)的內(nèi)容??? /linux-3.18.6/arch/x86/include/asm/ptrace.h

9#ifdef __i386__
10
11struct pt_regs {

// SAVE_ALL壓到內(nèi)核堆棧里的內(nèi)容
12 unsigned long bx; 13 unsigned long cx; 14 unsigned long dx; 15 unsigned long si; 16 unsigned long di; 17 unsigned long bp; 18 unsigned long ax; // 傳遞的系統(tǒng)調(diào)用號 19 unsigned long ds; 20 unsigned long es; 21 unsigned long fs; 22 unsigned long gs; 23 unsigned long orig_ax; // 原來的eax
// 執(zhí)行int 0x80指令的時候,CPU自動壓到內(nèi)核堆棧里面的內(nèi)容
24 unsigned long ip; 25 unsigned long cs; 26 unsigned long flags; 27 unsigned long sp; 28 unsigned long ss; 29}; 30 31#else /* __i386__ */

在復制內(nèi)核堆棧的時候衷佃,i386只復制了內(nèi)核堆棧最棧底的那一部分內(nèi)容趟卸,也就是系統(tǒng)調(diào)用壓棧的過程,int 0x80指令(CPU自動)和SAVE_ALL壓到內(nèi)核堆棧里的內(nèi)容

160	childregs->ax = 0;      // 為什么子進程的fork返回0,這里就是原因锄列!

返回值存放在eax图云,pid=0就是在這賦值的。因為子進程的返回值是0右蕊,所以拷貝完還需要修改一下內(nèi)核堆棧里壓入的返回值

161	if (sp)
162		childregs->sp = sp;      // sp是傳遞給copy_thread的第二個參數(shù)stack_start

包括棧底的數(shù)據(jù)

164	p->thread.ip = (unsigned long) ret_from_fork;      // 調(diào)度到子進程時的第一條指令地址

賦值thread.ip的內(nèi)容為ret_from_fork琼稻,子進程得到進程調(diào)度,得到CPU的時候饶囚,是從這個位置開始執(zhí)行的

看一下entry_32.S ?? /linux-3.18.6/arch/x86/kernel/entry_32.S

系統(tǒng)調(diào)用總控程序帕翻,找到ret_from_fork

290ENTRY(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		// 在這里會跳轉(zhuǎn)到syscall_exit
299	CFI_ENDPROC
300END(ret_from_fork)

syscall_exit 在哪個地方呢?

490ENTRY(system_call)

493	pushl_cfi %eax			# save orig_eax
494	SAVE_ALL			// 這里進行SAVE_ALL

501syscall_call:			// 這里進行system_call
502	call *sys_call_table(,%eax,4)
503syscall_after_call: // 這里call返回了萝风,返回到內(nèi)核堆棧 // 也就是內(nèi)核堆棧怎么壓棧嘀掸,它就又怎么出來了
504 movl %eax,PT_EAX(%esp) # store the return value 505syscall_exit:

call返回,返回到內(nèi)核堆棧规惰,也就是內(nèi)核堆棧怎么壓棧睬塌,它就又怎么出來了,所以到syscall_exit的時候歇万,實際上和sys_call之前它的堆棧狀態(tài)是一樣的

所以ret_from_fork跳到syscall_exit來揩晴,就可以繼續(xù)往下執(zhí)行,就可以正常地返回到用戶態(tài)

也就是說當子進程獲得CPU控制權(quán)贪磺,開始運行的時候硫兰,它的ret_from_fork可以把后面的堆棧出棧出棧,從iret返回到用戶態(tài)寒锚,這時候返回到用戶態(tài)劫映,就不是原來父進程的進程空間了,而是子進程的進程空間了


(下篇完)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末刹前,一起剝皮案震驚了整個濱河市泳赋,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌喇喉,老刑警劉巖祖今,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異轧飞,居然都是意外死亡衅鹿,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門过咬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來大渤,“玉大人,你說我怎么就攤上這事掸绞”萌” “怎么了耕捞?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長烫幕。 經(jīng)常有香客問我俺抽,道長,這世上最難降的妖魔是什么较曼? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任磷斧,我火速辦了婚禮,結(jié)果婚禮上捷犹,老公的妹妹穿的比我還像新娘弛饭。我一直安慰自己,他們只是感情好萍歉,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布侣颂。 她就那樣靜靜地躺著,像睡著了一般枪孩。 火紅的嫁衣襯著肌膚如雪憔晒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天蔑舞,我揣著相機與錄音拒担,去河邊找鬼。 笑死攻询,一個胖子當著我的面吹牛澎蛛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蜕窿,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼呆馁,長吁一口氣:“原來是場噩夢啊……” “哼桐经!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起浙滤,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤阴挣,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后纺腊,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體畔咧,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年揖膜,在試婚紗的時候發(fā)現(xiàn)自己被綠了誓沸。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡壹粟,死狀恐怖拜隧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤洪添,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布垦页,位于F島的核電站,受9級特大地震影響干奢,放射性物質(zhì)發(fā)生泄漏痊焊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一忿峻、第九天 我趴在偏房一處隱蔽的房頂上張望薄啥。 院中可真熱鬧,春花似錦炭菌、人聲如沸罪佳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赘艳。三九已至,卻和暖如春克握,著一層夾襖步出監(jiān)牢的瞬間蕾管,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工菩暗, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留掰曾,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓停团,卻偏偏與公主長得像旷坦,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子佑稠,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

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