黎斌,林幼珍
(廈門理工學(xué)院 計算機科學(xué)與信息工程學(xué)院,廈門361024)
黎斌(講師)、林幼珍(本科),研究方向為嵌入式應(yīng)用、智能交通。
μC/OS-II是可移植性好、可裁減的搶占式、實時多任務(wù)嵌入式操作系統(tǒng)內(nèi)核,具有代碼量少、安全性高、簡潔易懂的特點。在工業(yè)自動化、交通控制、醫(yī)療儀器、軍事國防、航空航天等領(lǐng)域都有廣泛的應(yīng)用,關(guān)于μC/OS-II嵌入式操作系統(tǒng)各方面的研究也在不斷地深入。
μC/OS-II系統(tǒng)任務(wù)間的同步和通信部分主要通過信號量、互斥信號量、事件標(biāo)志組、消息郵箱、消息隊列等實現(xiàn)。其中,事件標(biāo)志組比信號量、互斥信號量有更豐富的控制功能,事件標(biāo)志組有多個狀態(tài)位,任務(wù)可以等待其中某一個或多個的狀態(tài)位置位(或清零),這些狀態(tài)位對任務(wù)起到阻塞作用,這樣任務(wù)是否能夠進入就緒狀態(tài)就可以由多個條件決定。只有事件標(biāo)志組的相應(yīng)狀態(tài)位滿足任務(wù)的要求,任務(wù)才可以進入就緒狀態(tài),這種機制能夠有效提高系統(tǒng)的穩(wěn)定性。
但在應(yīng)用實踐中,發(fā)現(xiàn)μC/OS-II的事件標(biāo)志組機制存在缺陷,這種缺陷可能導(dǎo)致重要敏感領(lǐng)域的災(zāi)難性后果。
發(fā)現(xiàn)μC/OS-II系統(tǒng)缺陷的工程 Mulflag設(shè)計如下:用戶定義4個任務(wù),其中兩個任務(wù)TaskpostA、TaskpostB優(yōu)先級分別為1和3,負責(zé)向同一事件標(biāo)志組的A、B位置位;另外兩個任務(wù)Taskpend1、Taskpend2優(yōu)先級為2和5,以O(shè)S_FLAG_WAIT_SET_ALL+ OS_FLAG_CONSUME的方式等待這一事件標(biāo)志組的A、B狀態(tài)位。
如圖1所示,在PC平臺上運行該工程,當(dāng)TaskpostB事件標(biāo)志組的狀態(tài)位置位時,喚醒兩個等待的任務(wù)Taskpend1和Taskpend2,優(yōu)先級較高的任務(wù)Taskpend1獲得CPU使用權(quán),事件標(biāo)志組的相關(guān)狀態(tài)位復(fù)位,而優(yōu)先級較低的任務(wù)Taskpend2沒有緊隨其后運行,而是被另一個置位事件標(biāo)志組狀態(tài)位的任務(wù)TaskpostA搶占了CPU使用權(quán)。任務(wù)Taskpend2在任務(wù)TaskpostA之后運行,錯誤地復(fù)位了TaskpostA任務(wù)新置位的事件標(biāo)志組的狀態(tài)位,即該狀態(tài)位還沒發(fā)揮作用就被復(fù)位了。
圖1 工程Mulflag運行圖
μC/OS-II主要通過兩個系統(tǒng)調(diào)用OSFlagPost和OSFlagPend來實現(xiàn)對事件標(biāo)志組的相關(guān)操作。任務(wù)調(diào)用OSFlagPend等待事件標(biāo)志組的事件標(biāo)志位,調(diào)用OSFlag-Post置位(或清零)事件標(biāo)志組的事件標(biāo)志位。
OSFlagPend的工作原理和步驟如下:
① 查看所需的狀態(tài)位是否置位(或清零)。如果條件得到滿足,則判斷是否需要消費事件標(biāo)志組的狀態(tài)位,若是則進行消費操作,并從OSFlagPend正常返回;如果條件得不到滿足,則掛起等待,并且做任務(wù)調(diào)度。
② 任務(wù)在等待狀態(tài)被喚醒后,檢測被喚醒原因,如果是由于等待條件滿足而被喚醒,則判斷是否需要消費事件標(biāo)志組的狀態(tài)位,若是則消費相關(guān)事件標(biāo)志位。
OSFlagPost的工作原理和步驟如下:
① 置位(或清零)相應(yīng)事件標(biāo)志組的狀態(tài)位。
② 若等待鏈表不為空,檢查等待鏈表中的任務(wù),若其所等待的狀態(tài)位都已滿足,則將任務(wù)的等待事件標(biāo)志組狀態(tài)清除,并移出等待鏈表;若任務(wù)狀態(tài)已就緒,將其加入任務(wù)就緒表。
③ 根據(jù)移出的任務(wù)狀態(tài)決定是否做任務(wù)調(diào)度。
當(dāng)系統(tǒng)有任務(wù)執(zhí)行,OSFlagPost函數(shù)對事件標(biāo)志組的事件標(biāo)志進行置位(或清零)時,若等待鏈表不為空,則遍歷等待鏈表,將所有條件得到滿足的任務(wù)移出該鏈表,并進行系統(tǒng)調(diào)度。若有多個任務(wù)被移出等待列表,那么這些被喚醒的任務(wù)都會執(zhí)行復(fù)位事件標(biāo)志組的標(biāo)志位的操作。但是,在這些被喚醒任務(wù)得以執(zhí)行前存有一個時間窗口,這個時間窗口會導(dǎo)致新的Post任務(wù)對標(biāo)志組的操作被錯誤地復(fù)位。時間窗口產(chǎn)生的原因有兩個:一是其他高優(yōu)先級的Post任務(wù)可能搶占CPU而先于被喚醒的Pend任務(wù)運行;二是如果Pend任務(wù)在等待期間被其他任務(wù)掛起,則所請求條件得到滿足后依然處于未就緒狀態(tài),那么Pend任務(wù)在恢復(fù)運行前還可能被其他低優(yōu)先級的Post任務(wù)插入運行。
如圖2所示,任務(wù)TaskpostB喚醒任務(wù)Taskpend1、Taskpend2之后,存在時間窗口1、2,隨時可能有新的Post任務(wù)插入運行,事件標(biāo)志組的事件標(biāo)志位有被重新置位或清零的可能性,而這些新設(shè)置的標(biāo)志位將會被后面運行的Pend任務(wù)錯誤地復(fù)位。
從事件標(biāo)志組缺陷形成的原因看,主要是時間窗口的存在造成的,故消除時間窗口成為解決問題的關(guān)鍵。時間窗口的形成主要是因為從事件標(biāo)志組等待鏈表中刪除任務(wù)和消費任務(wù)標(biāo)志位兩個操作分別屬于OSFlagPost和OSFlagPend兩個函數(shù),如果把消費任務(wù)標(biāo)志位操作移至OSFlagPost當(dāng)中,則時間窗口就得以消除。
OSFlagPend函數(shù)的示意性代碼如下:
其中對第③部分的代碼處理如下:
圖2 缺陷原因解析圖
OSFlagPost函數(shù)的示意性代碼如下:
第(3)部分遍歷等待鏈表的while循環(huán)的起始位置插入如下代碼,以判斷該任務(wù)是否需要做消費操作,并把消費標(biāo)志從waitType中剔除:
在第(3)部分,while循環(huán)的switch語句內(nèi)的每一個case分支中添加一段代碼,若該任務(wù)需要做消費操作,則將需要復(fù)位的事件標(biāo)志組的相關(guān)標(biāo)志位保存在flags_consume變量中:
在第(3)部分中while循環(huán)之后插入一段代碼,對所有滿足條件的任務(wù)進行統(tǒng)一的消費操作:
將發(fā)現(xiàn)缺陷的工程Mulflag在修改后的內(nèi)核代碼下再次運行,不再出現(xiàn)之前所述的錯誤,修改內(nèi)核后任務(wù)運行時序圖如圖3所示。任務(wù)TaskpostB在置位并喚醒任務(wù)Taskpend1、Taskpend2后,及時復(fù)位相關(guān)的標(biāo)志位,而被喚醒的Taskpend1、Taskpend2任務(wù)不再執(zhí)行復(fù)位操作。在時間窗口中插入運行的Post任務(wù)所做的置位操作,不會再被錯誤復(fù)位。
該解決方案沒有改動事件標(biāo)志組的數(shù)據(jù)結(jié)構(gòu),僅修改了OSFlagPend和OSFlagPost兩個函數(shù),并且兩個函數(shù)的接口也沒有變動,修改只涉及到μC/OS-II系統(tǒng) 內(nèi)核源碼的OS_FLAG.C文件。其中,OSFlagPend只是注釋掉了部分源碼,所在的臨界區(qū)大幅縮短,提高了系統(tǒng)的實時性。而OSFlagPost函數(shù)中新增加的代碼量只占到所在臨界區(qū)代碼量的1/5,對實時性影響也很小。μC/OS-II的現(xiàn)有工程只需在修改后的內(nèi)核源碼上重新編譯即可正常運行,兼容性強。該方案從根源上對事件標(biāo)志組存在的不足進行改進,直接、徹底地解決了存在的問題,可行性較強。
圖3 修改內(nèi)核后任務(wù)運行時序圖
[1]Jean J Labrosse.嵌入式實時操作系統(tǒng)μC/OS-II[M].邵貝貝,譯.2版.北京:北京航空航天大學(xué)出版社,2003.
[2]Jean J Labrosse.μC/OS-III the Real Time Kernel for the Freescale Kinetis[EB/OL].[2014-09].http://micrium.com/page/downloads/os-iii-projects.