欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
linux進(jìn)程及進(jìn)程控制

http://blog.csdn.net/kennyrose/article/details/7533534

2012  

程序是一組可執行的靜態(tài)指令集,而進(jìn)程(process)是一個(gè)執行中的程序實(shí)例。利用分時(shí)技術(shù),在linux操作系統上同時(shí)可以運行多個(gè)進(jìn)程。分時(shí)技術(shù)的基本原理是把CPU的運行時(shí)間劃分成一個(gè)個(gè)規定長(cháng)度的時(shí)間片,讓每個(gè)進(jìn)程在一個(gè)時(shí)間片內運行。當進(jìn)程的時(shí)間片用完時(shí)系統就利用調度程序切換到另一個(gè)進(jìn)程去運行。因此實(shí)際上對于具體單個(gè)CPU的機器來(lái)說(shuō)某一個(gè)時(shí)刻只能運行一個(gè)進(jìn)程。但由于每個(gè)進(jìn)程運行的時(shí)間片很短(例如15個(gè)系統滴答=150ms),所以表面看起來(lái)好像所有進(jìn)程在同時(shí)運行著(zhù)。

  對于Linux0.11內核來(lái)講,系統最多可由64個(gè)進(jìn)程同時(shí)存在。除了第一個(gè)進(jìn)程是"手工"建立以外,其余的都是進(jìn)程使用系統調用fork創(chuàng )建的新進(jìn)程,被創(chuàng )建的進(jìn)程成為子進(jìn)程(Child Process),創(chuàng )建者,則稱(chēng)為父進(jìn)程(parent process)。內核程序使用進(jìn)程標識號(process ID,pid)來(lái)標識每個(gè)進(jìn)程。進(jìn)程由可執行的指令代碼,數據和堆棧區組成。進(jìn)程中的代碼和數據部分分別對應一個(gè)可執行文件中的代碼段,數據段。每個(gè)進(jìn)程只能執行自己的代碼和訪(fǎng)問(wèn)自己的數據及堆棧區。進(jìn)程之間相互之間的通信需要通過(guò)系統調用來(lái)進(jìn)行。對于只有一個(gè)CPU的系統,在某一個(gè)時(shí)刻只能有一個(gè)進(jìn)程正在運行。內核通過(guò)進(jìn)程調度程序分時(shí)調度各個(gè)進(jìn)程運行。

  Linux系統中,一個(gè)進(jìn)程可以在內核態(tài)(Kernal mode)或者用戶(hù)態(tài)(user mode)下執行,因此Linux內核堆棧和用戶(hù)堆棧是分開(kāi)的。用戶(hù)堆棧用于進(jìn)程在用戶(hù)態(tài)下臨時(shí)保存調用函數的參數,局部變量等數據。內核堆棧則含有內核程序執行函數調用時(shí)的信息。


1.1任務(wù)數據結構

  內核程序通過(guò)進(jìn)程表對進(jìn)程進(jìn)行管理,每個(gè)進(jìn)程在進(jìn)程表中占有一項。在Linux系統中,進(jìn)程表項是一個(gè)task_struct任務(wù)結構指針。任務(wù)數據結構定義在頭文件include/linux/sched.h中。有些書(shū)上稱(chēng)其為進(jìn)程控制塊PCB(Process Control Block)或者進(jìn)程描述符PD(Processor Descriptor)。其中保存著(zhù)用于控制和管理進(jìn)程的所有信息。主要包括進(jìn)程當前運行的狀態(tài)信息,信號,進(jìn)程號,父進(jìn)程號,運行時(shí)間累計值,正在使用的文件和本任務(wù)的局部描述符以及任務(wù)狀態(tài)段信息。該結構每個(gè)字段的含義如下所示。




當一個(gè)進(jìn)程在執行時(shí),CPU的所有寄存器中的值,進(jìn)程的狀態(tài)以及堆棧中的內容被稱(chēng)為該進(jìn)程的上下文。當內核需要切換(switch)至另一個(gè)進(jìn)程時(shí),它就需要保存當前進(jìn)程的所有狀態(tài),也即保存當前進(jìn)程的上下文,以便在再次執行該進(jìn)程時(shí),能夠恢復到切換時(shí)的狀態(tài)執行下去。在Linux中,當前進(jìn)程上下文均保存在進(jìn)程的任務(wù)數據結構task_struct中。在發(fā)生中斷時(shí),內核就在被中斷進(jìn)程的上下文中,在內核狀態(tài)下執行中斷服務(wù)例程。但同時(shí)會(huì )保留所有需要用到的資源,以便中斷服務(wù)結束時(shí)能恢復被中斷進(jìn)程的執行。


1.2 進(jìn)程運行狀態(tài)

  一個(gè)進(jìn)程在其生存期內,可處于一組不同的狀態(tài)下,稱(chēng)為進(jìn)程狀態(tài)。見(jiàn)下圖2-6所示。進(jìn)程狀態(tài)保存在進(jìn)程任務(wù)結構的state字段中。當進(jìn)程正在等待系統中的資源而處于等待狀態(tài)時(shí),則稱(chēng)其處于睡眠等待狀態(tài)。在Linux系統中,睡眠等待狀態(tài)被分為可中斷的和不可中斷的等待狀態(tài)。


運行狀態(tài)(TASK_RUNNING)

  當進(jìn)程正在被CPU執行,或已經(jīng)準備就緒隨時(shí)可以由調度程序執行,則稱(chēng)該進(jìn)程為處于運行狀態(tài)(running)。進(jìn)程可以在內核態(tài)運行,也可以在用戶(hù)態(tài)運行。當系統資源已經(jīng)可用時(shí),進(jìn)程就被喚醒而進(jìn)入準備運行狀態(tài),該狀態(tài)稱(chēng)為就緒態(tài)。這些狀態(tài)在內核中表示方法相同,都被稱(chēng)為處于TASK_RUNNING狀態(tài)。


可中斷睡眠狀態(tài)(TASK_INTERRUPTIBLE)

  當進(jìn)程處于可中斷等待狀態(tài)時(shí),系統不會(huì )調度該進(jìn)程執行。當系統產(chǎn)生一個(gè)中斷或者釋放了進(jìn)程正在等待的資源,或者進(jìn)程收到一個(gè)信號,都可以喚醒進(jìn)程轉換到就緒狀態(tài)(運行狀態(tài))。


不可中斷睡眠狀態(tài)(TASK_UNINTERRUPTIBLE)

  與可中斷睡眠狀態(tài)類(lèi)似。但處于該狀態(tài)的進(jìn)程只有被使用wake_up()函數明確喚醒時(shí)才能被轉換到可運行就緒狀態(tài)。


暫停狀態(tài)(TASK_STOPPED)

  當進(jìn)程收到信號SIGSTOP,SIGTSTP,SIGTTIN或SIGTTOU時(shí)就會(huì )進(jìn)入暫停狀態(tài)??上蚱浒l(fā)送SIGCONT信號讓進(jìn)程轉換到可運行狀態(tài)。在Linux0.11中,還為實(shí)現對該狀態(tài)的轉換處理。處于該狀態(tài)的進(jìn)程將被作為進(jìn)程終止來(lái)處理。


僵死狀態(tài)(TASK_ZOMBIE)

  當進(jìn)程已停止運行,但其父進(jìn)程還沒(méi)有詢(xún)問(wèn)其狀態(tài)時(shí),則稱(chēng)該進(jìn)程處于僵死狀態(tài)。


當一個(gè)進(jìn)程的運行時(shí)間片用完,系統就會(huì )使用調度程序強制切換到其他的進(jìn)程去執行。另外,如果進(jìn)程在內核態(tài)執行時(shí)需要等待系統的某個(gè)資源,此時(shí)該進(jìn)程就會(huì )調用sleep_on()或者sleep_on_interruptible()自愿放棄CPU使用權,而讓調度程序去執行其他程序。進(jìn)程則進(jìn)入睡眠狀態(tài)(TASK_UNINTERRUPTIBLE或TASK_INTERRUPTIBLE)。

  只有當進(jìn)程從"內核運行態(tài)"轉移到"睡眠狀態(tài)"時(shí),內核才會(huì )進(jìn)行進(jìn)程切換操作。在內核態(tài)下運行的進(jìn)程不能被其他進(jìn)程搶占,而且一個(gè)進(jìn)程不能改變另一個(gè)進(jìn)程的狀態(tài)。為了避免進(jìn)程切換時(shí)造成內核數據錯誤,內核在執行臨街區代碼時(shí)禁止一切中斷。


1.3 進(jìn)程初始化

  在boot/目錄中引導程序把內核從磁盤(pán)上加載到內存中,并讓系統進(jìn)入保護模式下運行后,就開(kāi)始執行系統初始化程序init/main.c。該程序首先確定如何分配使用系統物理內存,然后調用內核各部分的初始化函數分別對內存管理,中斷處理,塊設備和字符設備,進(jìn)程管理以及硬盤(pán)和軟盤(pán)硬件進(jìn)行初始化處理。在完成了這些操作之后,系統各部分已經(jīng)處于可運行狀態(tài)。此后程序把自己"手工"移動(dòng)到任務(wù)0(進(jìn)程0)中運行,并使用fork()調用首次創(chuàng )建出進(jìn)程1。在進(jìn)程1種程序將繼續進(jìn)行應用環(huán)境的初始化并執行shell登陸程序。而原進(jìn)程0則會(huì )在系統空閑時(shí)被調度執行,此時(shí)任務(wù)0僅執行pause()系統調用,并又會(huì )調用調度函數。

  "移動(dòng)到任務(wù)0種執行"這個(gè)過(guò)程由宏move_to_user_mode(include/asm/system.h)完成。它把main.c程序執行流從內核態(tài)(特權級0)移動(dòng)到了用戶(hù)態(tài)(特權級3)的任務(wù)0種繼續運行。在移動(dòng)之前,系統在對調度程序的初始化過(guò)程(sched_init())中,首先對任務(wù)0的運行環(huán)境進(jìn)行的設置。這包括人工預先設置好 任務(wù)0數據結構各字段的值(include/linux/shed.h),在全局描述符中添入任務(wù)0的任務(wù)狀態(tài)段(TSS)描述符和局部描述符表(LDT)的段描述符,并把它們分別加載到任務(wù)寄存器tr和局部描述符表寄存器ldtr中。

  這里需要強調的是,內核初始化是一個(gè)特殊過(guò)程,內核初始化代碼也即是任務(wù)0的代碼。從任務(wù)0數據結構中設置的初始化數據可知,任務(wù)0的代碼段和數據段的基址是0,段限長(cháng)是640KB。而內核代碼段和數據段的基地址時(shí)0,段限長(cháng)是16MB,因此任務(wù)0的代碼段和數據段分別包含在內核代碼段和數據段中。內核初始化程序main.c也即是任務(wù)0中的代碼,只是在移動(dòng)到任務(wù)0之前系統正以?xún)群藨B(tài)特權級0運行著(zhù)main.c程序。宏move_to_user_mode的功能就是把運行特權級內核態(tài)的0級變換到用戶(hù)態(tài)的3級,但是仍然繼續執行原來(lái)的代碼指令流。

  在移動(dòng)到任務(wù)0的過(guò)程中,宏move_to_user_mode使用了中斷返回指令造成特權級改變的方法。該方法的主要思想是在對站中構筑中斷返回指令需要的內容,把返回地址的段選擇符設置成任務(wù)0代碼段選擇符,其特權級為3。此后執行中斷返回指令iret時(shí)將導致系統CPU從特權級0跳轉到外層的特權級3上運行。參見(jiàn)下圖所示的特權級發(fā)生變化時(shí)中斷返回堆棧結構示意圖。


         宏move_to_user_mode首先往內核堆棧中壓入任務(wù)0數據段選擇符和內核堆棧指針。然后壓入標志寄存器內容。最后壓入任務(wù)0代碼段選擇符合執行中斷返回后需要執行的下一條指令的偏移位置。該偏移位置是iret后的一條指令處。

  當執行iret指令時(shí),CPU把返回地址送入CS:EIP中,同時(shí)探出對站中標志寄存器內容。由于CPU判斷出墓地代碼段的特權級是3,與當前內核態(tài)的0級不同。于是CPU會(huì )把堆棧中的堆棧段選擇符合堆棧指針彈出到SS:ESP中。由于特權級發(fā)生了變化,段寄存器DS,ES,FS和GS的值變得無(wú)效,此時(shí)CPU會(huì )把這些段寄存器清零。因此在執行了iret指令后需要重新加載這些段寄存器。此后,系統就開(kāi)始特權級3運行在任務(wù)0的代碼上。所使用的用戶(hù)態(tài)堆棧還是原來(lái)在移動(dòng)之前使用的堆棧。而其內核態(tài)堆棧則被指定為其任務(wù)數據解噢股所在頁(yè)面的頂端開(kāi)始(PAGE_SIZE+(long)&init_task)。由于以后在創(chuàng )建新進(jìn)程時(shí),需要復制任務(wù)0的任務(wù)數據結構,包括其用戶(hù)堆棧指針,因此需要任務(wù)0的用戶(hù)態(tài)堆棧在創(chuàng )建任務(wù)1(進(jìn)程1)之前保持"干凈"狀態(tài)。


1.4 創(chuàng )建新進(jìn)程

  Linux系統中創(chuàng )建新進(jìn)程使用fork()系統調用。所有進(jìn)程都是通過(guò)復制進(jìn)程0而得到的,都是進(jìn)程0的子進(jìn)程。

  在創(chuàng )建新進(jìn)程的過(guò)程中,系統首先在任務(wù)數組中找出一個(gè)還沒(méi)有被任何進(jìn)程使用的空項(空槽)。如果系統已經(jīng)有64個(gè)進(jìn)程在運行,則fork()系統調用會(huì )因為任務(wù)數組表中沒(méi)有可用空項而出錯返回。然后系統為新建進(jìn)程在主內存區中申請一頁(yè)內存來(lái)存放其任務(wù)數據結構信息,并復制當前進(jìn)程任務(wù)數據結構中所有內容作為新進(jìn)程人物數據結構的模板。為了防止這個(gè)還未處理完成的新進(jìn)程被調度函數執行,此時(shí)應該立刻將新進(jìn)程狀態(tài)置為不可中斷的等待狀態(tài)(TASK_UNINTERRUPTIBLE)。

  隨后對復制的任務(wù)數據結構進(jìn)行修改。把當前進(jìn)程設置為新進(jìn)程的父進(jìn)程,清除信號位圖并復位新進(jìn)程各統計值,并設置初始運行時(shí)間片值為15個(gè)系統嘀嗒數(150ms)。接著(zhù)根據當前進(jìn)程設置任務(wù)狀態(tài)段(TSS)中各寄存器的值。由于創(chuàng )建進(jìn)程時(shí)新進(jìn)程返回值應為0,所以需要設置tss.eax=0。新建進(jìn)程內核態(tài)堆棧指針tss.esp0被設置成新進(jìn)程任務(wù)數據結構所在內存頁(yè)面的頂端,而堆棧段tss.ss0被設置成內核數據段選擇符。tss.ldt被設置為局部表描述符在GDT中所引值。如果當前進(jìn)程使用了協(xié)處理器,把還需要協(xié)處理器的完整狀態(tài)保存到新進(jìn)程的tss.i387結構中。

  此后系統設置新任務(wù)的代碼和數據段基址,限長(cháng)并輔之當前進(jìn)程內存分頁(yè)管理的頁(yè)表。如果父進(jìn)程中也有文件是打開(kāi)的,則應將對應文件的打開(kāi)次數增1。接著(zhù)在GDT中設置新任務(wù)的TSS和LDT描述符項,其中基地址信息指向新進(jìn)程人物結構中的tss和ldt。最后再將新任務(wù)設置成可運行狀態(tài)并返回新進(jìn)程號。


1.5 進(jìn)程調度

  由前面描述可知,Linux進(jìn)程是搶占式的。被搶占的進(jìn)程仍然處于TASK_RUNNING狀態(tài),只是暫時(shí)沒(méi)有被CPU運行。進(jìn)程的搶占發(fā)生在進(jìn)程處于用戶(hù)態(tài)執行階段,在內核執行時(shí)是不能被搶占的。

  為了能讓進(jìn)程有效地使用系統資源,又能使進(jìn)程有較快的響應時(shí)間,就需要對進(jìn)程的切換調度采用一定的調度策略。在Linux0.11中采用了基于優(yōu)先級排隊的調度策略。

  調度程序:  

  schedule()函數首先掃描任務(wù)數組。通過(guò)比較每個(gè)就緒態(tài)(TASK_RUNNING)任務(wù)的運行時(shí)間遞減滴答計數counter的值來(lái)確定當前哪個(gè)進(jìn)程運行時(shí)間最少。哪一個(gè)的值大,就表示運行時(shí)間還不長(cháng),于是就選中該進(jìn)程,并使用任務(wù)切換宏函數切換到該進(jìn)程運行。

  如果此時(shí)所有處于TASK_RUNNING狀態(tài)進(jìn)程的時(shí)間片已經(jīng)用完,系統就會(huì )根據每個(gè)進(jìn)程的優(yōu)先權值priority,對系統中所有進(jìn)程(包括正在睡眠的進(jìn)程)重新計算每個(gè)任務(wù)需要運行的時(shí)間片值counter。

  計算公式是:  counter= counter/2 + priority

  然后schedule()函數重新掃描人物數組中所有處于TASK_RUNNING狀態(tài),重復上述過(guò)程,直到選擇出一個(gè)進(jìn)程位置。最后調用switch_to()執行實(shí)際的進(jìn)程切換操作。

  如果此時(shí)沒(méi)有其他進(jìn)程可運行,系統就會(huì )選擇進(jìn)程0運行。對于linux0.11來(lái)說(shuō),進(jìn)程0會(huì )調用pause()把自己置為可中斷的睡眠狀態(tài)并在此調用schedule()。不過(guò)在調度進(jìn)程運行時(shí),schedule()并不在意進(jìn)程0處于什么狀態(tài)。只要系統空閑就調度進(jìn)程0運行。

  進(jìn)程切換:

  執行實(shí)際進(jìn)程切換的任務(wù)由switch_to()宏定義的一段匯編代碼完成。在進(jìn)行切換之前,switch_to()首先檢查要切換到的進(jìn)程是否就是當前進(jìn)程,如果是則什么也不做,直接退出。否則就首先把內核全局變量current置為新任務(wù)的指針,然后長(cháng)跳轉到新任務(wù)的任務(wù)狀態(tài)段TSS組成的地指處,造成CPU執行任務(wù)切換操作。此時(shí)CPU會(huì )把其所有寄存器的轉改保存到當前人物寄存器TR中TSS段選擇符所指向的當前進(jìn)程任務(wù)數據結構的tss結構中,然后把新任務(wù)狀態(tài)段選擇符所指向的新任務(wù)數據結構中tss結構中的寄存器信息恢復到CPU中,系統就正式開(kāi)始運行新切換的任務(wù)了。這個(gè)過(guò)程可參考下圖



1.6 終止進(jìn)程

  當一個(gè)進(jìn)程結束了運行或在半途中終止了運行,那么內核就需要釋放該進(jìn)程所占用的系統資源。這包括進(jìn)程運行時(shí)打開(kāi)的文件,申請的內存等。

  當一個(gè)用戶(hù)程序調用exit()系統調用時(shí),就會(huì )執行內核函數do_exit()。該函數會(huì )首先釋放進(jìn)程代碼段和數據段占用的內存頁(yè)面,關(guān)閉進(jìn)程打開(kāi)著(zhù)的所有文件,對進(jìn)程使用的當前工作目錄,根目錄和運行程序的i節點(diǎn)進(jìn)行同步操作。如果進(jìn)程有子進(jìn)程,則讓init進(jìn)程作為其所有子進(jìn)程的父進(jìn)程。如果進(jìn)程是一個(gè)會(huì )話(huà)頭進(jìn)程并且有控制終端,則釋放控制終端,并向屬于該會(huì )話(huà)的所有進(jìn)程發(fā)送掛斷信號SIGHUP,這通常會(huì )終止該會(huì )話(huà)中的所有進(jìn)程。然后把進(jìn)程狀態(tài)置為僵死狀態(tài)TASK_ZOMBIE。并向其原父進(jìn)程發(fā)送SIGCHILD信號,通知其某個(gè)子進(jìn)程已經(jīng)終止。最后do_exit()調用調度函數去執行其他進(jìn)程。由此可見(jiàn)在進(jìn)程終止時(shí),它的task_struct任務(wù)數據結構仍然保留著(zhù)。因為其父進(jìn)程還需要使用其中的信息。

  在子進(jìn)程在執行期間,父進(jìn)程通常使用wait()或waitpid()函數等待其某個(gè)子進(jìn)程終止。當子進(jìn)程被終止并處于僵死狀態(tài)時(shí),父進(jìn)程就會(huì )把子進(jìn)程運行所使用的時(shí)間累加到自己進(jìn)程中。最終釋放已終止子進(jìn)程任務(wù)數據結構所占用的內存頁(yè)面,并置空子進(jìn)程在任務(wù)數組中占用的指針項。

轉載:

http://www.cnblogs.com/hongzg1982/articles/2112224.html


本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Linux內核模式
進(jìn)程調度
Linux進(jìn)程-進(jìn)程的創(chuàng )建
Linux內核中的init
Linux內核CFS調度器:實(shí)現高效多任務(wù)處理
進(jìn)程上下文意思
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久