Linux操作系統(tǒng)分析與實(shí)踐第三講:進(jìn)程管理.ppt_第1頁(yè)
Linux操作系統(tǒng)分析與實(shí)踐第三講:進(jìn)程管理.ppt_第2頁(yè)
Linux操作系統(tǒng)分析與實(shí)踐第三講:進(jìn)程管理.ppt_第3頁(yè)
Linux操作系統(tǒng)分析與實(shí)踐第三講:進(jìn)程管理.ppt_第4頁(yè)
Linux操作系統(tǒng)分析與實(shí)踐第三講:進(jìn)程管理.ppt_第5頁(yè)
已閱讀5頁(yè),還剩87頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

Linux操作系統(tǒng)分析與實(shí)踐第三講:進(jìn)程管理,Linux操作系統(tǒng)分析與實(shí)踐課程建設(shè)小組北京大學(xué)二零零八年春季*致謝:感謝Intel對(duì)本課程項(xiàng)目的資助,本講主要內(nèi)容,Linux中的進(jìn)程Linux進(jìn)程控制Linux的進(jìn)程調(diào)度Linux源代碼閱讀示例:進(jìn)程調(diào)度schedule部分的閱讀,一、Linux中的進(jìn)程,進(jìn)程是程序執(zhí)行時(shí)的一個(gè)實(shí)例從內(nèi)核的觀點(diǎn)來(lái)看,進(jìn)程的目的是擔(dān)當(dāng)分配系統(tǒng)資源(CPU時(shí)間,存儲(chǔ)器等)的實(shí)體Linux中的關(guān)于進(jìn)程的代碼大部分是如何管理進(jìn)程的代碼每個(gè)進(jìn)程運(yùn)行的是程序的代碼,輕量級(jí)進(jìn)程,線程代表進(jìn)程的一個(gè)執(zhí)行流,內(nèi)核無(wú)法感知Linux使用輕量級(jí)進(jìn)程對(duì)多線程應(yīng)用程序提供更好的支持輕量級(jí)進(jìn)程可以共享資源通過(guò)將輕量級(jí)進(jìn)程與線程相關(guān)聯(lián),內(nèi)核可以獨(dú)立調(diào)度線程,進(jìn)程描述符task_struct(include/linux/sched.h),進(jìn)程描述符(續(xù)),Task_struct結(jié)構(gòu)的描述:進(jìn)程標(biāo)識(shí)進(jìn)程狀態(tài)(State)進(jìn)程調(diào)度信息和策略標(biāo)識(shí)號(hào)(Identifiers)進(jìn)程通信有關(guān)的信息(IPC)進(jìn)程鏈接信息(Links)時(shí)間和定時(shí)器信息(TimesandTimers)文件系統(tǒng)信息(FilesSystem)處理器相關(guān)的上下文信息,進(jìn)程描述符(續(xù)),Linux中每一個(gè)進(jìn)程由一個(gè)task_struct數(shù)據(jù)結(jié)構(gòu)來(lái)描述(進(jìn)程控制塊PCB)進(jìn)程描述符放在動(dòng)態(tài)內(nèi)存中而且和內(nèi)核態(tài)的進(jìn)程棧放在一個(gè)獨(dú)立的8KB的內(nèi)存區(qū)中好處:通過(guò)esp就能引用進(jìn)程描述符,current宏,current宏current宏獲取當(dāng)前正在運(yùn)行的進(jìn)程描述符的指針,current宏經(jīng)常作為進(jìn)程描述符出現(xiàn)在內(nèi)核代碼里,例如current-pid返回當(dāng)前正在運(yùn)行的進(jìn)程的PID值,進(jìn)程的狀態(tài),task_struct中的state表示進(jìn)程當(dāng)前的狀態(tài)Linux中的進(jìn)程有5個(gè)狀態(tài):,狀態(tài)之間的轉(zhuǎn)換,進(jìn)程鏈表,task_struct中的structtask_struct*next_task,*prev_task;,TASK_RUNNING狀態(tài)的進(jìn)程鏈表,task_struct中的structlist_headrun_list;list_head是Linux內(nèi)核當(dāng)中定義的一個(gè)數(shù)據(jù)結(jié)構(gòu)用來(lái)實(shí)現(xiàn)雙向鏈表,Linux內(nèi)核中使用上百個(gè)向鏈表來(lái)存放各種數(shù)據(jù)結(jié)(includelist.h),進(jìn)程PIDhash,task_struct中的pid為了快速的從pid值獲得進(jìn)程描述符。需要有hash表hash_pid(),unhashpid()在pidhash表中分別插入和刪除一個(gè)進(jìn)程find_task_by_pid()查找散列表并返回給定PID的進(jìn)程描述符指針,進(jìn)程之間的父子關(guān)系,task_struct中的structtask_struct*p_opptr,*p_pptr,*p_cptr,*p_ysptr,*p_osptr;p_opptr:originalparent(process1或者創(chuàng)建它的父進(jìn)程)p_pptr:parent(父進(jìn)程,有時(shí)候是調(diào)試時(shí)的調(diào)試監(jiān)管進(jìn)程)p_cptr:child(指向自己最年輕的子進(jìn)程)p_ysptr:指向比自己年輕的兄弟進(jìn)程p_osptr:指向比自己老的兄弟進(jìn)程,進(jìn)程之間的父子關(guān)系(續(xù)),進(jìn)程之間的父子關(guān)系(續(xù)),Linux中的0號(hào)進(jìn)程,通常稱(chēng)為swapper進(jìn)程,是所有進(jìn)程的祖先。由它執(zhí)行cpu_idle()函數(shù),當(dāng)沒(méi)有其他進(jìn)程處于TASK_RUNNING的時(shí)候,調(diào)度程序會(huì)選擇0號(hào)進(jìn)程運(yùn)行0號(hào)進(jìn)程創(chuàng)建1號(hào)進(jìn)程,通常稱(chēng)為init進(jìn)程。它創(chuàng)建和監(jiān)控其他進(jìn)程的活動(dòng),進(jìn)程的地址空間,Linux把進(jìn)程的線性地址空間組織為一個(gè)個(gè)線性區(qū)每一個(gè)線性區(qū)對(duì)應(yīng)一組連續(xù)的頁(yè)線性區(qū)之間不重疊,進(jìn)程的地址空間(續(xù)),task_structstructmm_struct*mm;內(nèi)存描述符mm_struct里面有一個(gè)字段mmp指向內(nèi)存線性區(qū)鏈表的首部。,進(jìn)程的地址空間(續(xù)),每個(gè)線性區(qū)有一定的訪問(wèn)權(quán)限在增加或刪除線性區(qū)時(shí),Linux盡量合并訪問(wèn)權(quán)限相同且相鄰的線性區(qū),進(jìn)程的地址空間(續(xù)),進(jìn)程堆的管理,每個(gè)進(jìn)程都擁有一個(gè)特殊的線形區(qū):堆內(nèi)存描述符里面的start_brk和brk字段限定了這個(gè)區(qū)的開(kāi)始地址和結(jié)束地址常用的C庫(kù)函數(shù):malloc(),free()系統(tǒng)調(diào)用brk()用于直接修改堆大小,二、LINUX進(jìn)程控制,Linux進(jìn)程的創(chuàng)建和執(zhí)行相關(guān)的數(shù)據(jù)結(jié)構(gòu)和系統(tǒng)調(diào)用進(jìn)程的創(chuàng)建程序的執(zhí)行Linux進(jìn)程的撤消,相關(guān)的數(shù)據(jù)結(jié)構(gòu),系統(tǒng)創(chuàng)建進(jìn)程時(shí),Linux為新進(jìn)程分配一task_struct結(jié)構(gòu),進(jìn)程結(jié)束時(shí)收回其task_struct結(jié)構(gòu)Linux在內(nèi)存空間中分配了一塊空間來(lái)存放進(jìn)程的task_struct結(jié)構(gòu),并將所有的task_struct結(jié)構(gòu)的指針?lè)旁谝粋€(gè)task數(shù)組中,該數(shù)組是在操作系統(tǒng)內(nèi)核中專(zhuān)門(mén)開(kāi)辟的一塊區(qū)域,數(shù)組大小也就是系統(tǒng)中所能容納的進(jìn)程的數(shù)目,相關(guān)的數(shù)據(jù)結(jié)構(gòu)(續(xù)),Task數(shù)組的結(jié)構(gòu):structtask_struct*taskNR_TASKS=NR_TASKS是數(shù)組的大小,默認(rèn)是512,相關(guān)的數(shù)據(jù)結(jié)構(gòu)(續(xù)),Task_struct結(jié)構(gòu)的描述:進(jìn)程標(biāo)識(shí)進(jìn)程狀態(tài)(State)進(jìn)程調(diào)度信息和策略標(biāo)識(shí)號(hào)(Identifiers)進(jìn)程通信有關(guān)的信息(IPC)進(jìn)程鏈接信息(Links)時(shí)間和定時(shí)器信息(TimesandTimers)文件系統(tǒng)信息(FilesSystem)處理器相關(guān)的上下文信息,相關(guān)的系統(tǒng)調(diào)用,Fork()通過(guò)復(fù)制調(diào)用進(jìn)程來(lái)建立新的進(jìn)程,是最基本的進(jìn)程建立過(guò)程Exec包括一系列系統(tǒng)調(diào)用,它們都是通過(guò)用一個(gè)新的程序覆蓋原來(lái)的內(nèi)存空間,實(shí)現(xiàn)進(jìn)程的轉(zhuǎn)變Wait()提供初級(jí)的進(jìn)程同步措施,能使一個(gè)進(jìn)程等待,直到另外一個(gè)進(jìn)程結(jié)束為止。Exit()該系統(tǒng)調(diào)用用來(lái)終止一個(gè)進(jìn)程的運(yùn)行,如何區(qū)分父進(jìn)程和子進(jìn)程的功能?父子進(jìn)程怎樣被調(diào)度執(zhí)行?父子進(jìn)程在內(nèi)存中如何存放?子進(jìn)程如何繼承父進(jìn)程的資源?,進(jìn)程的創(chuàng)建過(guò)程,新的進(jìn)程通過(guò)克隆舊的進(jìn)程來(lái)建立,當(dāng)前進(jìn)程是通過(guò)fork()系統(tǒng)調(diào)用來(lái)建立新的進(jìn)程當(dāng)系統(tǒng)調(diào)用結(jié)束時(shí),內(nèi)核在系統(tǒng)的物理內(nèi)存中為新進(jìn)程分配新的task_struct結(jié)構(gòu),并為新進(jìn)程要使用的堆棧分配物理頁(yè)和進(jìn)程標(biāo)志符父進(jìn)程和子進(jìn)程共享打開(kāi)的文件fork()的簡(jiǎn)單流程,Fork調(diào)用執(zhí)行示意,如上圖所示,分別使fork調(diào)用前后的兩個(gè)部分PC指向當(dāng)前執(zhí)行的語(yǔ)句,fork之前,它指向第一個(gè)printf語(yǔ)句,fork調(diào)用之后進(jìn)程A、B一起運(yùn)行,A是父進(jìn)程,B是子進(jìn)程進(jìn)程A的副本,執(zhí)行與A一樣的程序。兩個(gè)pc都指向第二個(gè)printf語(yǔ)句。也就是AB從程序的相同點(diǎn)開(kāi)始執(zhí)行,Fork內(nèi)存的變動(dòng),Fork()執(zhí)行的內(nèi)存變動(dòng)如下:分配1頁(yè)給task_struct結(jié)構(gòu)分配1頁(yè)給內(nèi)核堆棧分配1頁(yè)給pg_dir并且給page_tables分配一些頁(yè),Fork硬件相關(guān)的變化,硬件相關(guān)的變化SS被置為內(nèi)核堆棧(0 x10)ESP被置為新分配棧的頂端(kernel_stack_page)CR3指向新分配的頁(yè)目錄(由copy_page_table()完成)Idt=_LDT(task_nr)建立新的局部描述符為新的任務(wù)狀態(tài)段(tss)和局部描述符表(ldt)裝入gdt從父進(jìn)程繼承剩下的寄存器,Fork系統(tǒng)調(diào)用,Pid_tfork(void);由fork創(chuàng)建的新進(jìn)程稱(chēng)為子進(jìn)程。該函數(shù)被調(diào)用一次,會(huì)返回兩次。給子進(jìn)程的返回值是0,給父進(jìn)程的返回值是子進(jìn)程的進(jìn)程ID。然后子進(jìn)程和父進(jìn)程繼續(xù)執(zhí)行fork之后的指令。子進(jìn)程擁有父進(jìn)程數(shù)據(jù)空間,堆和棧的拷貝,但是它們并不是共享這些存儲(chǔ)空間。這里就用到了“寫(xiě)時(shí)復(fù)制”技術(shù),寫(xiě)時(shí)復(fù)制,寫(xiě)時(shí)復(fù)制技術(shù)(copy_on_write)Linux通過(guò)寫(xiě)時(shí)復(fù)制技術(shù)來(lái)調(diào)入執(zhí)行的程序Linux將可寫(xiě)虛擬內(nèi)存頁(yè)的頁(yè)表項(xiàng)標(biāo)志為只讀,當(dāng)進(jìn)程向該內(nèi)存頁(yè)寫(xiě)入數(shù)據(jù)時(shí),處理器會(huì)發(fā)現(xiàn)內(nèi)存訪問(wèn)中的問(wèn)題(向只讀頁(yè)中寫(xiě)入),然后會(huì)導(dǎo)致操作系統(tǒng)可以捕獲的頁(yè)故障,由操作系統(tǒng)來(lái)完成內(nèi)存頁(yè)的復(fù)制一個(gè)給定的物理頁(yè)面可以代表多個(gè)邏輯頁(yè)面,當(dāng)這個(gè)頁(yè)被一個(gè)進(jìn)程從另一個(gè)進(jìn)程處得到共享時(shí),它是邏輯上的拷貝如前面的fork調(diào)用,邏輯拷貝整個(gè)進(jìn)程的地址空間,僅當(dāng)試圖修改頁(yè)面(產(chǎn)生寫(xiě)錯(cuò)誤)才真正的拷貝,程序的執(zhí)行,用fork創(chuàng)建子進(jìn)程之后,為了讓父進(jìn)程和子進(jìn)程執(zhí)行不同的任務(wù),經(jīng)常需要調(diào)用一種exec函數(shù)以執(zhí)行另一個(gè)程序。當(dāng)進(jìn)程調(diào)用exec函數(shù)時(shí),該進(jìn)程完全由新程序替代。新程序從main開(kāi)始執(zhí)行exec并不創(chuàng)建新進(jìn)程,前后進(jìn)程ID是不變的。它是用另外一個(gè)程序替代了當(dāng)前進(jìn)程的正文,數(shù)據(jù),堆和棧,exec函數(shù),exec執(zhí)行時(shí)的內(nèi)存變化1頁(yè)分配給可執(zhí)行文件頭1頁(yè)或者多頁(yè)分配給堆棧硬件相關(guān)的變化:clear_page_tables()移去舊頁(yè)在新的LDT中設(shè)置描述符包含argv和envp的“臟”頁(yè)被分配設(shè)置調(diào)用者的指針設(shè)置調(diào)用者的堆棧指針指向建立的堆棧更新內(nèi)存段的邊界,ForkVSExec,因?yàn)閒ork只能建立相同程序的副本,如果它是程序員唯一可以使用的建立進(jìn)程的手段,會(huì)影響linux的性能exec系列系統(tǒng)調(diào)用把新進(jìn)程裝入調(diào)用進(jìn)程的地址空間,改變調(diào)用進(jìn)程的代碼。如果exec成功,調(diào)用者進(jìn)程將被覆蓋,從新進(jìn)程的入口地址開(kāi)始執(zhí)行。exec只用新進(jìn)程取代了原來(lái)的進(jìn)程。并且沒(méi)有返回?cái)?shù)據(jù),進(jìn)程的撤銷(xiāo),撤銷(xiāo)時(shí)機(jī)主動(dòng)撤銷(xiāo):執(zhí)行完代碼,通知內(nèi)核釋放進(jìn)程的資源被動(dòng):內(nèi)核有選擇地強(qiáng)迫進(jìn)程死掉。e.g內(nèi)核代表進(jìn)程運(yùn)行時(shí)在內(nèi)核態(tài)產(chǎn)生不可恢復(fù)的異常,進(jìn)程的撤銷(xiāo),進(jìn)程可能已死,但必須保存它的描述符,在你進(jìn)程得到通知后才可以刪除僵死狀態(tài):表明進(jìn)程已死,但需要等待父進(jìn)程刪除撤銷(xiāo)過(guò)程分為進(jìn)程終止:釋放進(jìn)程占有的大部分資源進(jìn)程刪除:徹底刪除進(jìn)程的所有數(shù)據(jù)結(jié)構(gòu),系統(tǒng)調(diào)用_exit(),C編譯程序總是把exit()插入到main()的最后一條語(yǔ)句之后,exit()調(diào)用_exit()系統(tǒng)調(diào)用_exit()調(diào)用do_exit()釋放進(jìn)程所占資源,終止進(jìn)程,進(jìn)程終止:do_exit(),刪除內(nèi)核對(duì)終止進(jìn)程的大部分引用:信號(hào)量隊(duì)列中的進(jìn)程描述符刪除進(jìn)程描述符中與分頁(yè)、文件系統(tǒng)、打開(kāi)文件描述符和信號(hào)處理相關(guān)數(shù)據(jù)結(jié)構(gòu)減小進(jìn)程所用模塊的引用計(jì)數(shù)將進(jìn)程描述符的exit_code字段設(shè)置為終止代號(hào)更新父子進(jìn)程的親屬關(guān)系,強(qiáng)制將自己的子進(jìn)程作為其它某個(gè)進(jìn)程的子進(jìn)程,以等待該父進(jìn)程進(jìn)行刪除調(diào)用schedule()進(jìn)行調(diào)度,進(jìn)程刪除,父進(jìn)程調(diào)用wait()類(lèi)系統(tǒng)調(diào)用檢查子進(jìn)程是否終止若子進(jìn)程包含終止代號(hào),則父進(jìn)程通過(guò)release()釋放僵死進(jìn)程的描述符釋放進(jìn)程id從進(jìn)程鏈表中刪除進(jìn)程描述符釋放存放進(jìn)程描述符的內(nèi)存區(qū),三、Linux的進(jìn)程調(diào)度,schedule()決定是否進(jìn)行進(jìn)程切換,若要切換,切換到哪個(gè)進(jìn)程Linux的調(diào)度時(shí)機(jī)調(diào)度策略,1、進(jìn)程調(diào)度的依據(jù),選擇一個(gè)權(quán)值(weight)最大的進(jìn)程權(quán)值的計(jì)算goodness():綜合policy,priority,rt_priority和counter四項(xiàng)計(jì)算步驟:1、區(qū)分實(shí)時(shí)進(jìn)程和普通進(jìn)程實(shí)時(shí)進(jìn)程的權(quán)值:rt_priority普通進(jìn)程的權(quán)值:與counter有關(guān)2、權(quán)值:普通進(jìn)程:weight=p-counter實(shí)時(shí)進(jìn)程:weight=1000+rt_priority,task_struct,policy,priority,rt_priority,counter,實(shí)時(shí)進(jìn)程,SCHED_RR,SCHED_FIFO,普通進(jìn)程動(dòng)態(tài)優(yōu)先調(diào)度周期性地修改進(jìn)程的優(yōu)先級(jí)(避免饑餓)根據(jù)進(jìn)程的counter值實(shí)時(shí)進(jìn)程的優(yōu)先級(jí)是靜態(tài)優(yōu)先級(jí),counter剩余的時(shí)間片時(shí)間單位:時(shí)鐘滴答(10ms)初值200msdo_fork()同時(shí)設(shè)置父進(jìn)程和子進(jìn)程的counter域把父進(jìn)程的剩余時(shí)間片分成相等的兩份,父子進(jìn)程各占一份對(duì)于普通進(jìn)程,counter起作用與priority的關(guān)系,當(dāng)時(shí)間片用完后,用priority重新對(duì)counter賦值何時(shí)重新賦值所有處于可運(yùn)行狀態(tài)的普通進(jìn)程的時(shí)間片都用完時(shí)間片確定CPU時(shí)間的兩個(gè)層次:時(shí)間段,時(shí)間段中時(shí)間片基本時(shí)間片,need_resched此標(biāo)志若為1,調(diào)用調(diào)度程序schedule()選擇下一個(gè)應(yīng)該運(yùn)行的進(jìn)程調(diào)用ret_from_sys_call()恢復(fù)所選進(jìn)程的環(huán)境時(shí)鐘中斷:最頻繁的調(diào)度時(shí)機(jī),下一次調(diào)度將基本時(shí)間片指定為進(jìn)程的運(yùn)行時(shí)間片可以通過(guò)nice()和setpriority()改變進(jìn)程的時(shí)間片子進(jìn)程繼承父進(jìn)程的基本時(shí)間片INIT_TASK宏中初始化DEF_COUNTER,2、Linux調(diào)度的時(shí)機(jī),進(jìn)程狀態(tài)轉(zhuǎn)換時(shí)刻如,進(jìn)程終止、進(jìn)程睡眠(進(jìn)程調(diào)用sleep(),exit()等)可運(yùn)行隊(duì)列中增加新的進(jìn)程時(shí)系統(tǒng)調(diào)用add_to_runqueue(),會(huì)比較進(jìn)程時(shí)間片計(jì)數(shù),符合條件則調(diào)度標(biāo)志置1當(dāng)前進(jìn)程時(shí)間片用完時(shí)進(jìn)程從系統(tǒng)調(diào)用返回到用戶(hù)態(tài)時(shí)內(nèi)核處理完中斷,進(jìn)程返回到用戶(hù)態(tài)時(shí)后三種,調(diào)用ret_from_sys_call(),檢測(cè)調(diào)度標(biāo)志,若調(diào)度標(biāo)志為1,此刻也為時(shí)機(jī),3、調(diào)度程序源代碼分析,可運(yùn)行隊(duì)列雙向循環(huán)隊(duì)列,task_struct中的next_run和prev_run兩個(gè)特殊進(jìn)程:當(dāng)前進(jìn)程current和空進(jìn)程(idle_task)新出現(xiàn)的進(jìn)程被插入到idle_task-next處(為什么?)隊(duì)列長(zhǎng)度:nr_running(為1時(shí),表示隊(duì)列中只有空進(jìn)程)實(shí)時(shí)進(jìn)程時(shí)間片用完后,重新賦值,并放到隊(duì)列末尾從就緒隊(duì)列的隊(duì)首開(kāi)始,遍歷隊(duì)列,尋找權(quán)值最大的進(jìn)程如果所有普通進(jìn)程的時(shí)間片都用完了,則給所有進(jìn)程的counter重新賦值如果當(dāng)前進(jìn)程被調(diào)度,則其繼續(xù)執(zhí)行,Linux源代碼閱讀-示例,進(jìn)程調(diào)度schedule部分的閱讀1.如何入手2.結(jié)構(gòu)分析,入手,涉及到的主要入口文件:cess.cincludeasm-system.h,入手,如何認(rèn)定以上就是主要內(nèi)容的所在?從sched.c依據(jù)主要的導(dǎo)出過(guò)程(即此模塊希望被別人使用的接口)的實(shí)現(xiàn)和其中關(guān)鍵對(duì)外調(diào)用依賴(lài)的分布情況。(通過(guò)簡(jiǎn)單的代碼掃描即可獲得這個(gè)信息,通過(guò)代碼閱讀工具將更加便于引用的查找)忽略大多數(shù)本地函數(shù)的實(shí)現(xiàn)和對(duì)外依賴(lài),只關(guān)注組織模塊代碼流程的關(guān)鍵函數(shù),這個(gè)可以從系統(tǒng)調(diào)用接口的實(shí)現(xiàn)看出來(lái),例如sys_fork()、sys_clone()等都通過(guò)調(diào)用do_fork()實(shí)現(xiàn),顯然后者負(fù)責(zé)組織fock模塊的主體功能和程序流程。這里可以透過(guò)調(diào)用關(guān)系分析以及名字的敏感性發(fā)現(xiàn)schedule()函數(shù)是這一模塊組織形態(tài)的核心。并且,可以預(yù)見(jiàn)到這個(gè)函數(shù)將完成一些“主動(dòng)”的功能這里的劃分基于對(duì)代碼樹(shù)構(gòu)成和代碼功能分布的一般認(rèn)識(shí),這是一個(gè)前提,入手-統(tǒng)計(jì)主要的代碼符號(hào),鑒別本地使用和意圖導(dǎo)出的符號(hào):找到模塊的主要對(duì)外功能接口。查看sched.h對(duì)比sched.c,可以發(fā)現(xiàn)下面的函數(shù)是在其中實(shí)現(xiàn)的:externvoidsched_init(void);externvoidinit_idle(void);externvoidshow_state(void);externsignedlongFASTCALL(schedule_timeout(signedlongtimeout);asmlinkagevoidschedule(void);,入手,在contex.c中實(shí)現(xiàn)了:externintschedule_task(structtq_struct*task);externvoidflush_scheduled_tasks(void);externintstart_context_thread(void);externintcurrent_is_keventd(void);此外,該頭文件也定義了下面幾個(gè)函數(shù)。externvoidcpu_init(void);=arch.kernel.externvoidtrap_init(void);=arch.kernel.,入手,下面是和計(jì)時(shí)相關(guān)的函數(shù):externvoidupdate_process_times(intuser);externvoidupdate_one_process(structtask_struct*p,unsignedlonguser,unsignedlongsystem,intcpu);還有相當(dāng)數(shù)量的內(nèi)核調(diào)用實(shí)現(xiàn),例如和信號(hào)相關(guān)的內(nèi)容等,入手,通過(guò)對(duì)頭文件的觀察還可以發(fā)現(xiàn)幾組重要的系統(tǒng)變量,下面是幾個(gè)主要部分全局鎖跟蹤變量全局唯一的結(jié)構(gòu)單體和表全局參數(shù)全局常量,入手,這里羅列的符號(hào)實(shí)質(zhì)上給出了調(diào)度模塊的模糊的組織輪廓:通過(guò)系統(tǒng)知識(shí)可以判斷調(diào)度器模塊是一個(gè)主動(dòng)模塊:它的代碼被激活執(zhí)行主要不是由用戶(hù)調(diào)用引發(fā),而直接受系統(tǒng)機(jī)制的影響,例如定時(shí)機(jī)制、系統(tǒng)調(diào)用機(jī)制、異常處理機(jī)制等。因此需要關(guān)注這些系統(tǒng)機(jī)制如何觸發(fā)調(diào)度器的運(yùn)行的問(wèn)題主動(dòng)性和功能特征意味著調(diào)度器本身的初始化必須在系統(tǒng)正常運(yùn)轉(zhuǎn)起來(lái)之前完成,它的初始化和系統(tǒng)其它部分的初始化有邏輯上的關(guān)聯(lián),這是值得考慮的又一個(gè)問(wèn)題同時(shí),作為一個(gè)系統(tǒng)功能和服務(wù)的提供者,也有被動(dòng)服務(wù)。有兩類(lèi):為內(nèi)核實(shí)現(xiàn)功能而提供的調(diào)用以及實(shí)現(xiàn)的系統(tǒng)調(diào)用在“假象”的模塊邊界上除了調(diào)用形態(tài)的依賴(lài),還有數(shù)據(jù)關(guān)聯(lián):全局的數(shù)據(jù)以及它們的格式(數(shù)據(jù)結(jié)構(gòu))到目前為止,我們關(guān)心的仍舊是結(jié)構(gòu)問(wèn)題而非實(shí)現(xiàn)問(wèn)題,結(jié)構(gòu)分析-調(diào)度器何時(shí)被激活?,主要想法是首先將scheduler看作一個(gè)實(shí)體,考察它在何時(shí)被激活:可以通過(guò)查找對(duì)schedule()函數(shù)的引用來(lái)考察這個(gè)問(wèn)題,當(dāng)然這一點(diǎn)很可能是不完全的,心里要有數(shù)。這里列出了部分典型的對(duì)schedule()的調(diào)用(此處列表不包括驅(qū)動(dòng)程序中存在的調(diào)用):Apm.c(archi386kernel):schedule();Buffer.c(fs):schedule();Exit.c(kernel):schedule();Filemap.c(mm):schedule();等等,結(jié)構(gòu)分析,通過(guò)對(duì)這些引用簡(jiǎn)單的瀏覽可以發(fā)現(xiàn)幾個(gè)值得注意的地方:1、這些調(diào)用中的大部分在調(diào)用點(diǎn)是因?yàn)樾枰却粋€(gè)尚未發(fā)生的事件(通常是由調(diào)用者自身產(chǎn)生了一個(gè)去做這件事的執(zhí)行線序),而主動(dòng)放棄處理器。其中一部分出現(xiàn)在實(shí)際實(shí)現(xiàn)某些系統(tǒng)調(diào)用的內(nèi)部函數(shù)中,例如do_signal()。有較多的存在于非通常意義的kernel部分,例如文件系統(tǒng)驅(qū)動(dòng)程序中:ext3_ioctl()2、一部分調(diào)用具有如下的形式:if(current-need_resched)改變當(dāng)前狀態(tài);schedule();這里的全局變量current以及對(duì)應(yīng)的need_resched值得關(guān)注3、處在無(wú)限循環(huán)中的調(diào)用,典型的就是softirq.c中的調(diào)用,由對(duì)linux中斷處理機(jī)制的了解,可以想象,這里將是系統(tǒng)調(diào)度得以不斷進(jìn)行的一個(gè)關(guān)鍵點(diǎn),結(jié)構(gòu)分析,4、sched.c自己產(chǎn)生的調(diào)用。這關(guān)系到調(diào)度機(jī)制的實(shí)現(xiàn)問(wèn)題5、由匯編代碼產(chǎn)生的調(diào)用6、以上的第2點(diǎn)提到的need_resched在那些地方被改變呢?通過(guò)查找發(fā)現(xiàn),下面這些地方會(huì)設(shè)置這個(gè)變量的值(也可能不完全)。比較明顯的可以看到,除了sched.c其它部分基本上只會(huì)將當(dāng)前進(jìn)程的該標(biāo)志設(shè)置為1,即需要調(diào)度,而sched.c中則會(huì)將某個(gè)進(jìn)程(剛退下處理器)的該標(biāo)志復(fù)位為零。還需要注意的是有兩處被設(shè)置為1的情況:fork.c和mian.c,這兩處均涉及到產(chǎn)生新的進(jìn)程之后設(shè)置此值,后者更是系統(tǒng)的第一個(gè)進(jìn)程的實(shí)現(xiàn),結(jié)構(gòu)分析數(shù)據(jù)結(jié)構(gòu)和全局?jǐn)?shù)據(jù),調(diào)度的核心結(jié)構(gòu)就是task_struct,在includelinuxsched.h中定義:這個(gè)結(jié)構(gòu)相當(dāng)長(zhǎng),其內(nèi)容大致可以分為如下幾個(gè)部分:調(diào)度時(shí)刻需要跟蹤的信息跟蹤狀態(tài)是否需要調(diào)度上下文多處理器支持等進(jìn)程結(jié)構(gòu)之間的組織隊(duì)列前后指向指針父進(jìn)程子進(jìn)程進(jìn)程屬性?xún)?yōu)先級(jí)進(jìn)程號(hào)對(duì)應(yīng)的程序等等用戶(hù)以及資源配置計(jì)時(shí):跟蹤記錄各種時(shí)間信息文件相關(guān):掌握的文件資源內(nèi)存相關(guān):撞我的內(nèi)存資源,包括頁(yè)映射等配額、用戶(hù)信息進(jìn)程間通信、擴(kuò)展點(diǎn)以及異常處理信號(hào)以及處理的掛鉤各種鎖信號(hào)量等,結(jié)構(gòu)分析,從數(shù)據(jù)結(jié)構(gòu)看到的結(jié)構(gòu)互聯(lián)的組織:系統(tǒng)隊(duì)列:雙鏈表,通過(guò)next_task和prev_task兩個(gè)指針相互勾連進(jìn)程家族:通過(guò)p_opptr、p_pptr、p_cptr、p_ysptr和p_osptr五個(gè)指針連接,如下圖,結(jié)構(gòu)分析狀態(tài)轉(zhuǎn)換部分,狀態(tài)轉(zhuǎn)換進(jìn)程的狀態(tài)由state跟蹤,取值可為:#defineTASK_RUNNING0#defineTASK_INTERRUPTIBLE1#defineTASK_UNINTERRUPTIBLE2#defineTASK_ZOMBIE4#defineTASK_STOPPED8當(dāng)state的值小于零(-1),表示不可運(yùn)行,為零勢(shì)正在運(yùn)行,而大于零則是處于暫停階段。簡(jiǎn)單分析調(diào)用關(guān)系之后,可以看出狀態(tài)變化,具體的方法就是查找使用上述狀態(tài)常量進(jìn)行賦值的點(diǎn)。經(jīng)過(guò)分析有如下的圖:,結(jié)構(gòu)分析,結(jié)構(gòu)分析調(diào)度流程,從schedul()函數(shù)入手:這個(gè)函數(shù)有asmlinkagevoidschedule(void)structschedule_data*sched_data;structtask_struct*prev,*next,*p;structlist_head*tmp;intthis_cpu,c;spin_lock_prefetch(prev就是當(dāng)前進(jìn)程結(jié)構(gòu),結(jié)構(gòu)分析調(diào)度流程,this_cpu=prev-processor;if(unlikely(in_interrupt()在中斷的處理過(guò)程中不應(yīng)該有對(duì)此函數(shù)的調(diào)用printk(Schedulingininterruptn);BUG();release_kernel_lock(prev,this_cpu);釋放內(nèi)核鎖:有什么作用?/*sched_dataisprotectedbythefactthatwecanrun*onlyoneprocessperCPU.*/sched_data=此處正式加鎖,以下部分由于修改重要全局?jǐn)?shù)據(jù)而進(jìn)行保護(hù)性操作,主要為了防止代碼的重入,/*moveanexhaustedRRprocesstobelast.*/if(unlikely(prev-policy=SCHED_RR)對(duì)于使用RR算法的進(jìn)程,如果到時(shí)了,就重置時(shí)間片,并移動(dòng)到隊(duì)列的末尾。if(!prev-counter)prev-counter=NICE_TO_TICKS(prev-nice);move_last_runqueue(prev);,switch(prev-state)這里根據(jù)狀態(tài)調(diào)整隊(duì)列,這句話由于case和default的順序顛倒而顯得比較怪異,仔細(xì)觀察會(huì)發(fā)現(xiàn)后兩個(gè)分支的顛倒可以節(jié)約一個(gè)break,是否是一個(gè)優(yōu)化,就不得而知了。caseTASK_INTERRUPTIBLE:可被打斷if(signal_pending(prev)有信號(hào)prev-state=TASK_RUNNING;置為運(yùn)行態(tài)break;default:del_from_runqueue(prev);其他狀況:從運(yùn)行隊(duì)列刪除caseTASK_RUNNING:;運(yùn)行狀態(tài):不做操作,prev-need_resched=0;重置調(diào)度標(biāo)記:不需要調(diào)度/*thisistheschedulerproper:*/repeat_schedule:一個(gè)重要的地址標(biāo)簽/*Defaultprocesstoselect.*/next=idle_task(this_cpu);將下一個(gè)要被調(diào)度的進(jìn)程設(shè)為idlec=-1000;c用來(lái)跟蹤權(quán)重最大的進(jìn)程,這里用的初始值是-1000,在調(diào)度的權(quán)重計(jì)算中,這個(gè)值相當(dāng)于負(fù)無(wú)窮,因?yàn)間oodness函數(shù)的值域遠(yuǎn)大于它list_for_each(tmp,這就是其中的一項(xiàng)if(can_schedule(p,this_cpu)判定可被調(diào)度intweight=goodness(p,this_cpu,prev-active_mm);計(jì)算權(quán)重if(weightc)跟蹤、記錄循環(huán)中發(fā)現(xiàn)的最大權(quán)重以及對(duì)應(yīng)的進(jìn)程c=weight,next=p;,結(jié)構(gòu)分析,這個(gè)點(diǎn)上,next就是指向下一個(gè)要運(yùn)行的進(jìn)程的結(jié)構(gòu)的指針,c就是權(quán)重考慮c區(qū)各種值的含義:c=0,這代表某個(gè)調(diào)度(普通以及RR)時(shí)間片到時(shí),要更新全部進(jìn)程的權(quán)重c=-1,運(yùn)行隊(duì)列上的都有SCHED_YIELD標(biāo)志,他們都想讓位不引發(fā)計(jì)時(shí)器更新c1000,實(shí)時(shí)進(jìn)程,/*Doweneedtore-calculatecounters?*/if(unlikely(!c)如果c為0,重新計(jì)算structtask_struct*p;spin_unlock_irq(因?yàn)闀r(shí)間片到時(shí),所以重新選一個(gè),/*fromthispointonnothingcanpreventusfrom*switchingtothenexttask,savethisfactin*sched_data.*/選定了,從這里開(kāi)始,切換到“下”一個(gè)進(jìn)程的動(dòng)作將必然發(fā)生sched_data-curr=next;task_set_cpu(next,this_cpu);spin_unlock_irq(不做上下文切換,直接返回?cái)帱c(diǎn),上下文切換kstat.context_swtch+;prepare_to_switch();準(zhǔn)備上下文切換主要是更換內(nèi)存映射structmm_struct*mm=next-mm;structmm_struct*oldmm=prev-active_mm;if(!mm)BUG_ON(next-active_mm);next-active_mm=oldmm;atomic_inc(/*Thisjustswitchestheregisterstateandthe*stack.*/,switch_to(prev,next,prev);切換在這個(gè)函數(shù)里發(fā)生:關(guān)注運(yùn)行到這里,已經(jīng)是再次被調(diào)度執(zhí)行了_schedule_tail(prev);same_process:r

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論