Understanding uC/OS-II (1)



    -- Real-Time Systems Concepts







Foreground/Background Systems



  • The system consists of an infinite loop which calls modules (functions) to perform jobs. (a super loop)

    • The background (task level).


  • Interrupt Service Routines (ISRs) handle asynchronous events.>

    • The foreground (interrupt level).


圖 1







Operating System (O.S.)



  • resource management


所謂的 OS 包含有…



圖 2




Hard & Soft Real-Time Issue



  • A hard real-time system is a real-time system that must meet its deadlines with a near-zero degree of flexibility. The deadlines must be met, or catastrophes occur.
  • A soft real-time system is a real-time system that must meet its deadlines but with a degree of flexibility. The deadlines can contain varying levels of tolerance, average timing deadlines, and even statistical distribution of response times with different degrees of acceptability.





Kernel 在做什麼?


在多工系統中,kernel 負責管理各個 task,或者可以說為每個 task 分配 CPU 時間,並且負責 task 之間的溝通。kernel 提供的基本服務是 context switch(or task switch)。之所以使用 real time kernel 可以大大簡化應用系統的設計,是因為 real time kernel 允許將”應用”分成若干個 task,由 real time kernel 來管理它們。kernel 本身也增加了應用程式的額外負荷,程式空間增加 ROM 的用量, kernel 本身的資料結構增加了 RAM 的用量。但更主要的是,每個 task 要有自己的 stack 空間,這一塊吃起記憶體來是相當厲害的。Single-chip 一般不能執行 real time kernel,是因為 single-chip 的 RAM 很有限。real time kernel 透過提供不可缺少的系統服務,如 semaphore management、mailboxes、queues、time delays 等,使得 CPU 的利用更為有效。




什麼是 Scheduler?


排程器 (Scheduler),這是 kernel 的主要職責之一,就是要決定該輪到哪個 task 執行了。多數 real time kernel 是基於優先權排程法。每個 task 根據其重要程度的不同被賦予一定的優先權。而在優先權的處理上有:



  • 靜態優先權 (Static Priorities),應用程式執行過程中各 task 優先權不變,則稱為靜態優先權。
  • 動態優先權 (Dynamic Priorities),應用程式執行過程中,task 的優先權是可變的,則稱之為動態優先權。
  • 時間片調度 (Round-Robin Scheduling or time slicing),是說當兩個或兩個以上 task 有同樣優先權,kernel 允許一個 task A 執行一段時間,然後切換給 task B。


什麼是 Task?


任務 (task),亦稱作執行緒 (thread),簡單的說是一個程式,該程式可以認為 CPU 完全只屬該程式自己,而且它自己擁有一套 CPU's register 和自己的 stack 空間。一般而言、每個 task 都是一個無限的迴圈。而每個 task 都會有幾種狀態,我們將它稱之為 task status,隨著使用的 kernel 不同,task status 的狀態數目及狀態的名稱都會不同,以 uCOS 為例,它總共有 5 種狀態分別是休眠態 (DORMANT)、就緒態 (READY)、執行態 (RUNNING)、等候態 (WAITING)和被中斷態 (ISR)。




Non-Preemptive Kernels



  • 不可剝奪型內核要求每個 task 自我放棄 CPU 的所有權。
  • Non-preemptive scheduling 也稱作合作型多工,各個 task 彼此合作共用一個 CPU。
  • 非同步事件還是由中斷服務來處理。中斷服務可以使一個高優先權的 task 由等候狀態變為就 ready status。但中斷服務以後控制權還是回到原來被中斷了的那個 task,直到該 task 主動放棄 CPU 的使用權時,那個高優先權的 task 才能獲得 CPU 的使用權。
  • Non-preemptive kernel 的一個優點是回應中斷快。另一個優點是,幾乎不需要使用 semaphore 保護共用資料。
  • 以 thread/task 的角度,non-preemptive kernel 允許使用 non-reentrant function, non-reentrant function 也稱作不可重入函數。每個 task 都可以呼叫 non-reentrant function,而不必擔心其他 task 可能正在使用該函數,從而造成資料的破壞。因為每個 task 要執行到完成時才釋放 CPU 的控制權。當然該 non-reentrant function 本身不得有放棄 CPU 控制權的企圖。
  • Non-preemptive kernel 的最大缺陷在於其response time。高優先權的 task 已經進入就緒態,但還不能執行,要等,也許要等很長時間,直到當前執行著的 task 釋放 CPU。Non-preemptive kernel 的 task response time 是不確定的,不知道什麼時候最高優先權的 task 才能拿到 CPU 的控制權,完全取決於應用程式什麼時候釋放 CPU。


圖 3


總之,non-preemptive kernel 允許每個 task 執行,直到該 task 自願放棄 CPU 的控制權。中斷可以打斷正在執行著的 task。 ISR 完成以後將 CPU 控制權還給被中斷了的 task。Task's response time 是不可預知的,商業軟體幾乎沒有 non-preemptive kernel。




Preemptive Kernels



  • 當系統 response time 很重要時,則要使用 preemptive kernel。而絕大多數商業上銷售的 real time kernel 都是 preemptive kernel。
  • Preemptive scheduling 也稱作強制型多工,各個 task 彼此爭奪一個 CPU 的控制權。
  • 最高優先權的 task 一旦就緒,總是能得到 CPU 的控制權。當一個正在執行的 task 使一個比它優先權高的 task 進入了 ready status,目前的 task 則進入 waiting status,而那個高優先權的 task 立刻得到了CPU的控制權。如果是 ISR 使一個高優先權的 task 進入 ready status,當中斷完成時,被中斷的 task 進入 waiting status,優先權高的那個 task 開始 running。
  • 使用 preemptive kernel,最高優先權的 task 什麼時候可以執行,可以得到 CPU 的控制權是可預知的。使用 preemptive kernel 使得 task's response time 得以最佳化。
  • 使用 preemptive kernel 時,應用程式不應直接使用 non-reentrant function。 呼叫 non-reentrant function 時,要滿足互斥條件,這一點可以用互斥型的 semaphore 來實現。如果呼叫 non-reentrant function 時,低優先權 task 的 CPU 使用權會被高優先權 task 剝奪,則 non-reentrant function 中的資料有可能被破壞。


圖 4


結論,preemptive kernel 總是讓 ready status 的高優先權的 task 先執行,ISR 可以搶佔 CPU,到 ISR 完成時,kernel 讓此時優先權最高的 task 執行 (不一定是那個被中斷了的 task)。Task's response time 得到了最佳化,且是可預知的。




Context Switch (Task Switch)



  • 它發生在當 scheduler 決定去執行不同的 task 時。
  • scheduler 必須儲存目前處於 running 的 task 的 context,並將要進入 running 的 task 的 context 載入。

    • context 是相當重要的資料,其包含 CPU's registers 的內容,stack 的 pointer,以及有關維持運作的資料

  • Context-switches 增加了在執行 task 的 overheads。

    • 一個適用的 scheduler 必須不可太過密集的做 context switches。這是因為近代的 CPU 有著較深的 instruction pipelines 以及較多的 registers。

  • 對於一個 Real-Time Operating System (RTOS),我們能知道執行 context switch 需要多少時間。

    • context switch 的所產生的 overheads 是切換進入 high priority tasks 的花費。


圖 5



圖 6



圖 7




Reentrant Functions (可重入函式)



  • Reentrant functions 能被同時執行而不會造成資料錯誤。
  • Reentrant functions 使用 local variables (on stacks) 或者 同步機制 (such as semaphores)

[example]:

char *xstrcpy(char *dest, const char *src)
{
char *tmp = dest;

while ((*dest++ = *src++) != '\0')
; /* nothing */

return tmp;
}


Non-Reentrant Functions (不可重入函式)



  • Non-Reentrant functions 會在 shared resources 上發生 race conditions的現象,而使資料發生錯誤。

[example]:

int Temp;
void swap(int *x, int *y)
{
Temp = *x;
*x = *y;
*y = Temp;
}


圖 5



  • There are several ways to make the code reentrant:

    • Declare Temp as a local variable.
    • Disable interrupts and then enable interrupts.
    • Use a semaphore or spin lock.


Task Priority



  • Static Priorities

    • 當每個 task 的優先權不在應用的執行期間改變時,我們稱 task 的優先權是靜態的。
    • 每個 task 是在 compile time 給予固定的優先權。因為全部的 task 及他們的 timing 限制條件在 compile time 已經是已知的。

  • Dynamic Priorities

    • 如果 task 的優先權可以在應用的執行期間改變,我們稱 task 的優先權是動態的。
    • 每個 task 是在執行期間能改變它的優先權。但必須去避免優先權倒置的的現象。


Critical Region


Critical Region 的意思是說有某一段程式碼的執行是不能被分割的。其用意是在保護 shared resources 以避免發生 race conditions 的現象,而造成系統錯誤。可以實作下述的方法來達到保護 Critical Region 的目的:



  • enable/disable interrupt.
  • enable/disable scheduling.
  • semaphores.
  • spin lock.


Mutual Exclusion (互斥)


互斥 (Mutual Exclusion) 是用來保護 shared resources,此處所說的 shared resources 包含了 global variables, linked lists, pointers, buffers, ring buffers and I/O devices 等等。因為一般在實現 task 間溝通最簡便的辦法是使用共用資料區。雖然共用資料區法簡化了 task 間的資訊交換,但是必須保證每個 task 在處理共用資料時的排它性,以避免 race conditions 和資料的破壞。所以與共用資源打交道時,使之滿足互斥條件最一般的技巧有:



  • enable/disable interrupt.
  • performing a test-and-set instruction.
  • disabling scheduling.
  • using semaphores or spin lock.

Enable/Disable Interrupt

處理共用資料時保證互斥,最簡便快捷的辦法是關中斷和開中斷。



  • Disable interrupts;
  • Access the resource (read/write from/to variables);
  • Reenable interrupts;

可是,必須十分小心,disable interrupt 的時間不能太長。因為它影響整個系統的中斷回應時間,即中斷延遲時間。當改變或複製幾個變數的值時,要想到用這種方法來做。這也是在中斷服務副程式中處理共用變數或共用資料結構的唯一方法。在任何情況下,disable interrupt 的時間都要儘量短。


Test-And-Set Instruction


如果不使用 real-time kernel,當兩個 task 共用一個資源時,一定要先約定好,先測試某一全域變數,如果該變數是 0,就允許該 task 與共用資源打交道。為防止另一個 task 也要使用該資源,前者只要簡單地將全域變數置為 1,這種通常稱作 Test-And-Set,或稱作 TAS。TAS 操作可能是微處理器的單獨一條不會被中斷的指令,或者是在程式中 disable interrupt 做 TAS 操作再 enable interrupt。有的微處理器就有硬體的 TAS 指令 (如 Motorola 68000 系列)。


Disabling And Enabling The Scheduler


將 kernel 的 scheduler 關閉後,兩個或兩個以上的 task 就可以共用資料而不發生 race conditions。注意,此時雖然 task switch 是被禁止了,但中斷還是開著的。如果這時中斷來了,中斷服務副程式會在這 critical section 內立即執行。當中斷服務副程式結束時,儘管有優先權高的 task 已經進入 READY status,但是 kernel 還是返回到原來被中斷了的 task。直到將 scheduler 再度打開。


雖然這種方法是可行的,但應該儘量避免禁止 task switch 之類操作,因為 kernel 最主要的功能就是做 task 的調度與協調。禁止 task switch 顯然與 kernel 設計的初衷相違。


Semaphores (信號量)


semaphore 像是一把鑰匙,task 要執行下去,就得先拿到這把鑰匙。如果 semaphore 已被別的 task 佔用,該 task 只得等候,直到 semaphore 被當前使用者釋放。換句話說,申請 semaphore 的 task 是在說:“把鑰匙給我,如果誰正在用著,我只好等!”


一般來說,對 semaphore 只有三種操作:



  • 初始化 (initialize),也可稱作建立 (create)。
  • 等 semaphore (wait) 也可稱作等候 (pend)。
  • 給 semaphore (signal) 或發信號 (post)。

semaphore 初始化時要給 semaphore 賦予初值,等待 semaphore 的 task 表 (waiting list) 應清為空。想要得到 semaphore 的 task 執行等待 (WAIT) 操作。如果該 semaphore 有效,則 task 得以繼續執行。如果 semaphore 為無效的,等待 semaphore 的 task 就被列入等待 semaphore task 表。大多數的 kernel 允許使用者定義等待 time-out,如果等待時間超過了某一設定值時,該 semaphore 還是無效,則等待 semaphore 的 task 進入 READY 準備執行,並返回錯誤碼。


[example]:

OS_EVENT *SharedDataSem;
void Function (void)
{
INT8U err;

OSSemPend(SharedDataSem, 0, &err);
.
. /* You can access shared data in here (interrupts are recognized) */
. /* 共用資料的處理在此進行,(中斷是開著的) */
OSSemPost(SharedDataSem);
}


Deadlock (鎖死)


是指兩個 task 無限期地互相等待對方控制著的資源。假設 task T1 正獨享資源 R1,task T2 在獨享資源 R2,而此時 T1 又要獨享 R2,T2 也要獨享 R1,於是哪個 task 都沒法繼續執行了,發生了 Deadlock。最簡單的防止發生 Deadlock 的方法是讓每個 task 都:



  • 先得到全部所需要的資源再做下一步的工作。
  • 每個 task 去申請多個資源時,必須有相同的順序。
  • 在釋放資源時,必須使用與上述相反的順序。

kernel 大多允許使用者在申請 semaphore 時定義等待 time-out,以此化解 deadlock。當等待時間超過了某一確定值, semaphore 還是無效狀態,就會回覆某種形式的 time-out 錯誤碼,這個錯誤碼告知該 task,不是得到了資源使用權,而是系統錯誤。




Synchronization


可以利用 semaphore 使某 task 與中斷服務同步 (或者是與另一個 task 同步,這兩個 task 間沒有資料交換)。如圖 9 所示。注意,圖中用一面旗幟,或稱作一個標誌表示 semaphore 。這個標誌表示某一事件的發生 (不再是一把用來保證互斥條件的鑰匙)。用來實現同步機制的 semaphore 初始化成 0, semaphore 用於這種類型同步的稱作單向同步 (unilateral rendezvous)。一個 task 做 I/O 操作,然後等信號回應。當 I/O 操作完成, ISR (或另外一個 task) 發出信號,該 task 得到 semaphore 後繼續往下執行。



圖 9


兩個 task 可以用兩個 semaphore 同步它們的行為。如圖 10 所示。這叫做雙向同步 (bilateral rendezvous)。雙向同步同單向同步類似,只是兩個 task 要相互同步。



圖 10


Event Flags (事件標誌)


當某個 task 要與多個 event 同步時,要使用事件標誌。若 task 需要與任何事件之一發生同步,可稱為獨立型同步 (disjunctive synchronization, 即 logical OR)。task 也可以與所有 event 都發生了才同步,稱之為關聯型 ( conjunctive synchronization, 即 logical AND)。獨立型及關聯型同步如圖 11 所示。



圖 11


可以用多個 event 的組合發信號給多個 task 。如圖 12 所示,一般來說,8 個、16 個或 32 個 event 可以組合在一起,這必須取決於我們用的哪種 kernel。每個 event 占一位元 (bit),以 32 bits 的情況為多。 task 或中斷服務可以給某一位元設置或清除,當 task 所需的 event 都發生了,該 task 繼續執行,至於哪個 task 該繼續執行了,視新的 event 發生時辨定的。


uCOS,支援 event flag 並提供設置 (SET)、清除 (CLEAR) 和等待 (WAIT) 等服務。且 event flag 可以是獨立型或組合型。



圖 12




Intertask communication


有時會需要 task 間的或中斷服務與 task 間的通訊。這種資訊傳遞稱為 intertask communication。 task 間資訊的傳遞有兩個途徑:



  • 通過全域變數
  • 發出信息給另一個 task。

使用全域變數時,必須保證每個 task 或 ISR 獨享該變數。中斷服務中保證獨享的唯一辦法是 disable interrupt。如果兩個 task 共用某個變數,各 task 實現獨享該變數的辦法可以是 disable interrupt 再 enable interrupt,或使用 semaphore (如前面提到的那樣)。


請注意,task 只能通過全域變數與 ISR 通訊,而 task 並不知道什麼時候全域變數被 ISR 修改了,除非 ISR 是以 semaphore 的方式向 task 發信號或者是該 task 以 polling 的方式不斷周期性地查詢變數的值。要避免這種情況,我們可以考慮使用信息郵箱 (message mailbox)信息佇列 (message queue)


Message Mailboxes (信息郵箱)


透過 kernel services 可以給 task 發送消息。典型的信息郵箱也稱作信息交換,是用一個指標型變數,透過 kernel services,一個 task 或一個 ISR 可以把一則信息 (即一個指標) 放到 mailbox 裏去。同樣,一個或多個 task 可以透過 kernel services 接收到這則消息。發送消息的 task 和接收消息的 task 約定,該指標所指向的內容就是那則消息。每個 mailbox 有相應的正在等待消息的 task list,要得到消息的 task 會因為 mailbox 是空的而繼續等候,且被記錄到等待消息的 task list 中,直到收到消息。


一般來說,kernel 允許使用者自行定義等待超時,等待消息的時間超過了,仍然沒有收到該消息,這 task 進入就緒態,並返回錯誤資訊,報告等待超時錯誤。消息放入郵箱後,或者是把消息傳給等待消息的 task list 中優先權最高的那個 task (基於優先權),或者是將消息傳給最先開始等待消息的 task (基於先進先出)。圖 13 示意把消息放入郵箱。用一個I字表示郵箱,旁邊的小砂漏表示超時計時器,計時器旁邊的數位表示計時器設定值,即 task 最長可以等多少個時鐘節拍 (clock ticks),關於 clock tick 以後會講到。而 kernel 一般會提供以下 mailbox 服務:



  • mailbox 內消息的內容初始化,mailbox 裏最初可以有,也可以沒有消息
  • 將消息放入 mailbox (POST)
  • 等待有消息進入 mailbox (PEND)
  • 如果 mailbox 內有消息,就接受這則消息。如果 mailbox 裏沒有消息,則 task 並不等候 (ACCEPT),用返回碼 表示呼叫結果,是收到了消息還是沒有收到消息。

message mailboxes 也可以當作只取兩個值的 semaphore 來用。mailbox 裏有消息,表示資源可以使用,而空郵箱表示資源已被其他 task 佔用。



圖 13


Message Queues (消息佇列)


消息佇列用於給 task 發消息。message queue 實際上是 mailbox的陣列。通過 kernel 所提供的服務, task 或 ISR 可以將一條消息 (該消息的指標) 放入 message queue。同樣,一個或多個 task 可以通過 kernel services 從消息佇列中得到消息。發送和接收消息的 task 約定,傳遞的消息實際上是傳遞的指標所指向的內容。通常,先進入 message queue 的消息先傳給 task,也就是說, task 先得到的是最先進入消息佇列的消息,即先進先出原則 (FIFO)。然而 uCOS 也允許使用後進先出方式 (LIFO)。像使用 mailbox 那樣,當一個以上的 task 要從 message queue 接收消息時,每個 message queue 有一張等待消息 task 的等待列表 (waiting list)。如果 message queue 中沒有消息,即 message queue 是空,等待消息的 task 就繼續等候並放入等待消息 task list 中,直到有消息到來。通常,kernel 允許等待消息的 task 定義等待超時的時間。如果限定時間內 task 沒有收到消息,該 task 就進入就緒態並開始執行,同時返回錯誤碼,指出出現等待超時錯誤。一旦一則消息放入 message queue,該消息將傳給等待消息的 task 中優先權最高的那個 task ,或是最先進入等待消息 task list 的 task 。圖 14 示意 ISR 如何將消息放入消息佇列。圖中兩個大寫的I表示消息佇列,“10”表示消息佇列最多可以放 10 條消息,沙漏旁邊的 0 表示 task 沒有定義超時,將永遠等下去,直至消息的到來。


一般而言,kernel 會提供的 message queue 服務如下:



  • message queue 初始化。佇列初始化時總是清為空。
  • 放一則消息到 queue 中去 (POST)
  • 等待一則消息的到來 (PEND)
  • 如果 queue 中有消息,則 task 可以得到消息,但如果此時 queue 為空,則 task 不等候 (ACCEPT)。如果有消息, 則消息從 queue 中取走。沒有消息則用特別的返回碼通知 caller,queue 中沒有消息。


圖 14




Clock Tick (時鐘節拍)


時鐘節拍是特定的周期性中斷。這個中斷可以看作是系統心臟的脈動。中斷之間的時間間隔取決於不同的應用,一般在 10ms 到 200ms 之間。這個 clock tick 中斷使得 kernel 可以將 task 延時若干個整數 clock tick,以及當 task 等待事件發生時,提供等待 time-out 的依據。clock tick 的頻率越快,系統的額外開銷就越大。


各種 real-time kernel 都有將 task 延時若干個 clock tick 的功能。然而這並不意味著延時的精度是 1 個 clock tick,只是在每個 clock tick 中斷到來時對 task 延時做一次裁決而已。


圖 15 到圖 17 示意 task 將自身延遲一個 clock tick 的時序。陰影部分是各部分程式的執行時間。請注意,相應的程式執行時間是長短不一的,這反映了程式中含有迴圈和條件轉移語句 (即 if/else, switch, ? : 等語句) 的典型情況。clock tick ISR 的執行時間也是不一樣的。儘管在圖中畫得比較誇大。


第一種情況如圖 15 所示,優先權高的 task 和 ISR 超前於要求延時一個 clock tick 的 task 執行。可以看出,雖然該 task 想要延時 20ms,但由於其優先權的緣故,實際上每次延時多少是變化的,這就引起了 task 執行時間的抖動 (jitter)



圖 15


第二種情況,如圖 16 所示,所有高優先權的 task 和 ISR 的執行時間略微小於一個 clock tick。如果 task 將自己延時一個 clock tick 的請求剛好發生在下一個 clock tick 之前,這個 task 的再次執行幾乎是立即開始的。因此,如果要求 task 的延遲至少為一個 clock tick 的話,則要多定義一個延時 clock tick。換句話說,如果想要將一個 task 至少延遲 5 個 clock tick 的話,得在程式中延時 6 個 clock tick。



圖 16


第三種情況,如圖 17 所示,所有高優先權的 task 加上 ISR 的執行時間長於一個 clock tick 。在這種情況下,欲延遲一個 clock tick 的 task 實際上在兩個 clock tick 後開始執行,引起了延遲時間超差。這在某些應用中或許是可以的,然而在多數情況下是不可接受的。



圖 17


上述情況在所有的 real-time kernel 中都會出現,這與 CPU's loading 有關,也可能與系統設計不正確有關。以下是這類問題可能的解決方案:



  • 增加 microprocessor 的 clock rate。
  • 增長 clock tick 的時間。
  • 重新安排 task 的優先權。
  • 避免使用浮點運算 (如果非使用不可,儘量用單精確度數)。
  • 使用有較好最佳化程式的編譯器。
  • 對時間要求苛刻的程式用組合語言寫。
  • 如果可能,用同一家族的更快的 microprocessor 做系統升級。如從8086向80186升級, 從68000向68020升級等。

但不管如何,抖動 (jitter) 總是存在的




interrupts (中斷)


中斷是一種硬體機制,用於通知 CPU 有個非同步事件發生了。中斷一旦被識別,CPU 保存部分 (或全部) 它自己的狀態 (context),即部分或全部暫存器的值,再跳到指定的副程式,我們稱為中斷服務副程式 (Interrupt Service Routine or ISR)。中斷使得 microprocessor 可以在事件發生時才予以處理,而不必讓 microprocessor 經常地查詢 (polling) 是否有事件發生。接下來我們解釋幾個與中斷相關的術語。


Interrupt Latency (中斷延遲)


可能 real-time kernel 最重要的指標就是中斷關了多長時間。所有 real-time system 在進入 critical section 程式段之前都要 disable interrupt,執行完 critical section 的程式之後再 enable inetrrupt。disable interrupt 的時間越長,中斷延遲就越長。



  • Interrupt Latency = disable inetrrupt 的最長時間 + 開始執行 ISR 的第一條指令的時間

Interrupt Response (中斷回應)


中斷回應定義為從中斷發生到開始執行使用者的 ISR 來處理這個中斷的時間。中斷回應時間包括開始處理這個中斷前的全部開銷。一般而言,執行使用者程式碼之前要保存現場,將 CPU 的各暫存器推入堆疊。這段時間將被記作中斷回應時間。



  • 對於 foreground/background system,保存暫存器以後立即執行使用者程式碼。

    • Interrupt Response = Interrupt Latency + 保存CPU內部暫存器的時間


  • 對於 non-preemptive kernel,微處理器保存內部暫存器以後,使用者的 ISR 立即得到執行。

    • Interrupt Response = Interrupt Latency + 保存CPU內部暫存器的時間


  • 對於 preemptive kernel,則要先呼叫一個特定的函式,該函式通知 kernel 即將進行中斷服務,使得 kernel 可以跟蹤 中斷的巢狀。對於 uCOS 說來,這個函式是 OSIntEnter()。

    • Interrupt Response = Interrupt Latency + 保存CPU內部暫存器的時間 + kernel 進入 ISR 前的執行時間

Interrupt Recovery (中斷恢復時間)


中斷恢復時間定義為 microprocessor 返回到被中斷了的程式碼所需要的時間。



  • 在 foreground/background system,中斷恢復時間很簡單,只包括恢復 CPU 內部暫存器值的時間和執行中斷返回指令的時間。

    • Interrupt Recovery = 恢復 CPU 內部暫存器值的時間 + 執行中斷返回指令的時間


  • 在 non-preemptive kernel,中斷恢復時間也很簡單,只包括恢復 CPU 內部暫存器值的時間和執行中斷返回指令的時間。

    • Interrupt Recovery = 恢復 CPU 內部暫存器值的時間 + 執行中斷返回指令的時間


  • 在 preemptive kernel,中斷的恢復要複雜一些。一般而言,在 ISR 的末尾,要呼叫一個由 kernel 提供的函式。 在 uCOS 中,這個函式叫做 OSIntExit(),這個函式是用於判定中斷是否已脫離了所有的巢狀中斷。如果脫離了巢狀 (即已經可以返回到被中斷了的任務級時),kernel 要辨定,由於 ISR 的執行,是否使得一個優先權更高的任務進入 了 READY。如果是,則要讓這個優先權更高的 task 開始執行。在這種情況下,被中斷了的任務只有重新成為優先權 最高的任務而進入 READY 時才能繼續執行。

    • Interrupt Recovery = 判定是否有優先權更高的任務進入了 READY 的時間 + 恢復那個優先權更高任務的 CPU 內部暫存器的時間 + 執行中斷返回指令的時間



圖 18,foreground/background system



圖 19,non-preemptive kernel



圖 20,preemptive kernel

立你斯 發表在 痞客邦 留言(0) 人氣()