第三章 APO用戶系統類的實現

                                第三章   APO用戶系統類的實現

 
每當寫新一章,前面的章節都要重改;這沒辦法。

      APO系統中一個進程可以在內核態(kernelmode)或用戶態(user mode)下執行,並且分別使用各自獨立的內核態堆棧MSP和用戶態堆棧PSP及各自的PC、寄存器組等;就像有2個CPU一樣,我們可以看作是有2個核;這種32位核,佔IC空間很小;即使集成個千核也沒問題。 APO的CPU核,本質就是小體積的32位核;但外部數據通道是256位的,集成的多功能硬件模塊是64K位的;還有強大運算能力的GPU。CPU寄存器可16位、32位、一行256位(傳送)的方式。 在內核態運行的是內核進程;在用戶態下運行的是用戶進程。有2個CPU線路:內核CPU線路,用戶CPU線路。內核代碼和實時用戶進程運行在內核CPU線路。實時用戶進程、內核中斷服務後半部是在內核調度和運行的內核線程;而內核中斷服務前半部是硬件調度的硬內核線程;關於內核態另文討論。

     軟實時、普通用戶進程則是運行在用戶CPU線路的採用動態優先級調度的用戶進程。用戶堆棧用於進程在用戶態下臨時保存調用函數的參數、局部變量等數據;內核堆棧則含有內核程序執行函數調用時的信息;每個用戶進程都有一個用戶堆棧。通常中斷只是打斷內核線程;用戶進程除了一個消息中斷(用於系統消息通知),和“時鐘滴答”(tick= 10ms)中斷及異常中斷外;在其它硬件中斷時還是繼續運行在用戶CPU線路上。

一、用戶進程(CPU線路)


1、APO將任務主要劃分爲4個狀態:

(1)運行狀態(TASK_RUNNING)。
       當進程正在被CPU執行,則稱該進程處於運行狀態(RUNstate)。若此時進程沒有被CPU執行,又已經完成任務運行前的所有準備工作,但由於具有更高優先權的任務在運行而未執行,在這種狀態下的任務一旦成爲優先權最高的任務,其將被執行;則稱其處於就緒運行狀態(READYstate)。當系統資源已經可用時,進程就被喚醒而進入準備運行狀態,也會進入就緒態(READYstate)。這些狀態在內核中表示方法相同,都被稱爲處於TASK_RUNNING 可運行狀態。

BU8K RUNWT{ // 可運行狀態標誌位圖,共32行。進程進入運行或就緒;相應位置1

  BU256  rtask_RUNNING;   // 軟實時進程的運行狀態標誌位圖

  BU256  task_RUNNING;    // 普通進程的的運行狀態標誌位圖,有31行

  …                      // 全局變量,屬於CPU類屬性區。

}

/*  當start()方法調用時,進程首先進入可運行狀態。從阻塞掛起、睡眠狀態回來後重新設置RUNWT運行狀態標誌位圖的相應位,也返回到可運行狀態。

*/

(2)掛起態(Pend):

      進程需等待某些不可馬上利用的資源而被阻塞的狀態。這時,系統不會調度該進程執行。只有,當系統釋放了進程正在等待的資源,或者進程收到一個相關消息,纔可以喚醒進程轉換到就緒狀態。管理者之間的消息、系統消息、資源消息等等,都是內核消息管理員管理的;給進程發消息、喚醒進程等等都是它的事情。進程掛起時,置進程掛起標誌PRR.pend。它先保存其當前進程的H0-H3行寄存器到內存對應i節點數據區,之後把對應動態優先級值清0,RUNWT運行狀態標誌位圖的相應位被清0,進程不再參與調度;使硬件優先級判斷部件動作,置需調度標誌,安排下一個更高優先級的進程;調用進程切換方法switch。當系統喚醒進程轉換到就緒狀態;則從內存對應i節點數據區COPYJI_inode.counter到對應的動態優先級值位置;並使硬件優先級判斷部件動作。

(3)休眠態(Sleep):

        如果系統不需要某一個進程工作,則這個進程被屏蔽而處於休眠狀態;可以休眠一段時間後再啓動。位圖RUNWT相應位置清0,對應動態優先級值清0。

(4)靜止態(DORMANTstate):
      進程建立,但未開始運行;還沒在其上調用start()方法。

       8K/256= 32E(行)的進程號分配位圖FPWT描述進程號分派標誌。實時進程的進程號在內核管理的位圖;軟實時進程的進程號是0—255,對應第0行位圖; 普通進程的進程號是256—--8K-1,對應第2行到第31行的位圖。打開一個進程,系統會在FPWT位圖尋找一個空閒位並置1,從而爲該進程分配進程號。

BU8K  JIWT{         // 進程號分配位圖,共有32行;

  BU256  rtask_pid; // 第0行對應的是256個軟實時進程的進程號。

  BU256  task_pid; // 第1行起對應的是8K-256個普通進程的進程號;共31行。

…                  // 全局變量,屬於CPU類屬性區。

}


2、進程調度

 
        APO採用了基於動態優先級的搶佔式調度算法。當一進程的優先級變動並進入就緒態時,如果其優先級比當前運行的進程優先級高;內核就會置需調度標誌。當前運行進程的動態優先級,每次“時鐘滴答”(tick= 10ms)都會減一。這時,都會做優先級判斷;而這一優先級判斷過程是硬件實現的,需10個指令週期(10ns)。
 
         當一個進程的運行時間片用完,系統就會使用調度程序強制切換到其他的進程去執行。另外,如果進程需要等待系統的某個資源,此時該進程就會調用CPU.sleep()或自願地放棄CPU的使用權,而讓調度程序去執行其他進程;進程則進入掛起態(Pend)。通常,“時鐘滴答”(tick= 10ms)中斷時;如果需調度標識置1,可搶佔標誌爲1;中斷程序纔會進行進程切換操作。在“可搶佔標誌”爲0時,進程不能被其他進程搶佔。每個進程都有自己的內存空間,一個進程不能改變另一個進程的狀態。

        對於實時進程,APO 採用了兩種調度策略,即先來先服務調度(First-In, First-Out , FIFO )和時間片輪轉調度(Round Robin , RR )。在APO中,FIFO實時進程在內核CPU線路中調度和運行。

      SCHED_FIFO:不同的進程根據靜態優先級進行排隊,誰先準備好運行就先調度誰,並且正在運行的進程不會被終止直到以下情況發生:
(1)被有更高優先級的進程所強佔CPU;
(2)自己因爲資源請求而阻塞;(調用CPU.sleep())。
(3)自己主動放棄CPU(調用CPU.yield())。

     當 policy 的值爲SCHED_FIFO 時,遵守 POSIX1.b 標準的FIFO 調度規則。它會一直運行,直到有一個進程因 I/O 阻塞,或者主動釋放CPU ,或者是 CPU 被另一個具有更高rt_priority 的實時進程搶先。在 APO 實現中,SCHED_FIFO 進程仍然擁有時間片,只有當時間片用完時它們才被迫釋放CPU 。因此,如同 POSIX1.b 一樣,這樣的進程就象沒有時間片 (不是採用分時 ) 一樣運行。 APO中進程仍然保持對其時間片的記錄(不修改 counter )主要是爲了實現的方便。通常會把運行時間較短的進程設置爲FIFO調度策略,把運行時間較長的進程設置爲RR調度策略。

SCHED_RR:

       這種調度策略跟上面的SCHED_FIFO一樣,除了它給每個進程分配一個時間片,時間片到了正在執行的進程就放棄執行;時間片的長度可以通過CPU.get(JI_inode.rr)調用得到。

      SCHED_OTHER調度策略中,調度器總是選擇那個counter值最大的進程來調度執行。從邏輯上分析SCHED_OTHER調度策略存在着調度週期(epoch),在每一個調度週期中,一個進程的counter值的大小影響了當前時刻應該調度哪一個進程來執行,其中priority是一個固定不變的值,在進程創建時就已經確定,它代表了該進程的優先級,也代表這該進程在每一個調度週期中能夠得到的時間片的多少;counter是一個動態變化的值,它反映了一個進程在當前的調度週期中還剩下的時間片。在每一個調度週期的開始,priority的值被賦給counter,然後每次該進程被調度執行時,counter值都減少。當counter值爲零時,該進程用完自己在本調度週期中的時間片,不再參與本調度週期的進程調度。當所有進程的時間片都用完時,一個調度週期結束,然後週而復始。另外可以看出 APO系統中的調度週期不是靜態的,它是一個動態變化的量,比如處於可運行狀態的進程的多少和它們priority值都可以影響一個epoch的長短。可見SCHED_OTHER調度策略本質上是一種比例共享的調度策略,它的這種設計方法能夠保證進程調度時的公平性--一個低優先級的進程在每一個epoch中也會得到自己應得的那些CPU執行時間,另外它也提供了不同進程的優先級區分,具有高priority值的進程能夠獲得更多的執行時間。

      當policy 的值爲 SCHED_OTHER 時,是普通的用戶進程,採用動態優先調度,選擇進程的依據就是進程counter 的大小。進程創建時,優先級 priority 被賦一個初值,一般爲 0~ 8K 之間的數字,這個數字同時也是計數器 counter的初值,就是說進程創建時兩者是相等的。字面上看, priority 是“優先級”、counter 是“計數器”的意思,然而實際上,它們表達的是同一個意思,即進程的“時間片”。priority代表分配給該進程的時間片, counter 表示該進程剩餘的時間片。在進程運行過程中,counter 不斷減少,而 priority 保持不變,以便在counter 變爲 0 的時候(該進程用完了所分配的時間片)對counter 重新賦值。當一個普通進程的時間片用完以後,並不馬上用priority 對 counter 進行賦值,只有所有處於可運行狀態的普通進程的時間片都用完了以後,才用priority 對 counter 重新賦值,這個普通進程纔有了再次被調度的機會。這表明,普通進程在運行過程中,counter 的減小給了其它進程得以運行的機會,直至 counter 減爲 0時才完全放棄對 CPU 的使用,這就相當於優先級在動態變化,所以稱之爲動態優先級調度。時間片的概念和其他操作系統是一樣的,APO 的時間單位也是“時鐘滴答”,只是不同操作系統對一個時鐘滴答的定義不同而已,APO 爲 10ms 。進程的時間片就是指多少個時鐘滴答,內核創建新進程時分配給進程的時間片缺省爲1K tick = 1024ms ~= 1s ,用戶可以通過CPU類的方法調用改變它。

       當policy 的值爲 SCHED_RR 時,表示軟實時進程。最多有256個軟實時進程,每個實時進程都有一個rt_priority,其作用與SCHED_OTHER進程的priority作用一樣。軟實時進程的rt_priority大於等於32K。當SCHED_RR 進程的時間片用到剩下8K後,停止對其調度,也不馬上用rt_priority對counter進行賦值,只有所有處於可運行狀態的軟實時進程的時間片都用到剩下8K了以後,才用rt_priority對counter重新賦值,這個軟實時進程纔有了再次被調度的機會。只要系統中有一個軟實時進程在運行,則任何SCHED_OTHER 進程都不能在CPU 運行。

         每個進程都有優先級priority數值。還沒有創建,即還沒分配進程號的進程其priority是0。所有進程的優先級值構成有512行的數組BU16 [8K] priority; 在CPU類屬性區;數組的下標是進程號。當開始一個新的軟實時進程調度週期時:
COPY.E( counter,priority, #16 );  // 19ns。
當開始一個新的普通進程調度週期時,
COPY.E( counter.256.E, priority.256.E, 496 ); 248ns。
當“時鐘滴答”(tick= 10ms)中斷到來時;用戶進程被打斷,保護現場(保存H0-H3)。進入中斷程序後,當前進程的counter先減一;之後,專用硬件模塊約在10ns判斷出其最大值,並與當前進程的counter(B1H)比較,如大於則連同進程號存到B1寄存器;同時置狀態寄存器的需調度標誌。對數組BU16  counter[8K]中的任一行中的任一字符寫都需要進行硬件判斷最大值及相關操作。counter變化除了每次tick的減一外,進程收到的消息也會對其加一個數;數的大小取決於消息的緊迫性。一個低優先級的進程或許由於鼠標點擊消息而獲得焦點而成爲較高優先級的進程。

動態優先級寄存器區:
BU512E DYV_priority{  // 動態優先級分爲32組,每組有一個組內counter最大值。
BU16 [8K] counter; // 所有的動態優先級佔512行,CPU的字符尋址區:H256---H767。
//  H768---H1023是多功能硬件模塊區;H191—H255爲進程i節點寄存器區域。
//  CPU的片內RAM: H32—H1023共1KE = 8KW = 256K位,全部可字符、字、行尋址。
//  H0-H255的64K位是可尋址的。H0—H31是寄存器區,其中H0-H3是用戶寄存器區。
//  分爲64個Z寄存器R0H、R0L、….R31H、R31L或32個W寄存器R0-R31或1K位。

}

          8K/256= 32E(行)的TWT位圖描述counter減爲 0的時間片用完標誌。第0行是256個軟實時進程的時間片用完標誌位圖。其它行是普通用戶進程的時間片用完標誌位圖。位圖的每一位對應相應進程號的進程,位爲1表示相應進程的時間片未用完。8K位圖的初始狀態全0,進程開始新的週期時,置相應位爲1,counter= priority 。每次tick,當前進程的counter-1。當普通進程counter減爲 0時,清位圖的相應位爲0;如果是軟實時進程,並判斷第0行爲0?如是,置就緒狀態的所有軟實時進程相應時間片用完標誌位圖位爲1,並counter= ty_priority;開始新一輪軟實時進程運行週期。如果是普通進程,並判斷第1行開始的所有位圖行爲0?如是,置就緒狀態的所有普通進程相應時間片用完標誌位圖位爲1,並counter= priority;開始新一輪普通進程運行週期。TWT位圖源自運行位圖RUNWT,每一個已建立需運行的沒被屏蔽的進程其進程號對應的位都爲1。

BU8K TWT{           //  進程的時間片用完標誌位圖, 共32E。

  BU256  rtask_counter8k;  // 軟實時進程的時間片用完標誌位圖

  BU256  task_counter0;    // 普通進程的時間片用完標誌位圖,有31行

  …                      // 全局變量,屬於CPU類屬性區。

}

/*  如果所有進程的時間片用完,就需要重置BU16 counter [8K]數組;COPY指令會耗費256ns的時間,相當於要多花256個指令週期;這會增大時鐘中斷的時間損耗。所以,系統安排一個最後的守護進程ZVHWUWHU;它的進程號是8K-1,優先級就一個時間片。當除它外的所有進程時間片用完時,纔會輪到它運行;它的任務就是:
COPY priority[8K]到counter[8K];重置RUNWT位圖、TWT位圖。
*/

二、進程調度類


待續。。。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章