摘要:該文從源代碼角度分析了μC/OS-Ⅱ的超時等待機制,指出了其缺陷,即在一定情況下超時時間間隔不準確,在時間間隔到期的情況下,內核仍有可能返回成功,與此同時指出了其改進方向。
關鍵詞:超時等待;資源;任務
中圖分類號:TP316文獻標識碼:A文章編號:1009-3044(2009)33-9267-02
Analysis of the Flaw in Waiting-timeout Mechanism inμC/OS-Ⅱ
XU Jing-feng
(Nanjing Institute of Politics, Nanjing 210003, China)
Abstract: This paper analyses the the mechanism of waiting-timeout in μC/OS-Ⅱ. It shows waiting-timeout of the system is not correct in some cases. A method to improve the mechanism is also provided.
Key words: waiting-timeout; resource; task
μC/OS-Ⅱ是一個著名的嵌入式實時多任務操作系統,現已廣泛應用于各類單片機上。因為其源代碼公開,為專業人員提供了難得的學習機會。本文將根據其源代碼對其超時等待機制進行分析并提出相應的改進方法。
1 超時等待機制的基本原理
在實際使用中,應用程序經常會等待一些系統資源,如信號量,事件標志,消息等。這些等待類型分為三種:
1) 如果不能馬上獲取,則掛起等待;
2) 不管是否能獲取資源,馬上返回,不再等待;
3) 如果不能馬上獲取資源,將進行有限時間的等待,即超時等待。
一般操作系統都會執行以下流程:
1) 如果資源能馬上獲取,系統調用將成功返回。
2) 如果資源不能馬上獲取,操作系統將設置一定時器進行計時,當前任務被掛起并進入該資源的等待隊列中,同時該任務從就緒表中刪除,并讓出CPU的使用權。
3) 如果在指定的時間內資源可以獲取了,定時器馬上停止計時,該任務從等待隊列中刪除并重新回到就緒表中等候調度。
4) 如果定時器到時,該任務從等待隊列中刪除并且重新返回就緒表,系統調用返回超時信息。
操作系統通常會提供任務調用等待時間的入口參數,一般以毫秒為單位,內部則會將其轉化為系統的時鐘滴嗒數tick。每一個tick都會做一系列的工作,包括任務的延遲以及超時等待資源的定時器等相關的檢查操作。一般來講,在指定的時間間隔以外到達的資源和信號被認為是無效的,這也是指定超時時間間隔的原意所在,有些對時間要求苛刻的場合就有這種需求,操作系統必須處理好這方面的問題。
2 μC/OS-Ⅱ超時等待機制的缺陷及改進
下面我們通過分析μC/OS-Ⅱ的源代碼來看一下它的超過等待機制。
假設某任務T超時等待信號量資源R,其時鐘節拍函數OSTimeTick的流程主要如下:
時鐘中斷服務程序在每一個時鐘中斷需要的情況下對任務的延遲進行減1操作,如果任務T的定時時間間隔到期(延遲被減為0),并且任務T沒有附加的掛起操作,任務T就會進入就緒表。然而該函數卻沒有進一步將任務T移出資源R的等待隊列,也就是說此時任務T具有兩個狀態,這兩個狀態從本質上講是矛盾的。雖然任務T此時處于就緒狀態,但未必馬上就能獲得執行權,這取決于任務T的優先級。在任務T沒有被調度執行之前的這段時間內,假設資源R到達了,比如一個中斷服務程序調用了OSSemPost函數,會是什么情況呢?
我們再來分析另一個很重要的函數OSSemPost的流程,其代碼如下:
void OSSemPend(OS_EVENT *pevent,INT16U timeout,INT8U *err)
{
OS_ENTER_CRITICAL();
if(pevent->OSEventType!=OS_EVENT_TYPE_SEM){
OS_EXIT_CRITICAL();
*err=OS_ERR_EVENT_TYPE;
}
if(pevent->OSEventCnt>0){
pevent->OSEventCnt--;
OS_EXIT_CRITICAL();
*err=OS_NO_ERR;
}else if(OSIntNesting>0){
OS_EXIT_CRITICAL();
*err=OS_ERR_PEND_ISR;
}else{
OSTCBCur->OSTCBStat|=OS_STAT_SEM;
OSTCBCur->OSTCBDly=timeout;
OSEventTaskWait(pevent);
OS_EXIT_CRITICAL();
OSSched();
OS_ENTER_CRITICAL();
if(OSTCBCur->OSTCBStatOS_STAT_SEM){ //(1)
OSEventTo(pevent);
OS_EXIT_CRITICAL();
*err=OS_TIMEOUT;
}else{ // (2)
OSTCBCur->OSTCBEventPtr=(OS_EVENT*0);
OS_EXIT_CRITICAL();
*err=OS_NO_ERR;}}}
void OSEventTo(OS_EVENT *pevent)
{if((pevent->OSEventTbl[OSTCBCur->OSTCBY]=~OSTCBCur->OSTCBBitX)==0)
{pevent->OSEventGrp=~OSTCBBitY;}
OSTCBCur->OSTCBStat=OS_STAT_RDY;
v OSTCBCur->OSTCBEventPtr=(OS_EVENT*0);}
在資源R的等待隊列中有等待任務的情況下,等待隊列中最高優先級的任務將從等待隊列中刪除,并且進入就緒表。如果等待隊列中最高優先級任務就是前面講的等待超時的任務T,這相當于任務T又一次進入就緒表,不過只有一次從等待隊列中刪除。任務T獲取了資源,只不過是在超時時間以外獲取的。任務T獲得執行權以后從調度程序返回將運行函數OSSemPend語句(2)處的條件代碼,而此時語句(1)處的條件不成立,任務將到資源隊列中等待。如果任務T由于超時進入就緒態,到T獲得執行權之前,仍沒有獲取到資源R,將運行語句(1)處的條件代碼,由函數OSEventTo()可以看出,直到此時任務T才被從等待隊列中刪除,最后返回超時狀態。
通過分析開放源碼的nucleus內核,發現nucleus在超時到期時執行定時器的一個回調函數,此回調函數馬上將等待任務從等待隊列中刪除,將返回狀態定性為超時。這樣在任務獲得執行權前,即使資源到達,該任務也不會得到。我們若要改進,只需在μC/OS-II時鐘節拍函數里增加代碼將延時期滿的任務從相應的資源等待隊列中刪除即可。這一改進工作很容易實現,內核任務控制塊有指向所等待的信號量、消息等事件控制塊的指針,事件控制塊里有相應的等待表。對于uC/OS-II新引進的事件標志組,任務控制塊有指向相應的等待節點的指針,而等待節點有指向相應事件標志組控制塊的指針,這樣刪除一個等待節點也能進行改進。
3 結論
μC/OS-Ⅱ的超時等待機制,存在著上述的超時時間不嚴格的問題,這是由中斷節拍函數OSTimeTick()造成的,該函數只負責將任務移入就緒表,而不處理相應的等待隊列,對此應通過對等待隊列操作的修改加以改進。
參考文獻:
[1] Labrosse J J.嵌入式實時操作系統μC/OS-Ⅱ[M].邵貝貝,譯.2版.北京:北京航空航天大學出版社,2005.
[2] Cortadella J,Kondratyev A.Task generation and compile-time scheduling for mixed data-controlembedded software[J].Design Automation, 2000,5(9):489-494.