μC/OS-II的內(nèi)核結(jié)構
讀者可以看出,任務優(yōu)先級的低三位用于確定任務在總就緒表OSRdyTbl[]中的所在位。接下去的三位用于確定是在OSRdyTbl[]數(shù)組的第幾個元素。OSMapTbl[]是在ROM中的(見文件OS_CORE.C)屏蔽字,用于限制OSRdyTbl[]數(shù)組的元素下標在0到7之間,見表3.1
本文引用地址:http://www.ex-cimer.com/article/201610/305744.htm圖3.3μC/OS-Ⅱ就緒表
如果一個任務被刪除了,則用程序清單3.6中的代碼做求反處理。
程序清單L3.6從就緒表中刪除一個任務
if((OSRdyTbl[prio>>3]=~OSMapTbl[prio0x07])==0)
OSRdyGrp=~OSMapTbl[prio>>3];
以上代碼將就緒任務表數(shù)組OSRdyTbl[]中相應元素的相應位清零,而對于OSRdyGrp,
只有當被刪除任務所在任務組中全組任務一個都沒有進入就緒態(tài)時,才將相應位清零。也
就是說OSRdyTbl[prio>>3]所有的位都是零時,OSRdyGrp的相應位才清零。為了找到那個
進入就緒態(tài)的優(yōu)先級最高的任務,并不需要從OSRdyTbl[0]開始掃描整個就緒任務表,只
需要查另外一張表,即優(yōu)先級判定表OSUnMapTbl([256])(見文件 OS_CORE.C)。OSRdyTbl[]
中每個字節(jié)的8位代表這一組的8個任務哪些進入就緒態(tài)了,低位的優(yōu)先級高于高位。利用
這個字節(jié)為下標來查OSUnMapTbl這張表,返回的字節(jié)就是該組任務中就緒態(tài)任務中優(yōu)先級
最高的那個任務所在的位置。這個返回值在0到7之間。確定進入就緒態(tài)的優(yōu)先級最高的任
務是用以下代碼完成的,如程序清單L3.7所示。
程序清單 L3.7 找出進入就緒態(tài)的優(yōu)先級最高的任務
y=OSUnMapTbl[OSRdyGrp];
x=OSUnMapTbl[OSRdyTbl[y]];
prio=(y3)+x;
例如,如果OSRdyGrp的值為二進制01101000,查OSUnMapTbl[OSRdyGrp]得到的值是
3,它相應于OSRdyGrp中的第3位bit3,這里假設最右邊的一位是第0位bit0。類似地,
如果OSRdyTbl[3]的值是二進制11100100,則OSUnMapTbl[OSRdyTbc[3]]的值是2,即第2
位。于是任務的優(yōu)先級Prio就等于26(3*8+2)。利用這個優(yōu)先級的值。查任務控制塊優(yōu)
先級表OSTCBPrioTbl[],得到指向相應任務的任務控制塊OS_TCB的工作就完成了。
3.5 任務調(diào)度(TaskScheduling)
μC/OS-Ⅱ總是運行進入就緒態(tài)任務中優(yōu)先級最高的那一個。確定哪個任務優(yōu)先級最
高,下面該哪個任務運行了的工作是由調(diào)度器(Scheduler)完成的。任務級的調(diào)度是由函
數(shù)OSSched()完成的。中斷級的調(diào)度是由另一個函數(shù)OSIntExt()完成的,這個函數(shù)將在以
后描述。OSSched()的代碼如程序清單L3.8所示。
程序清單L3.8任務調(diào)度器(theTaskScheduler)
voidOSSched(void)
{
INT8Uy;
OS_ENTER_CRITICAL();
if((OSLockNesting|OSIntNesting)==0){(1)
y=OSUnMapTbl[OSRdyGrp];(2)
OSPrioHighRdy=(INT8U)((y3)+OSUnMapTbl[OSRdyTbl[y]]);(2)
if(OSPrioHighRdy!=OSPrioCur){(3)
OSTCBHighRdy=OSTCBPrioTbl[OSPrioHighRdy];(4)
OSCtxSwCtr++;(5)
OS_TASK_SW();(6)
}
}
OS_EXIT_CRITICAL();
}
μC/OS-Ⅱ任務調(diào)度所花的時間是常數(shù),與應用程序中建立的任務數(shù)無關。如程序清單
中[L3.8(1)]條件語句的條件不滿足,任務調(diào)度函數(shù)OSSched()將退出,不做任務調(diào)度。這
個條件是:如果在中斷服務子程序中調(diào)用OSSched(),此時中斷嵌套層數(shù)
OSIntNesting>0,或者由于用戶至少調(diào)用了一次給任務調(diào)度上鎖函數(shù)OSSchedLock(),使
OSLockNesting>0。如果不是在中斷服務子程序調(diào)用OSSched(),并且任務調(diào)度是允許的,
即沒有上鎖,則任務調(diào)度函數(shù)將找出那個進入就緒態(tài)且優(yōu)先級最高的任務[L3.8(2)],進入
就緒態(tài)的任務在就緒任務表中有相應的位置位。一旦找到那個優(yōu)先級最高的任務,
OSSched()檢驗這個優(yōu)先級最高的任務是不是當前正在運行的任務,以此來避免不必要的任
務調(diào)度[L3.8(3)]。注意,在μC/OS中曾經(jīng)是先得到OSTCBHighRdy然后和OSTCBCur做比
較。因為這個比較是兩個指針型變量的比較,在8位和一些16位微處理器中這種比較相對
較慢。而在μC/OS-Ⅱ中是兩個整數(shù)的比較。并且,除非用戶實際需要做任務切換,在查任
務控制塊優(yōu)先級表OSTCBPrioTbl[]時,不需要用指針變量來查OSTCBHighRdy。綜合這兩項
改進,即用整數(shù)比較代替指針的比較和當需要任務切換時再查表,使得μC/OS-Ⅱ比μC/OS
在8位和一些16位微處理器上要更快一些。
為實現(xiàn)任務切換,OSTCBHighRdy必須指向優(yōu)先級最高的那個任務控制塊OS_TCB,這是
通過將以OSPrioHighRdy為下標的OSTCBPrioTbl[]數(shù)組中的那個元素賦給OSTCBHighRdy來
實現(xiàn)的[L3.8(4)]。接著,統(tǒng)計計數(shù)器OSCtxSwCtr加1,以跟蹤任務切換次數(shù)[L3.8(5)]。
最后宏調(diào)用OS_TASK_SW()來完成實際上的任務切換[L3.8(6)]。
任務切換很簡單,由以下兩步完成,將被掛起任務的微處理器寄存器推入堆棧,然后
將較高優(yōu)先級的任務的寄存器值從棧中恢復到寄存器中。在μC/OS-Ⅱ中,就緒任務的棧結(jié)
構總是看起來跟剛剛發(fā)生過中斷一樣,所有微處理器的寄存器都保存在棧中。換句話說,
μC/OS-Ⅱ運行就緒態(tài)的任務所要做的一切,只是恢復所有的CPU寄存器并運行中斷返回指
令。為了做任務切換,運行OS_TASK_SW(),人為模仿了一次中斷。多數(shù)微處理器有軟中斷
指令或者陷阱指令TRAP來實現(xiàn)上述操作。中斷服務子程序或陷阱處理(Traphardler),
也稱作事故處理(exceptionhandler),必須提供中斷向量給匯編語言函數(shù)OSCtxSw()。
OSCtxSw()除了需要OS_TCBHighRdy指向即將被掛起的任務,還需要讓當前任務控制塊
OSTCBCur指向即將被掛起的任務,參見第8章,移植μC/OS-Ⅱ,有關于OSCtxSw()的更詳
評論