操作系統(tǒng) Lab5 用戶進(jìn)程管理 實(shí)驗(yàn)報(bào)告
課程信息所在網(wǎng)址:https://github.com/chyyuu/os_course_info
- 實(shí)驗(yàn)?zāi)康?/a>
- 實(shí)驗(yàn)內(nèi)容
- 基本練習(xí)
- 參考答案分析
- 實(shí)驗(yàn)中涉及的知識(shí)點(diǎn)列舉
- 實(shí)驗(yàn)中未涉及的知識(shí)點(diǎn)列舉
- 參考文獻(xiàn)
實(shí)驗(yàn)?zāi)康?/h2>
- 了解第一個(gè)用戶進(jìn)程創(chuàng)建過程
- 了解系統(tǒng)調(diào)用框架的實(shí)現(xiàn)機(jī)制
- 了解ucore如何實(shí)現(xiàn)系統(tǒng)調(diào)用sys_fork/sys_exec/sys_exit/sys_wait來進(jìn)行進(jìn)程管理
實(shí)驗(yàn)內(nèi)容
- 創(chuàng)建用戶進(jìn)程痴晦,讓用戶進(jìn)程在用戶態(tài)執(zhí)行;
- 支持ucore的系統(tǒng)調(diào)用為用戶進(jìn)程提供服務(wù)虑粥;
- 完成對(duì)用戶進(jìn)程的執(zhí)行過程的基本管理;
基本練習(xí)
練習(xí)0:填寫已有實(shí)驗(yàn)
在本練習(xí)中將LAB1/2/3/4的實(shí)驗(yàn)內(nèi)容移植到了LAB5的實(shí)驗(yàn)框架內(nèi)粱年,由于手動(dòng)進(jìn)行內(nèi)容移植比較煩雜,因此考慮使用diff和patch工具進(jìn)行自動(dòng)化的移植,具體使用的命令如下所示:(對(duì)于patch工具進(jìn)行合并的時(shí)候產(chǎn)生沖突的少部分內(nèi)容漓柑,則使用*.rej, *.orig文件來手動(dòng)解決沖突問題)
diff -r -u -P lab4_origin lab4 > lab4.patch
cd lab5
patch -p1 -u < ../lab4.patch
練習(xí)1:加載應(yīng)用程序并執(zhí)行(需要編碼)
do_execv函數(shù)調(diào)用load_icode(位于kern/process/proc.c中)來加載并解析一個(gè)處于內(nèi)存中的ELF執(zhí)行文件格式的應(yīng)用程序湖蜕,建立相應(yīng)的用戶內(nèi)存空間來放置應(yīng)用程序的代碼段逻卖、數(shù)據(jù)段 等,且要設(shè)置好proc_struct結(jié)構(gòu)中的成員變量trapframe中的內(nèi)容昭抒,確保在執(zhí)行此進(jìn)程后评也,能 夠從應(yīng)用程序設(shè)定的起始執(zhí)行地址開始執(zhí)行。需設(shè)置正確的trapframe內(nèi)容灭返。
設(shè)計(jì)實(shí)現(xiàn)
完成本練習(xí)的具體設(shè)計(jì)實(shí)現(xiàn)如下:
- 為了完成本實(shí)驗(yàn)中的編碼工作盗迟,首先需要對(duì)先前的lab的一些代碼進(jìn)行更新,進(jìn)行了更新的內(nèi)容分別如下所示:
- 在初始化IDT的時(shí)候婆殿,設(shè)置系統(tǒng)調(diào)用對(duì)應(yīng)的中斷描述符诈乒,使其能夠在用戶態(tài)下被調(diào)用,并且設(shè)置為trap類型婆芦。(事實(shí)上這個(gè)部分已經(jīng)在LAB1的實(shí)驗(yàn)中順手被完成了)
- 在時(shí)鐘中斷的處理部分怕磨,每過TICK_NUM個(gè)中斷,就將當(dāng)前的進(jìn)程設(shè)置為可以被重新調(diào)度的消约,這樣使得當(dāng)前的線程可以被換出肠鲫,從而實(shí)現(xiàn)多個(gè)線程的并發(fā)執(zhí)行;
- 在proc_alloc函數(shù)中或粮,額外對(duì)進(jìn)程控制塊中新增加的wait_state, cptr, yptr, optr成員變量進(jìn)行初始化导饲;
- 在do_fork函數(shù)中,使用set_links函數(shù)來完成將fork的線程添加到線程鏈表中的過程,值得注意的是渣锦,該函數(shù)中就包括了對(duì)進(jìn)程總數(shù)加1這一操作硝岗,因此需要將原先的這個(gè)操作給刪除掉;
- 在完成了對(duì)先前的LAB代碼的更新之后袋毙,考慮完成本LAB中的編碼工作型檀;通過對(duì)代碼的分析可以發(fā)現(xiàn),本練習(xí)中需要完成的編碼工作集中在load_icode函數(shù)中听盖,這個(gè)函數(shù)是由do_execve函數(shù)調(diào)用的胀溺,而該函數(shù)是exec系統(tǒng)調(diào)用的最終處理的函數(shù),功能為將某一個(gè)指定的ELF可執(zhí)行二進(jìn)制文件加載到當(dāng)前內(nèi)存中來皆看,然后將當(dāng)前進(jìn)程就執(zhí)行該文件(先前執(zhí)行的內(nèi)容全部清空)仓坞,而load_icode函數(shù)的功能則在于為執(zhí)行新的程序初始化好內(nèi)存空間,在調(diào)用該函數(shù)之前腰吟,do_execve中已經(jīng)退出了當(dāng)前進(jìn)程的內(nèi)存空間无埃,改使用了內(nèi)核的內(nèi)存空間,這樣使得對(duì)原先用戶態(tài)的內(nèi)存空間的操作成為可能蝎困;接下來不妨對(duì)load_icode函數(shù)進(jìn)行分析:
- 該函數(shù)的功能主要分為6個(gè)部分录语,而我們需要填寫的是第6個(gè)部分,就是偽造中斷返回現(xiàn)場(chǎng)禾乘,使得系統(tǒng)調(diào)用返回之后可以正確跳轉(zhuǎn)到需要運(yùn)行的程序入口澎埠,并正常運(yùn)行;而1-5部分則是一系列對(duì)用戶內(nèi)存空間的初始化始藕,這部分將在LAB8的編碼實(shí)現(xiàn)中具體體現(xiàn)蒲稳,因此在本LAB中暫時(shí)不加具體說明;與LAB1的challenge類似的伍派,第6個(gè)部分是在進(jìn)行中斷處理的棧(此時(shí)應(yīng)當(dāng)是內(nèi)核棧)上偽造一個(gè)中斷返回現(xiàn)場(chǎng)江耀,使得中斷返回的時(shí)候可以正確地切換到需要的執(zhí)行程序入口處;在這個(gè)部分中需要對(duì)tf進(jìn)行設(shè)置诉植,不妨通過代碼分析來確定這個(gè)tf變量究竟指到什么位置祥国,該tf變量與current->tf的數(shù)值一致,而current->tf是在進(jìn)行中斷服務(wù)里程的trap函數(shù)中被設(shè)置為當(dāng)前中斷的中斷幀晾腔,也就是說這個(gè)tf最終指向了當(dāng)前系統(tǒng)調(diào)用exec產(chǎn)生的中斷幀處舌稀;
- 完成了上述分析,可以具體確定應(yīng)當(dāng)怎么初始化tf中的變量了:
- 由于最終是在用戶態(tài)下運(yùn)行的灼擂,所以需要將段寄存器初始化為用戶態(tài)的代碼段壁查、數(shù)據(jù)段、堆棧段剔应;
- esp應(yīng)當(dāng)指向先前的步驟中創(chuàng)建的用戶棧的棧頂睡腿;
- eip應(yīng)當(dāng)指向ELF可執(zhí)行文件加載到內(nèi)存之后的入口處语御;
- eflags中應(yīng)當(dāng)初始化為中斷使能,注意eflags的第1位是恒為1的席怪;
- 設(shè)置ret為0应闯,表示正常返回;
- 最終具體的代碼實(shí)現(xiàn)如下所示:
tf->tf_cs = USER_CS; tf->tf_ds = tf->tf_es = tf->tf_ss = USER_DS; tf->tf_esp = USTACKTOP; tf->tf_eip = elf->e_entry; tf->tf_eflags = 0x00000002 | FL_IF; // to enable interrupt ret = 0;
- 至此完成了本練習(xí)中的所有編碼工作何恶;
問題回答
請(qǐng)?jiān)趯?shí)驗(yàn)報(bào)告中描述當(dāng)創(chuàng)建一個(gè)用戶態(tài)進(jìn)程并加載了應(yīng)用程序后孽锥,CPU是如何讓這個(gè)應(yīng)用程 序最終在用戶態(tài)執(zhí)行起來的嚼黔。即這個(gè)用戶態(tài)進(jìn)程被ucore選擇占用CPU執(zhí)行(RUNNING態(tài)) 到具體執(zhí)行應(yīng)用程序第一條指令的整個(gè)經(jīng)過细层。
- 分析在創(chuàng)建了用戶態(tài)進(jìn)程并且加載了應(yīng)用程序之后,其占用CPU執(zhí)行到具體執(zhí)行應(yīng)用程序的整個(gè)經(jīng)過:
- 在經(jīng)過調(diào)度器占用了CPU的資源之后唬涧,用戶態(tài)進(jìn)程調(diào)用了exec系統(tǒng)調(diào)用疫赎,從而轉(zhuǎn)入到了系統(tǒng)調(diào)用的處理例程;
- 在經(jīng)過了正常的中斷處理例程之后碎节,最終控制權(quán)轉(zhuǎn)移到了syscall.c中的syscall函數(shù)捧搞,然后根據(jù)系統(tǒng)調(diào)用號(hào)轉(zhuǎn)移給了sys_exec函數(shù),在該函數(shù)中調(diào)用了上文中提及的do_execve函數(shù)來完成指定應(yīng)用程序的加載狮荔;
- 在do_execve中進(jìn)行了若干設(shè)置胎撇,包括推出當(dāng)前進(jìn)程的頁(yè)表,換用kernel的PDT之后殖氏,使用load_icode函數(shù)晚树,完成了對(duì)整個(gè)用戶線程內(nèi)存空間的初始化,包括堆棧的設(shè)置以及將ELF可執(zhí)行文件的加載雅采,之后通過current->tf指針修改了當(dāng)前系統(tǒng)調(diào)用的trapframe爵憎,使得最終中斷返回的時(shí)候能夠切換到用戶態(tài),并且同時(shí)可以正確地將控制權(quán)轉(zhuǎn)移到應(yīng)用程序的入口處婚瓜;
- 在完成了do_exec函數(shù)之后宝鼓,進(jìn)行正常的中斷返回的流程,由于中斷處理例程的棧上面的eip已經(jīng)被修改成了應(yīng)用程序的入口處巴刻,而cs上的CPL是用戶態(tài)愚铡,因此iret進(jìn)行中斷返回的時(shí)候會(huì)將堆棧切換到用戶的棧,并且完成特權(quán)級(jí)的切換胡陪,并且跳轉(zhuǎn)到要求的應(yīng)用程序的入口處沥寥;
- 接下來開始具體執(zhí)行應(yīng)用程序的第一條指令;
練習(xí)2:父進(jìn)程復(fù)制自己的內(nèi)存空間給子進(jìn)程(需要編碼)
創(chuàng)建子進(jìn)程的函數(shù)do_fork在執(zhí)行中將拷貝當(dāng)前進(jìn)程(即父進(jìn)程)的用戶內(nèi)存地址空間中的合 法內(nèi)容到新進(jìn)程中(子進(jìn)程)督弓,完成內(nèi)存資源的復(fù)制营曼。具體是通過copy_range函數(shù)(位于 kern/mm/pmm.c中)實(shí)現(xiàn)的,請(qǐng)補(bǔ)充copy_range的實(shí)現(xiàn)愚隧,確保能夠正確執(zhí)行蒂阱。
設(shè)計(jì)實(shí)現(xiàn)
- 為了了解需要完成編碼的函數(shù)的作用锻全,不煩首先分析父進(jìn)程調(diào)用fork系統(tǒng)調(diào)用生成子進(jìn)程的過程:
- 父進(jìn)程調(diào)用fork系統(tǒng)調(diào)用,進(jìn)入正常的中斷處理機(jī)制录煤,最終交由syscall函數(shù)進(jìn)行處理鳄厌;
- 在syscall函數(shù)中,根據(jù)系統(tǒng)調(diào)用好妈踊,交由sys_fork函數(shù)處理了嚎;
- 該函數(shù)進(jìn)一步調(diào)用了do_fork函數(shù),這個(gè)函數(shù)是主要的創(chuàng)建子進(jìn)程廊营、并且將父進(jìn)程的內(nèi)存空間復(fù)制給子進(jìn)程的邏輯所在歪泳;
- 在do_fork函數(shù)中,調(diào)用copy_mm進(jìn)行內(nèi)存空間的復(fù)制露筒,在該函數(shù)中呐伞,進(jìn)一步調(diào)用了dup_mmap,在這個(gè)函數(shù)中慎式,遍歷了父進(jìn)程的所有合法虛擬內(nèi)存空間伶氢,并且將這些空間的內(nèi)容復(fù)制到子進(jìn)程的內(nèi)存空間中去,具體進(jìn)行內(nèi)存復(fù)制的函數(shù)就是我們?cè)诒敬尉毩?xí)中需要完善的copy_range瘪吏;
- 在copy_range函數(shù)中癣防,對(duì)需要復(fù)制的內(nèi)存空間按照頁(yè)為單位從父進(jìn)程的內(nèi)存空間復(fù)制到子進(jìn)程的內(nèi)存空間中去;
- copy_range函數(shù)的具體執(zhí)行流程如下:
- 遍歷父進(jìn)程指定的某一段內(nèi)存空間中的每一個(gè)虛擬頁(yè)掌眠,如果這個(gè)虛擬頁(yè)是存在的話蕾盯,為子進(jìn)程對(duì)應(yīng)的同一個(gè)地址(但是頁(yè)目錄表是不一樣的,因此不是一個(gè)內(nèi)存空間)也申請(qǐng)分配一個(gè)物理頁(yè)扇救,然后將前者中的所有內(nèi)容復(fù)制到后者中去刑枝,然后為子進(jìn)程的這個(gè)物理頁(yè)和對(duì)應(yīng)的虛擬地址(事實(shí)上是線性地址)建立映射關(guān)系;而在本練習(xí)中需要完成的內(nèi)容就是內(nèi)存的復(fù)制和映射的建立迅腔,具體流程如下:
- 找到父進(jìn)程指定的某一物理頁(yè)對(duì)應(yīng)的內(nèi)核虛擬地址装畅;
- 找到需要拷貝過去的子進(jìn)程的對(duì)應(yīng)物理頁(yè)對(duì)應(yīng)的內(nèi)核虛擬地址;
- 將前者的內(nèi)容拷貝到后者中去沧烈;
- 為子進(jìn)程當(dāng)前分配這一物理頁(yè)映射上對(duì)應(yīng)的在子進(jìn)程虛擬地址空間里的一個(gè)虛擬頁(yè)掠兄;
- 具體使用代碼實(shí)現(xiàn)的結(jié)果如下所示:
char *src_kvaddr = page2kva(page); // 找到父進(jìn)程需要復(fù)制的物理頁(yè)在內(nèi)核地址空間中的虛擬地址,這是由于這個(gè)函數(shù)執(zhí)行的時(shí)候使用的時(shí)內(nèi)核的地址空間 char *dst_kvaddr = page2kva(npage); // 找到子進(jìn)程需要被填充的物理頁(yè)的內(nèi)核虛擬地址 memcpy(dst_kvaddr, src_kvaddr, PGSIZE); // 將父進(jìn)程的物理頁(yè)的內(nèi)容復(fù)制到子進(jìn)程中去 page_insert(to, npage, start, perm); // 建立子進(jìn)程的物理頁(yè)與虛擬頁(yè)的映射關(guān)系
- 遍歷父進(jìn)程指定的某一段內(nèi)存空間中的每一個(gè)虛擬頁(yè)掌眠,如果這個(gè)虛擬頁(yè)是存在的話蕾盯,為子進(jìn)程對(duì)應(yīng)的同一個(gè)地址(但是頁(yè)目錄表是不一樣的,因此不是一個(gè)內(nèi)存空間)也申請(qǐng)分配一個(gè)物理頁(yè)扇救,然后將前者中的所有內(nèi)容復(fù)制到后者中去刑枝,然后為子進(jìn)程的這個(gè)物理頁(yè)和對(duì)應(yīng)的虛擬地址(事實(shí)上是線性地址)建立映射關(guān)系;而在本練習(xí)中需要完成的內(nèi)容就是內(nèi)存的復(fù)制和映射的建立迅腔,具體流程如下:
- 至此完成了本聯(lián)系中所有需要的編碼任務(wù)锌雀,從而正確地實(shí)現(xiàn)了操作系統(tǒng)的fork系統(tǒng)調(diào)用的功能;
問題回答
- 請(qǐng)?jiān)趯?shí)驗(yàn)報(bào)告中簡(jiǎn)要說明如何設(shè)計(jì)實(shí)現(xiàn)”Copy on Write 機(jī)制“蚂夕,給出概要設(shè)計(jì),鼓勵(lì)給出詳細(xì)設(shè)計(jì)腋逆。
- 接下來將說明如何實(shí)現(xiàn)“Copy on Write”機(jī)制婿牍,該機(jī)制的主要思想為使得進(jìn)程執(zhí)行fork系統(tǒng)調(diào)用進(jìn)行復(fù)制的時(shí)候,父進(jìn)程不會(huì)簡(jiǎn)單地將整個(gè)內(nèi)存中的內(nèi)容復(fù)制給子進(jìn)程惩歉,而是暫時(shí)共享相同的物理內(nèi)存頁(yè)等脂;而當(dāng)其中一個(gè)進(jìn)程需要對(duì)內(nèi)存進(jìn)行修改的時(shí)候俏蛮,再額外創(chuàng)建一個(gè)自己私有的物理內(nèi)存頁(yè),將共享的內(nèi)容復(fù)制過去上遥,然后在自己的內(nèi)存頁(yè)中進(jìn)行修改搏屑;根據(jù)上述分析,主要對(duì)實(shí)驗(yàn)框架的修改應(yīng)當(dāng)主要有兩個(gè)部分粉楚,一個(gè)部分在于進(jìn)行fork操作的時(shí)候不直接復(fù)制內(nèi)存辣恋,另外一個(gè)處理在于出現(xiàn)了內(nèi)存頁(yè)訪問異常的時(shí)候,會(huì)將共享的內(nèi)存頁(yè)復(fù)制一份模软,然后在新的內(nèi)存頁(yè)進(jìn)行修改伟骨,具體的修改部分如下:
- do fork部分:在進(jìn)行內(nèi)存復(fù)制的部分,比如copy_range函數(shù)內(nèi)部撵摆,不實(shí)際進(jìn)行內(nèi)存的復(fù)制底靠,而是將子進(jìn)程和父進(jìn)程的虛擬頁(yè)映射上同一個(gè)物理頁(yè)面,然后在分別在這兩個(gè)進(jìn)程的虛擬頁(yè)對(duì)應(yīng)的PTE部分將這個(gè)頁(yè)置成是不可寫的特铝,同時(shí)利用PTE中的保留位將這個(gè)頁(yè)設(shè)置成共享的頁(yè)面,這樣的話如果應(yīng)用程序試圖寫某一個(gè)共享頁(yè)就會(huì)產(chǎn)生頁(yè)訪問異常壹瘟,從而可以將控制權(quán)交給操作系統(tǒng)進(jìn)行處理鲫剿;
- page fault部分:在page fault的ISR部分,新增加對(duì)當(dāng)前的異常是否由于嘗試寫了某一個(gè)共享頁(yè)面引起的稻轨,如果是的話灵莲,額外申請(qǐng)分配一個(gè)物理頁(yè)面,然后將當(dāng)前的共享頁(yè)的內(nèi)容復(fù)制過去殴俱,建立出錯(cuò)的線性地址與新創(chuàng)建的物理頁(yè)面的映射關(guān)系政冻,將PTE設(shè)置設(shè)置成非共享的;然后查詢?cè)裙蚕淼奈锢眄?yè)面是否還是由多個(gè)其他進(jìn)程共享使用的线欲,如果不是的話明场,就將對(duì)應(yīng)的虛地址的PTE進(jìn)行修改,刪掉共享標(biāo)記李丰,恢復(fù)寫標(biāo)記苦锨;這樣的話page fault返回之后就可以正常完成對(duì)虛擬內(nèi)存(原想的共享內(nèi)存)的寫操作了;
- 上述實(shí)現(xiàn)有一個(gè)較小的缺陷趴泌,在于在do fork的時(shí)候需要修改所有的PTE舟舒,會(huì)有一定的時(shí)間效率上的損失;可以考慮將共享的標(biāo)記加在PDE上嗜憔,然后一旦訪問了這個(gè)PDE之后再將標(biāo)記下傳給對(duì)應(yīng)的PTE秃励,這樣的話就起到了標(biāo)記延遲和潛在的標(biāo)記合并的左右,有利于提升時(shí)間效率吉捶;
- 接下來將說明如何實(shí)現(xiàn)“Copy on Write”機(jī)制婿牍,該機(jī)制的主要思想為使得進(jìn)程執(zhí)行fork系統(tǒng)調(diào)用進(jìn)行復(fù)制的時(shí)候,父進(jìn)程不會(huì)簡(jiǎn)單地將整個(gè)內(nèi)存中的內(nèi)容復(fù)制給子進(jìn)程惩歉,而是暫時(shí)共享相同的物理內(nèi)存頁(yè)等脂;而當(dāng)其中一個(gè)進(jìn)程需要對(duì)內(nèi)存進(jìn)行修改的時(shí)候俏蛮,再額外創(chuàng)建一個(gè)自己私有的物理內(nèi)存頁(yè),將共享的內(nèi)容復(fù)制過去上遥,然后在自己的內(nèi)存頁(yè)中進(jìn)行修改搏屑;根據(jù)上述分析,主要對(duì)實(shí)驗(yàn)框架的修改應(yīng)當(dāng)主要有兩個(gè)部分粉楚,一個(gè)部分在于進(jìn)行fork操作的時(shí)候不直接復(fù)制內(nèi)存辣恋,另外一個(gè)處理在于出現(xiàn)了內(nèi)存頁(yè)訪問異常的時(shí)候,會(huì)將共享的內(nèi)存頁(yè)復(fù)制一份模软,然后在新的內(nèi)存頁(yè)進(jìn)行修改伟骨,具體的修改部分如下:
練習(xí)3:閱讀分析源代碼夺鲜,理解進(jìn)程執(zhí)行 fork/exec/wait/exit 的實(shí)現(xiàn)廓鞠,以及系統(tǒng)調(diào)用的實(shí)現(xiàn)(不需要編碼)
分析
-
接下來對(duì)fork/exec/wait/exit四個(gè)系統(tǒng)調(diào)用進(jìn)行分析:
- fork:在執(zhí)行了fork系統(tǒng)調(diào)用之后,會(huì)執(zhí)行正常的中斷處理流程谣旁,最終將控制權(quán)轉(zhuǎn)移給syscall床佳,之后根據(jù)系統(tǒng)調(diào)用號(hào)執(zhí)行sys_fork函數(shù),進(jìn)一步執(zhí)行了上文中的do_fork函數(shù)榄审,完成新的進(jìn)程的進(jìn)程控制塊的初始化砌们、設(shè)置、以及將父進(jìn)程內(nèi)存中的內(nèi)容到子進(jìn)程的內(nèi)存的復(fù)制工作搁进,然后將新創(chuàng)建的進(jìn)程放入可執(zhí)行隊(duì)列(runnable)浪感,這樣的話在之后就有可能由調(diào)度器將子進(jìn)程運(yùn)行起來了;
- exec:在執(zhí)行了exec系統(tǒng)調(diào)用之后饼问,會(huì)執(zhí)行正常的中斷處理流程影兽,最終將控制權(quán)轉(zhuǎn)移給syscall,之后根據(jù)系統(tǒng)調(diào)用號(hào)執(zhí)行sys_exec函數(shù)莱革,進(jìn)一步執(zhí)行了上文中的do_execve函數(shù)峻堰,在該函數(shù)中,會(huì)對(duì)內(nèi)存空間進(jìn)行清空盅视,然后將新的要執(zhí)行的程序加載到內(nèi)存中捐名,然后設(shè)置好中斷幀,使得最終中斷返回之后可以跳轉(zhuǎn)到指定的應(yīng)用程序的入口處闹击,就可以正確執(zhí)行了镶蹋;
- wait:在執(zhí)行了wait系統(tǒng)調(diào)用之后,會(huì)執(zhí)行正常的中斷處理流程赏半,最終將控制權(quán)轉(zhuǎn)移給syscall贺归,之后根據(jù)系統(tǒng)調(diào)用號(hào)執(zhí)行sys_wait函數(shù),進(jìn)一步執(zhí)行了的do_wait函數(shù)断箫,在這個(gè)函數(shù)中拂酣,將搜索是否指定進(jìn)程存在著處于ZOMBIE態(tài)的子進(jìn)程,如果有的話直接將其占用的資源釋放掉即可瑰枫;如果找不到這種子進(jìn)程踱葛,則將當(dāng)前進(jìn)程的狀態(tài)改成SLEEPING態(tài),并且標(biāo)記為等待ZOMBIE態(tài)的子進(jìn)程光坝,然后調(diào)用schedule函數(shù)將其當(dāng)前線程從CPU占用中切換出去尸诽,直到有對(duì)應(yīng)的子進(jìn)程結(jié)束來喚醒這個(gè)進(jìn)程為止;
- exit:在執(zhí)行了exit系統(tǒng)調(diào)用之后盯另,會(huì)執(zhí)行正常的中斷處理流程性含,最終將控制權(quán)轉(zhuǎn)移給syscall,之后根據(jù)系統(tǒng)調(diào)用號(hào)執(zhí)行sys_exit函數(shù)鸳惯,進(jìn)一步執(zhí)行了的do_exit函數(shù)商蕴,首先將釋放當(dāng)前進(jìn)程的大多數(shù)資源叠萍,然后將其標(biāo)記為ZOMBIE態(tài),然后調(diào)用wakeup_proc函數(shù)將其父進(jìn)程喚醒(如果父進(jìn)程執(zhí)行了wait進(jìn)入SLEEPING態(tài)的話)绪商,然后調(diào)用schedule函數(shù)苛谷,讓出CPU資源,等待父進(jìn)程進(jìn)一步完成其所有資源的回收格郁;
問題回答
-
請(qǐng)分析fork/exec/wait/exit在實(shí)現(xiàn)中是如何影響進(jìn)程的執(zhí)行狀態(tài)的腹殿?
- fork不會(huì)影響當(dāng)前進(jìn)程的執(zhí)行狀態(tài),但是會(huì)將子進(jìn)程的狀態(tài)標(biāo)記為RUNNALB例书,使得可以在后續(xù)的調(diào)度中運(yùn)行起來锣尉;
- exec不會(huì)影響當(dāng)前進(jìn)程的執(zhí)行狀態(tài),但是會(huì)修改當(dāng)前進(jìn)程中執(zhí)行的程序决采;
- wait系統(tǒng)調(diào)用取決于是否存在可以釋放資源(ZOMBIE)的子進(jìn)程自沧,如果有的話不會(huì)發(fā)生狀態(tài)的改變,如果沒有的話會(huì)將當(dāng)前進(jìn)程置為SLEEPING態(tài)树瞭,等待執(zhí)行了exit的子進(jìn)程將其喚醒拇厢;
- exit會(huì)將當(dāng)前進(jìn)程的狀態(tài)修改為ZOMBIE態(tài),并且會(huì)將父進(jìn)程喚醒(修改為RUNNABLE)移迫,然后主動(dòng)讓出CPU使用權(quán)旺嬉;
-
請(qǐng)給出ucore中一個(gè)用戶態(tài)進(jìn)程的執(zhí)行狀態(tài)生命周期圖(包執(zhí)行狀態(tài),執(zhí)行狀態(tài)之間的變換關(guān)系厨埋,以及產(chǎn)生變換的事件或函數(shù)調(diào)用)。(字符方式畫即可)
-
畫出執(zhí)行狀態(tài)圖如下所示:
state.png
-
實(shí)驗(yàn)結(jié)果
最終的實(shí)驗(yàn)結(jié)果符合預(yù)期捐顷,并且能夠通過make grade腳本的檢查荡陷,如下圖所示:
參考答案分析
接下來將對(duì)提供的參考答案進(jìn)行分析比較:
- 在完善先前實(shí)驗(yàn)內(nèi)容部分與參考答案基本一致;
- 在完成load_icode的部分與參考答案基本一致迅涮,但是存在一個(gè)比較細(xì)節(jié)的區(qū)別废赞,在設(shè)置trapframe上的eflags寄存器的時(shí)候,參考答案僅僅將寄存器上的IF位置成了1叮姑,但是根據(jù)Intel IA32的開發(fā)者手冊(cè)唉地,知道eflags的第1位(低地址數(shù)起)是默認(rèn)設(shè)置成1的,因此正確的寫法應(yīng)當(dāng)將這一位也置成1传透;
- 在完成copy_range函數(shù)部分與參考答案沒有區(qū)別耘沼;
實(shí)驗(yàn)中涉及的知識(shí)點(diǎn)列舉
本次實(shí)驗(yàn)中主要涉及到的知識(shí)點(diǎn)有:
- 從內(nèi)核態(tài)切換到用戶態(tài)的方法;
- ELF可執(zhí)行文件的格式朱盐;
- 用戶進(jìn)程的創(chuàng)建和管理群嗤;
- 簡(jiǎn)單的進(jìn)程調(diào)度;
- 系統(tǒng)調(diào)用的實(shí)現(xiàn)兵琳;
對(duì)應(yīng)的操作系統(tǒng)中的知識(shí)點(diǎn)有:
- 創(chuàng)建狂秘、管理骇径、切換到用戶態(tài)進(jìn)程的具體實(shí)現(xiàn);
- 加載ELF可執(zhí)行文件的具體實(shí)現(xiàn)者春;
- 對(duì)系統(tǒng)調(diào)用機(jī)制的具體實(shí)現(xiàn)破衔;
他們之間的關(guān)系為:
- 前者的知識(shí)點(diǎn)為后者具體在操作系統(tǒng)中實(shí)現(xiàn)具體的功能提供了基礎(chǔ)知識(shí);
實(shí)驗(yàn)中未涉及的知識(shí)點(diǎn)列舉
本次實(shí)驗(yàn)中為涉及到的知識(shí)點(diǎn)有:
- 操作系統(tǒng)的啟動(dòng)钱烟;
- 操作系統(tǒng)對(duì)內(nèi)存的管理晰筛;
- 進(jìn)程間的共享、互斥忠售、同步問題传惠;
- 文件系統(tǒng)的實(shí)現(xiàn);
實(shí)驗(yàn)代碼
https://github.com/AmadeusChan/ucore_os_lab/tree/master/lab5
參考文獻(xiàn)
- INTEL 80386 PROGRAMMER'S REFERENCE MANUAL 1986
如果我的文章給您帶來了幫助稻扬,并且您愿意給我一些小小的支持的話卦方,以下這個(gè)是我的比特幣地址~
My bitcoin address: 3KsqM8tef5XJ9jPvWGEVXyJNpvyLLsrPZj