調度的定義:
調度器,決定了任務的運行順序。uC/OS-III 是一個可搶佔的,基於優先級的內核。根據其重要性每個任務都被分配了一個優先級。uC/OS-III 支持多個任務擁有相同的優先級。
“可搶佔的”意味當事件發生時,如果事件讓高優先級任務被就緒,uC/OS-III 馬上將CPU 的控制權交給高優先級任務。因此,當一個任務提交信號量、發送消息給一個高優先級的任務(若該任務被就緒了),當前的任務就會被停止,更高優先級的任務獲得CPU 的控制權。類似的,當ISR 提交信號量或發送消息給一更高優先級的任務(若該任務被就緒了),那麼中斷返回的時候不會返回到原任務,而是高優先級任務。
一 搶佔式調度
(2)如果中斷使能,指令指針IP 會跳轉到中斷服務程序。
(3)中斷服務程序處理相關的程序,發送信號量或消息給一個高優先級任務。高優先級任務被就緒。
(4)中斷服務程序完成操作後,它將CPU 的控制權還給uC/OS-III。
(5)uC/OS-III 執行相應的操作。
(6)因爲就緒隊列中有一個更重要的任務,uC/OS-III 將不會返回中斷前那個低優先級的任務。而是執行高優先級任務。
(7)開始執行高優先級任務
(8)高優先級任務處理完成後,將CPU 的控制權交給uC/OS-III。
(10)uC/OS-III 轉向執行原先那個低優先級任務。
(11)低優先級任務從被中斷處繼續執行。
(2)當ISR 處理完它的工作時,就把CPU 的使用權交給uC/OS-III。
(3)uC/OS-III 處理一些操作。
(5)uC/OS-III 處理一些操作。
(6) 中斷處理任務將外部消息隊列中的消息移除並重新提交給相應的任務。這樣,就將這個過程消息提交從中斷級變成了任務級。使用這種方法的目的是爲了減小關中斷時間(詳見第9 章)。當消息隊列爲空時,uC/OS-III 將中斷處理任務從就緒隊列中移除,然後執行就緒隊列中的最高優先級任務。
二調度點
如果延時參數不是0,調度發生,調度會在該任務被放入掛起隊列後馬上執行。
當OS???Pend()被調用時。接收到該事件的任務、或超時的任務就會被移出等待隊列。然後調度器選擇就緒列表中優先級最高的任務執行。{移出等待隊列的任務不一定就是就緒狀態,因爲它還可能在停止隊列中,效果是可以疊加的。}
任務可以被取消掛起,若另一個任務調用OS???PendAbort()。當任務被移出等待列表中時調度發生。
新的任務被創建時調度發生。
6 任務被刪除
當一個任務被刪除時調度發生。
7 內核對象被刪除
任務所等待的內核對象被刪除時(事件標誌組、信號量、消息隊列、mutex 都是內核對象),這些任務就可能被就緒。然後調度發生。
8 任務改變自身的優先級或其它任務的優先級
當任務改變自身優先級或其它任務優先級時,調度發生。
9 當任務通過調用 OSTaskSuspend()停止自身
當任務調用OSTaskSuspend()停止自身時,調度發生。
10 任務調用 OSTaskResume()恢復其它停止了的任務
任務調用OSTaskResume()恢復其它停止了的任務時,調度發生。
當退出中斷服務程序時,調度發生。這種情況下,調度器調用OSIntExit()函數開始調度而不是OSSched()。
12 通過調用 OSSchedUnlock()調度器被解鎖
調用OSSchedLock()鎖調度器,調度發生。需要注意的是,鎖調度器可以被嵌套,解鎖次數必須等於加鎖次數。
13 調用OSSchedRoundRobinYield()任務放棄了分配給它的時間片
假定多個任務有相同的優先級,正在運行的任務放棄了分配給它的時間片。調度發生。
14 用戶調用 OSSched()
用戶程序調用OSSched()時,調度發生。若調用OS???Post()函數時設置參數爲了OS_OPT_POST_NO_SCHED,事件在被提交後,不調用調度器。當然,任務可以一次性提交多個事件,但在最後一個事件提交時才調用調度器。{因爲當一個事件被提交時,調度器就會發生調度。所以用戶設置了OS_OPT_POST_NO_SCHED 後,用戶一次性提交多個事件而只發生一次發生調度。}
三 循環輪轉調度
(2)任務3 主動放棄剩下的時間片。
(3)uC/OS-III 恢復任務1,因爲它是隊列中任務3 的下一個任務。
(4)任務1 被執行直到分配給它的時間片到期。
(6)任務3 主動放棄剩下的時間片。
(7)有趣的事情發生了,uC/OS-III 會重新設置任務1 的時間片長度爲4 個時基。但剩餘時間片的計數是每個時基中斷遞減,即在第4 個時基中斷髮生時時間片到期。而任務1 是在時基即將發生時接手的,所以事實上它的時間片會少一個時基。
(8)任務1 執行,uC/OS-III 允許用戶在任務運行時修改時間片的長度(通過OSSchedRoundRobinCfg(),)。這個函數也可以用於開啓或關閉循環輪轉調度。
四 調度的內部實現
(1)任務級調度OSSched()
2)第二步是確保調度器沒有被鎖。如果調度器被鎖,就不能運行調度器,函數馬上返回。
3)OSSched()通過掃描位映像表OSPrioTbl[]找到就緒列表中優先級最高的位。(詳見章節6)
4)確定好優先級後,索引到OSRdyList[]並提取該記錄中的首個TCB(OSRdyList[highest priority].HeadPtr)。到現在爲止,已經知道了哪個任務將要切換爲運行狀態。特別的,OSTCBCurPtr 指向的是當前任務的TCB,OSTCBHighRdyPtr 指向的是將要被切換的TCB。
注意的是,調度時和上下文切換是運行在關中斷的狀態下的。這是必要的因爲這些操作是原子性的。
2)OSInrExit()將OSIntNestingCtr 遞減,若OSIntNestingCtr 不爲0 時則返回。確保該函數是在第一級ISR 中執行。當還有中斷程序未被處理時就不能運行調度器。
3)OSIntExit()檢查調度器是否被鎖。如果被鎖,OSIntExit()不會運行調度器並返回到中斷前的任務。
4)當這是第一級中斷且調度器沒有被鎖時。查找優先級最高的任務。
5)從OSRdyList[]中獲得最高優先級的TCB。
6)如果最高優先級就緒任務不是當前正在運行的任務。uC/OS-III 就執行中斷級的上下文切換。中斷級切換的上文已經在中斷開始時被保存了,它可以直接切換到任務。這些在第8 章中詳細介紹。