linux設(shè)備驅(qū)動(dòng)歸納總結(jié)(四):1.進(jìn)程管理的相關(guān)概念 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 接下來(lái)的幾節(jié)我會(huì)大概的講一下內(nèi)核進(jìn)程的一些概念,,其實(shí)應(yīng)該在學(xué)習(xí)系統(tǒng)編程時(shí)候就應(yīng)該知道的,。。我參照的書(shū)籍是《linux內(nèi)核設(shè)計(jì)與實(shí)現(xiàn)》(第三版),。我會(huì)盡可能地跳開(kāi)內(nèi)核代碼,,簡(jiǎn)述一下原理。 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 一,、什么是進(jìn)程 簡(jiǎn)單的說(shuō),進(jìn)程就是正在運(yùn)行的程序,,一個(gè)程序可以同時(shí)有多個(gè)進(jìn)程,。學(xué)過(guò)C語(yǔ)言都知道,程序運(yùn)行時(shí)并不是只有代碼,,還包含其他的資源,,如打開(kāi)的文件,信號(hào),,全局變量等等,。我在《操作系統(tǒng)原理》中看過(guò)一個(gè)很生動(dòng)很深刻的例子:一個(gè)人對(duì)照著菜譜做菜。在這例子中,,人就是內(nèi)核,,菜譜就是程序,做菜的過(guò)程就是進(jìn)程,,而菜,、鍋就是這個(gè)進(jìn)程的資源。 內(nèi)核為線程提供了兩種技術(shù):虛擬處理器和虛擬內(nèi)存,。這就是說(shuō),,每個(gè)進(jìn)程都傻乎乎的認(rèn)為自己獨(dú)占著CPU和享用這4G的內(nèi)存,確不知道內(nèi)核在背后調(diào)度進(jìn)程和給每個(gè)進(jìn)程4G的虛擬地址,。 進(jìn)程由fork創(chuàng)建,,通過(guò)exit退出。 有人或許會(huì)問(wèn),,那線程是什么,?線程就是一種特殊的進(jìn)程。 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 二,、進(jìn)程是用什么結(jié)構(gòu)體來(lái)維護(hù) 內(nèi)核將所有的進(jìn)程放在叫任務(wù)隊(duì)列(task list)的雙向循環(huán)鏈表中,,鏈表中的每個(gè)項(xiàng)都是類型為task_struct、稱為進(jìn)程描述符的結(jié)構(gòu),。每個(gè)進(jìn)程描述符包含著一個(gè)進(jìn)程的所有信息,,驅(qū)動(dòng)開(kāi)發(fā)中我用得最頻繁的有兩個(gè)成員,,pid(進(jìn)程標(biāo)識(shí)值)和comm(當(dāng)前進(jìn)程的所執(zhí)行的程序文件名稱)。 來(lái)張形象點(diǎn)的圖:
獲得當(dāng)前正在進(jìn)行的進(jìn)程進(jìn)程描述符也很簡(jiǎn)單,,使用全局項(xiàng)current就可以獲得,。 /*4th_mutex/4th_mutex_1/1st/test.c*/ 113 P_DEBUG("[%s]:pid[%d]\n", current->comm, current->pid); xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 三、進(jìn)程的狀態(tài) 我只說(shuō)5種,,其中前兩種是之前在等待隊(duì)列的時(shí)候介紹過(guò),。 1)TASK_RUNNING(運(yùn)行):該狀態(tài)出現(xiàn)在進(jìn)程正在運(yùn)行,或者已經(jīng)放在運(yùn)行隊(duì)列中等待執(zhí)行(對(duì)應(yīng)操作系統(tǒng)原理上所說(shuō)的就緒狀態(tài)),。這里要注意的是等待執(zhí)行和休眠是兩碼事,。 2)TASK_INTERRUPTIBLE(可中斷休眠):這就是休眠狀態(tài)中一種,之所以說(shuō)可中斷,,就是說(shuō)除了可以被其他進(jìn)程從等待隊(duì)列喚醒以外,,還可以接送到信號(hào)而喚醒,這是常用的休眠狀態(tài),。 3)TASK_UNINTERRUPTIBLE(不可中斷休眠):這就是休眠狀態(tài)的另一種,,只能從等待隊(duì)列被喚醒。因?yàn)樗绱税缘?,所以很少有人使用?/FONT> 4)TASK_ZOMBIE(僵死):這種情況出現(xiàn)在進(jìn)程結(jié)束后,,但父進(jìn)程還有來(lái)回收該進(jìn)程的進(jìn)程描述符。 5)TASK_STOPPED(停止):一看就知道,,進(jìn)程停止執(zhí)行,。 來(lái)個(gè)圖來(lái)對(duì)照前四種狀態(tài)的轉(zhuǎn)換: 由上圖可以看到用戶空間的進(jìn)程有fork()系統(tǒng)調(diào)用產(chǎn)生,如果運(yùn)行途中沒(méi)有任何阻塞,,它會(huì)在最后調(diào)用do_exit將進(jìn)程的狀態(tài)轉(zhuǎn)為TASK_ZOMBIE,。等待父進(jìn)程來(lái)收尸。接下來(lái)就要簡(jiǎn)單地說(shuō)一下進(jìn)程的創(chuàng)建和進(jìn)程的終結(jié),。 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 四,、進(jìn)程的創(chuàng)建 進(jìn)程的創(chuàng)建一般分兩步: 1、調(diào)用fork(): 在系統(tǒng)編程時(shí),,我們一般都是調(diào)用fork()來(lái)創(chuàng)建新的用戶進(jìn)程,。 先說(shuō)一下傳統(tǒng)的forl()的實(shí)現(xiàn),傳統(tǒng)的fork()被調(diào)用后,,內(nèi)核會(huì)拷貝父進(jìn)程的所有資源給新建的子進(jìn)程,。要知道這是一個(gè)多愚蠢的操作,如果新建子進(jìn)程是打算執(zhí)行另一個(gè)新程序,,之前的拷貝過(guò)程就白費(fèi)了,。 出于這樣的原因,linux的fork()有了寫時(shí)拷貝(copy-on-write)技術(shù),。從字面上就能理解意思,,父進(jìn)程創(chuàng)建子進(jìn)程后,,他給子進(jìn)程創(chuàng)建一個(gè)文件描述符,并且與子進(jìn)程以只讀方式共享原有的資源,,只有在子進(jìn)程或者父進(jìn)程修改資源時(shí),,資源才會(huì)被復(fù)制。所以說(shuō),,在不修改資源的情況下,,fork()的實(shí)際開(kāi)銷就兩樣: 1)復(fù)制父進(jìn)程的頁(yè)表給子進(jìn)程。大家應(yīng)該都知道,,linux內(nèi)存管理使用的頁(yè)式管理,,只要也就是說(shuō),只要把父進(jìn)程的頁(yè)表復(fù)制給子進(jìn)程,,子進(jìn)程就能在頁(yè)表中找到與父進(jìn)程共享的4G虛擬地址了,。 2)為子進(jìn)程創(chuàng)建唯一的進(jìn)程描述符。這個(gè)就不用解釋了,,進(jìn)程與進(jìn)程描述符是一一對(duì)應(yīng)的。 fork具體調(diào)用的什么函數(shù)我就不詳細(xì)說(shuō)了,,不過(guò)應(yīng)該有這樣的一個(gè)概念: fork->clone->do_fork()->copy_procrss: fork()系統(tǒng)調(diào)用根據(jù)提供的參數(shù)調(diào)用clone(),,然后clone()去調(diào)用do_fork(),其中do_fork中完成了創(chuàng)建的大部分操作,,里面有一個(gè)主要的函數(shù)copy_process(),。 2、調(diào)用exec(): 一般的,,創(chuàng)建的子進(jìn)程都不是為了完成父進(jìn)程中的任務(wù),,而是需要執(zhí)行新的任務(wù)。exec()的作用就是讀取可執(zhí)行文件并加載到地址空間開(kāi)始運(yùn)行,,可以類比成命令”./xxxxx”,。如果fork()后子進(jìn)程調(diào)用exec()執(zhí)行新的代碼,就不需要拷貝父進(jìn)程的資源了,。所以,,一般fork()之后都是子進(jìn)程先運(yùn)行。 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 五,、進(jìn)程的終結(jié): 一般的,,進(jìn)程調(diào)用exit()結(jié)束進(jìn)程。相應(yīng)的,,exit()是調(diào)用do_exit()進(jìn)行刪除進(jìn)程的資源和改變進(jìn)程狀態(tài)等操作,。 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 六、什么是進(jìn)程上下文: 用戶態(tài)的應(yīng)用程序執(zhí)行系統(tǒng)調(diào)用時(shí),,它就會(huì)陷入內(nèi)核空間,,此時(shí),,我們稱內(nèi)核“代表進(jìn)程執(zhí)行”并處于進(jìn)程上下文。簡(jiǎn)單的說(shuō),,以我們之前寫的驅(qū)動(dòng)舉例,,當(dāng)應(yīng)用成調(diào)用open,他就會(huì)陷入內(nèi)核調(diào)用驅(qū)動(dòng)函數(shù)中的test_open,,此時(shí)內(nèi)核就處于進(jìn)程上下文了,。 值得一提的是,在進(jìn)程上下文時(shí),,current始終有效,,它還是指向應(yīng)用層中的進(jìn)程,所以在”1st”的例子中,,tesp_open打印出來(lái)的進(jìn)程號(hào)current->pid與應(yīng)用層是一樣的,。 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 七、線程,、進(jìn)程和內(nèi)核線程程又是怎么樣的關(guān)系: 線程,,它是進(jìn)程活動(dòng)中的對(duì)象,最通俗的解釋,,一個(gè)進(jìn)程里面可以有一個(gè)或者多個(gè)線程,,它們共同享用進(jìn)程的資源。 內(nèi)核線程,,獨(dú)立運(yùn)行在內(nèi)核空間的標(biāo)準(zhǔn)進(jìn)程,,但沒(méi)有獨(dú)立的運(yùn)行空間,只運(yùn)行在內(nèi)核空間,,但和普通進(jìn)程一樣被調(diào)度和搶占,。 總的來(lái)說(shuō),線程(又叫用戶線程)和內(nèi)核線程都是進(jìn)程的特殊形式,,它們的創(chuàng)建同樣也是通過(guò)調(diào)用clone(),。它們和進(jìn)程的最大區(qū)別在于它們沒(méi)有獨(dú)立的4G虛擬空間。 而線程和內(nèi)核線程的區(qū)別就是:線程存在與用戶態(tài),,內(nèi)核線程存在與內(nèi)核態(tài),。 同時(shí)需要強(qiáng)調(diào)的是,進(jìn)程是存在于用戶態(tài)的,。 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 八,、總結(jié): 今天只是介紹了進(jìn)程的一些基本的概念,為以后的進(jìn)程調(diào)度,、并發(fā),、競(jìng)態(tài)等理論打基礎(chǔ)。 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 源代碼: 4th_mutex_1.rar |
|