VxWorks 操作系統(tǒng)學習筆記1. 任務(wù)VxWorks
任務(wù):在執(zhí)行時每個程序都被稱之為任務(wù)。VxWorks操作系統(tǒng)中,任務(wù)可以直接地或者以共享方式訪問大多數(shù)系統(tǒng)資源,為了維護各自的線程,每個任務(wù)必須保持有足夠的上下文環(huán)境。
(1) 任務(wù)狀態(tài):
就緒(READY):該狀態(tài)時任務(wù)僅等待CPU的狀態(tài),不等待其他任何資源。
阻塞(PEND):任務(wù)由于一些資源不可用而被阻塞時的狀態(tài)。
睡眠(DELAY):出于睡眠的任務(wù)狀態(tài)。
掛起(SUSPEND):該狀態(tài)時任務(wù)不執(zhí)行,主要用于調(diào)試用。掛起僅僅約束任務(wù)的執(zhí)行,并不約束狀態(tài)的轉(zhuǎn)換,因此pended-suspended狀態(tài)時任務(wù)可以解鎖,delayed-suspended狀態(tài)時任務(wù)可以喚醒。
DELAY+S:既處于睡眠又處于掛起的任務(wù)狀態(tài)。
PEND+S:既處于阻塞又處于掛起的任務(wù)狀態(tài)。
PEND+T:帶有超時值處于阻塞的任務(wù)狀態(tài)。
PEND+S+T:帶有超時值處于阻塞,同時又處于掛起的任務(wù)狀態(tài)。
state+I:任務(wù)處于state且?guī)в幸粋€繼承優(yōu)先級。
----------------------------------------------------------------------------------------
| ready | ——> | pended | semTake () / msgQReceive () |
| ready | ——> | delayed | taskDelay () |
| ready | ——> | suspended | taskSuspend () |
| pended | ——> | ready | semGive () / msgQSend () |
| pended | ——> | suspended | taskSuspend () |
| delayed | ——> | ready | expired delay |
| delayed | ——> | suspended | taskSuspend () |
| suspended | ——> | ready | taskResume () / taskActivate () |
| suspended | ——> | pended | taskResume () |
| suspended | ——> | delayed | taskResume() |
---------------------------------------------------------------------------------------
(2) Wind任務(wù)調(diào)度
在Wind內(nèi)核中,默認算法是基于優(yōu)先級的搶占式調(diào)度算法,也可以使用輪轉(zhuǎn)調(diào)度算法。
任務(wù)調(diào)度控制函數(shù):
----------------------------------------------------------------------------------------
| 調(diào)用 | 描述 |
| kernelTimeSlice() | 控制輪轉(zhuǎn)調(diào)度 |
| taskPrioritySet() | 改變?nèi)蝿?wù)優(yōu)先級 |
| taskLock() | 禁止任務(wù)調(diào)度 |
| taskUnlock() | 允許任務(wù)調(diào)度 |
----------------------------------------------------------------------------------------
基于優(yōu)先級的搶占式任務(wù)調(diào)度:
當一個新任務(wù)優(yōu)先級高于系統(tǒng)當前執(zhí)行任務(wù)的優(yōu)先級時,它將搶占CPU執(zhí)行。因此,系統(tǒng)內(nèi)核將確保CPU分配給處于就緒狀態(tài)的具有最高優(yōu)先級的任務(wù)執(zhí)行。
缺點:當多個相同優(yōu)先級的任務(wù)需要共享一臺處理器時,如果某個執(zhí)行的任務(wù)永不阻塞,那么它將一直獨占處理器,其他相同優(yōu)先級的任務(wù)就沒有機會執(zhí)行。
輪轉(zhuǎn)式調(diào)度:
當所有相同優(yōu)先級的任務(wù)處于就緒狀態(tài)時,輪轉(zhuǎn)算法傾向于平均使用CPU,對于所有相同優(yōu)先級的任務(wù),通過時間片獲得相同的CPU處理時間。
搶占上鎖:
通過調(diào)用taskLock()和taskUnlock()函數(shù),可以禁止使用Wind內(nèi)核調(diào)度程序或啟用Wind內(nèi)核調(diào)度程序。當禁止使用調(diào)度程序時,若該任務(wù)正在執(zhí)行,不會發(fā)生基于優(yōu)先級的搶占。
搶占上鎖只能阻止任務(wù)的上下文切換,并不禁止中斷。
taskLock()和intLock()比較
任務(wù)優(yōu)先級:所有應用任務(wù)的優(yōu)先級應該在100-250之間;但是驅(qū)動程序支持的任務(wù)(與中斷服務(wù)程序關(guān)聯(lián)的任務(wù))優(yōu)先級能夠位于51-99。
(3) 任務(wù)異常處理:
(4) 共享代碼和重入
VxWorks操作系統(tǒng)中,大多數(shù)函數(shù)是可重入的。但若存在一個對應于命名為someName_r()的函數(shù),someName() 因作為函數(shù)重入的版本將認為是不可重入的。例如,ldiv() 有一個對應函數(shù)ldiv_r(),則ldiv() 是不可重入的。
重入技術(shù):
. 動態(tài)堆棧變量
. 被信號保護的全局和靜態(tài)變量
. 任務(wù)變量:taskVarAdd(), taskVarDelete()和taskVarGet()
(5) 操作系統(tǒng)任務(wù)VxWorks
.
tUserRoot:內(nèi)核執(zhí)行的首個任務(wù),入口點是安裝目錄/target/config/all/usrConfig.c下函數(shù)usrRoot(),可
初始化VxWorks操作系統(tǒng)的大部分程序,發(fā)起諸如日志任務(wù)、異常處理任務(wù)、網(wǎng)絡(luò)任務(wù)和tRlogind后臺程序。正常情況下根任務(wù)在所有初始化結(jié)束
后,終止任務(wù)并且被刪除。
. tLogTask:日志任務(wù)
. tExcTask:異常處理任務(wù),必須擁有系統(tǒng)的最高優(yōu)先級。
. tNetTask:網(wǎng)絡(luò)任務(wù),用于VxWorks網(wǎng)絡(luò)任務(wù)級程序處理。通常配置INCLUDE_NET_LIB組件的VxWorks操作系統(tǒng)可以發(fā)起網(wǎng)絡(luò)任務(wù)。
. tWdbTask:目標代理任務(wù),用INCLUDE_WDB組件配置的VxWorks操作系統(tǒng)包括目標代理功能。
. 可選組建的任務(wù)
. tShell
. tRlogind
. tTelnetd
. tPortmapd
2. 任務(wù)間通信
(1) 共享內(nèi)存,數(shù)據(jù)的簡單共享
在VxWorks操作系統(tǒng)中所有任務(wù)存在于一個單獨的線性地址空間中,所以任務(wù)間共享數(shù)據(jù)結(jié)構(gòu)是很容易實現(xiàn)的。全局變量、線性緩沖、環(huán)形緩沖、連接鏈和指針都可以被運行在不同上下文中的代碼直接引用。
(2) 信號量,基本的互斥和同步
. 實現(xiàn)資源互斥訪問的方法包括:
中斷上鎖(中斷上鎖時不要調(diào)用VxWorks操作系統(tǒng)函數(shù),強行使用會導致意外的中斷):intLock() 和intUnlock()
搶占上鎖:taskLock() 和taskUnlock()
信號量對資源的上鎖
. VxWorks操作系統(tǒng)中的信號量類型
二進制,最快最通用的信號量,適用于同步和互斥。
互斥,為解決內(nèi)在互斥問題、優(yōu)先級繼承、刪除安全以及遞歸問題等而最優(yōu)化的一種特殊二進制信號量。
計數(shù),類似于二進制信號量,但其跟蹤信號量被釋放的次數(shù),適用于單個資源多個實例需要保護的情況。
. 隊列類型:
SEM_Q_PRIORITY:根據(jù)優(yōu)先級順序
SEM_Q_FIFO:根據(jù)先進先出順序
. 互斥信號量
基本行為與二進制信號量一致,不同之處如下:
僅用于互斥;
僅能由提取它(即調(diào)用semTake())的任務(wù)釋放;
不能在中斷服務(wù)程序中釋放;
semFlush()函數(shù)操作非法;
..
優(yōu)先級倒置:互斥信號量選項SEM_INVERSION_SAF能夠繼承優(yōu)先級算法,優(yōu)先級繼承協(xié)議確保在資源阻塞的所有任務(wù)中優(yōu)先級最高的且擁有資源執(zhí)
行資格的任務(wù)將優(yōu)先執(zhí)行。一旦任務(wù)的優(yōu)先級被提高,它以提高后的優(yōu)先級執(zhí)行;直到釋放其占有的全部互斥信號量后,該任務(wù)將返回到正常或者標準的優(yōu)先級。該
選項要求與優(yōu)先級隊列(SEM_Q_PRIORITY)一起使用。
..
刪除安全:一個受信號量保護的臨界區(qū)域內(nèi)經(jīng)常需要保護執(zhí)行任務(wù)避免被意外地刪除。刪除一個在臨界區(qū)執(zhí)行的任務(wù)可能會導致意想不到的后果。原語
semSafe()和semUnsafe()提供了一種任務(wù)安全的方法。但是在使用互斥信號量選項SEM_DELETE_SAFE時,每次使用
semTake()將隱含調(diào)用taskSafe(),使用semGive()將隱含調(diào)用taskUnsafe()。使用這種方式,任務(wù)在占用信號量時不會
被刪除。
.. 遞歸資源訪問:互斥信號量能夠遞歸獲得。在釋放信號量前,遞歸獲取的互斥信號量被釋放和提取的次數(shù)應該相等,這通過一個計數(shù)器跟蹤實現(xiàn)。
. 計數(shù)器信號量
是實現(xiàn)任務(wù)同步和互斥的另一種手段,適用于保護多份復制的資源。
(3) 消息隊列
在VxWorks操作系統(tǒng)里,單個CPU里任務(wù)間的主要通信方式使用消息隊列。
------------------------------------------------------------------------------------
| 調(diào)用 | 描述 |
| msgQCreate() | 分配并初始化一個消息隊列 |
| msgQDelete() | 終止并釋放一個消息隊列 |
| msgQSend() | 向一個消息隊列發(fā)送消息 |
| msgQReceive() | 從一個消息隊列接收消息 |
------------------------------------------------------------------------------------
消息的優(yōu)先級:MSG_PRI_NORMAL和MSG_PRI_URGENT
中斷服務(wù)程序能夠向消息管道中寫入,但不能從消息管道中讀取。
(4) 管道
管道使用VxWorks操作系統(tǒng)中的I/O系統(tǒng),并提供替換消息隊列的接口。管道是由驅(qū)動程序pipeDrv管理的虛擬I/O設(shè)備,任務(wù)能夠使用標準I/O 對管道進行打開、讀取或?qū)懭氲炔僮?,另外也可以調(diào)用函數(shù)ioctl。
與消息管道類似,中斷服務(wù)程序能夠向管道寫入,但不能從管道讀取。
(5) 任務(wù)間網(wǎng)絡(luò)通信
套接字Sockets
遠程程序調(diào)用RPC
(6) 信號
VxWorks支持軟件信號功能。信號可以異步改變?nèi)蝿?wù)的控制流程。任何任
務(wù)或中斷服務(wù)程序可以向指定任務(wù)發(fā)送信號。接收到信號的任務(wù)立即掛起當前的執(zhí)行線程,在下次調(diào)度執(zhí)行時轉(zhuǎn)而執(zhí)行指定的信號處理程序。信號處理程序在接收任
務(wù)的上下文中執(zhí)行,并使用任務(wù)的堆棧。即使在任務(wù)被阻塞時,仍可調(diào)用信號處理程序。
通常信號處理程序可作為中斷處理程序看待,任何導致調(diào)用程序阻塞的函數(shù)均不能在信號處理程序中調(diào)用。
Wind內(nèi)核支持兩種類型的信號接口:UNIX BSD風格的信號和POSIX兼容信號。為了簡化設(shè)計,建議在一個應用程序中使用一種類型接口,不要混合使用不同接口。
基本信號函數(shù):
----------------------------------------------------------------------------------------------------------
| POSIX 1003.1b兼容調(diào)用|UNIX BSD兼容調(diào)用| 描述 |
| signal() | signal() | 指定信號的處理程序 |
| kill() | kill() | 向任務(wù)發(fā)送信號 |
| raise() | N/A | 向自身發(fā)送信號 |
| sigaction() | sigvec() | 檢查或設(shè)置信號的處理程序 |
| sigsuspend() | pause() | 掛起任務(wù)直至任務(wù)提交 |
| sigpending() | N/A | 恢復一組用于傳遞而被阻塞的信號|
| sigemptyset() ------- | ------------------------ | ---------------------------------------------|
| sigfillset() ------- | | |
| sigaddset() -------- | sigsetmask() | 設(shè)置信號屏蔽 |
| sigdelset() -------- | | |
| sigismember() ------- |--------------------- ---|---------------------------------------------|
| sigprocmask() | sigsetmask() | 設(shè)置阻塞信號的屏蔽 |
| sigprocmask() | sigblock() | 增加到一組阻塞的信號中 |
----------------------------------------------------------------------------------------------------------
信號發(fā)生通常與硬件中斷相聯(lián)系。例如總線出錯、非法指令以及浮點數(shù)異常都可能產(chǎn)生某種信號。
3. 事件VxWorks
VxWorks事件是一種在任務(wù)和中斷處理程序間,或任務(wù)和VxWorks結(jié)構(gòu)體間的通信方式。在VxWorks事件上下文中,這些結(jié)構(gòu)體被用作為資源,包括信號量和消息隊列。只有任務(wù)能夠接收事件;然而任務(wù)、中斷處理程序或資源都可以發(fā)送事件。
(1) 事件pSOS
. 發(fā)送和接收事件
任務(wù)、中斷服務(wù)程序以及資源都使用同一個應用編程接口ev_send()來發(fā)送事件。
對于從資源接收事件的任務(wù)來說,任務(wù)必須用資源寄存,而且請求資源在空閑時發(fā)送一系列指定的事件;這種資源可以使信號量,也可以是消息隊列。
. 等待事件
任務(wù)能夠從一個或多個資源等待多個事件。每個資源可以發(fā)送多個事件,同樣任務(wù)也可以等待接收一個或多個事件。
. 事件的寄存
從資源接收事件時,資源只能寄存一個任務(wù)。如果另一個任務(wù)隨后用同樣的資源寄存,那么不會通知原先寄存的任務(wù)就自動解除原有的寄存。VxWorks事件寄存的處理與pPOS事件則不同。
. 空閑資源
當資源給任務(wù)發(fā)送事件表明空閑時,不意味著資源的空閑狀態(tài)可以保留。因此,從資源等待事件的任務(wù)在資源空閑時被解除阻塞;但同時資源也可能被取走。
對于兩個或兩個以上的任務(wù)持續(xù)交換資源所有權(quán)的情況,資源雖然被釋放,但并不處于空閑狀態(tài),所以資源將不會發(fā)送事件。
. 應用編程接口
------------------------------------------------------------------------------------------------
| 函數(shù) | 描述 |
| ev_send() | 給任務(wù)發(fā)送事件 |
| ev_receive() | 等待事件 |
| sm_notify() | 寄存一個被信號量告知可用的任務(wù) |
| q_notify() | 寄存一個被消息隊列告知有消息到來的任務(wù) |
| q_vnoify | 寄存一個被可變長度的消息隊列告知有消息到來的任務(wù) |
------------------------------------------------------------------------------------------------
(2) 事件VxWorks
VxWorks事件執(zhí)行以pPOS事件為基石。
. 空閑資源定義
互斥信號量:當一個互斥信號量被釋放并且在其上沒有任務(wù)阻塞
二進制信號量:當沒有任務(wù)占有或等待一個二進制信號量
計數(shù)器信號量:一個計數(shù)器信號量在其計數(shù)值非零且其上沒有阻塞任務(wù)時
消息隊列:隊列中有消息存在,且沒有等待該隊列中消息而阻塞的任務(wù)
. VxWorks對pPOS事件的擴展
單任務(wù)資源寄存:在pPOS系統(tǒng)中一個任務(wù)用資源寄存發(fā)送pSOS事件時,它會無意地取消另一個已用該資源寄存的任務(wù)寄存,第一個用該資源寄存的任務(wù)將無
限期地被阻止。VxWorks事件則提供了一個選項,在該選項中如果另一個任務(wù)已經(jīng)用某個資源寄存了,則不允許第二個任務(wù)用該資源再寄存。如果第二個任務(wù)
用該資源寄存,將返回一個錯誤。
立即發(fā)送選項:當一個pPOS任務(wù)用資源寄存時,即使寄存時資源處于空閑狀態(tài),也不會立即給任務(wù)發(fā)送時間。對于VxWorks事件,默認行為與之相同。然
而,VxWorks事件提供了一個選項,即若該資源在寄存時處于空閑狀態(tài),該選項允許任務(wù)請求資源立即給其發(fā)送事件。
自動取消寄存選項:pPOS執(zhí)行過程序要任務(wù)在從資源接收任務(wù)后明確地取消寄存。VxWorks執(zhí)行提供一個選項,該選項可以通知資源僅發(fā)送一次事件,然后在發(fā)送后自動取消寄存。
自動解除資源堵塞:當刪除資源(一個信號量或者消息隊列時),調(diào)用函數(shù)semDelete()和msgQDelete()解除所有任務(wù)的掛起。在任務(wù)等待
被刪除資源發(fā)送事件時,該措施保護任務(wù)避免無限期地堵塞。然后任務(wù)繼續(xù)執(zhí)行,導致任務(wù)掛起的函數(shù)eventReceive()返回一個ERROR值。
事件25到32(VXEV25或0x01000000到VXEV32或0x80000000)用作系統(tǒng)保留用,VxWorks用戶不可以使用這些事件。
(3) 比較API
------------------------------------------------------------------------------------------------------------------
| VxWorks函數(shù) | pPOS函數(shù) | 注釋 |
| eventSend | ev_send | 直接端口 |
| eventReceive | ev_receive | 直接端口 |
| eventClear | | VxWorks中的新功能 |
| semEvStart | sm_notify | SemEvStart等價于用非零事件參數(shù)調(diào)用sm_notify |
| semEvStop | sm_notify | SemEvStop等價于用事件參數(shù)為0調(diào)用sm_notify |
| msgQEvStart | q_vnotify | msgQEvStart等價于用非零事件參數(shù)調(diào)用q_notify |
| msgQEvStop | q_vnotify | msgQEvStop等價于用事件參數(shù)為0調(diào)用q_notify |
| | q_notify | VxWorks沒有一個固定長度的消息隊列機制 |
------------------------------------------------------------------------------------------------------------------
4. 看門狗定時器
VxWorks包括一個看門狗定時器機制,允許任何C函數(shù)與一個特定的時間
延時器聯(lián)系??撮T狗定時器作為系統(tǒng)時鐘中斷服務(wù)程序的一部分來維護。被看門狗定時器調(diào)用的函數(shù)通常作為系統(tǒng)時鐘中斷級的中斷服務(wù)代碼來執(zhí)行。但如果內(nèi)核由
于某種原因不能立即執(zhí)行能夠函數(shù)(例如一個優(yōu)先中斷或者內(nèi)核狀態(tài)),函數(shù)將放在tExcTask工作隊列中。tExcTask工作隊列中的函數(shù)以
tExcTask(通常是0)優(yōu)先級來執(zhí)行。
-------------------------------------------------------------------------------------------
| 調(diào)用 | 描述 |
| wdCreate() | 分配并初始化一個看門狗定時器 |
| wdDelete() | 終止并釋放一個看門狗定時器 |
| wdStart() | 啟動一個看門狗定時器 |
| wdCancel() | 取消當前的一個計數(shù)的看門狗定時器 |
-------------------------------------------------------------------------------------------
5. 中斷服務(wù)代碼
為了盡快地響應中斷,VxWorks中斷處理程序在所有任務(wù)上下文之外的一個特殊上下文內(nèi)執(zhí)行。因此,中斷處理不涉及到任務(wù)上下文的切換。
--------------------------------------------------------------------------------------------
| 調(diào)用 | 描述 |
| intConnect() | 設(shè)置中斷處理的C程序 |
| intContext() | 如果是從中斷級調(diào)用,返回真 |
| intCount() | 獲得當前中斷嵌套深度 |
| intLevelSet() | 設(shè)置處理器的中斷屏蔽級 |
| intLock() | 禁止中斷 |
| intUnlock() | 重新允許中斷 |
| intVecBaseSet() | 設(shè)置向量基地址 |
| intVecBaseGet() | 得到向量基地址 |
| intVecSet() | 設(shè)置異常向量 |
| intVecGet() | 獲得異常向量 |
--------------------------------------------------------------------------------------------
調(diào)用中斷服務(wù)程序函數(shù)存在著很多的限制。例如,在應用中斷服務(wù)程序時不能使用printf(), malloc()和semTake()函數(shù),但是可以使用semGive(), logMsg(), msgQSend()和bcopy()這樣的函數(shù)。
產(chǎn)生這些限制的原因是由于中斷服務(wù)程序不在一個固定的任務(wù)上下文中執(zhí)行,而且沒有任務(wù)控制塊,因此所有中斷服務(wù)程序必須共享一個單獨的堆棧。
. 中斷服務(wù)程序基本限制為禁止調(diào)用導致調(diào)用者堵塞的函數(shù)。
. malloc()和free()都要求獲得信號量,中斷服務(wù)程序不能調(diào)用任何用于創(chuàng)建或刪除的函數(shù)。
. 中斷服務(wù)程序不能通過VxWorks驅(qū)動程序來執(zhí)行I/O操作,因為大多數(shù)的設(shè)備驅(qū)動器可能會堵塞等待設(shè)備的調(diào)用者,因此它們需要一個任務(wù)上下文。但VxWorks管道驅(qū)動器是個例外,它設(shè)計用于中斷服務(wù)程序的寫操作。
. VxWorks提供了一個記錄功能,允許向系統(tǒng)任務(wù)平臺打印文本信息。這個機制是專門為中斷服務(wù)程序使用而設(shè)計的,同時它也是從中斷服務(wù)程序打印信息的最常用方法。
. 中斷服務(wù)程序同時禁止調(diào)用浮點協(xié)處理器函數(shù)。在VxWorks操作系統(tǒng)中,由intConnect()函數(shù)建立的中斷驅(qū)動代碼不能保存和恢復浮點寄存器。若中斷服務(wù)程序需要使用浮點指令,則必須明確地保存和恢復fppArchLib中函數(shù)浮點協(xié)處理器的寄存器。
. 所有VxWorks函數(shù)庫,像連接鏈和環(huán)形緩沖器,都可以被中斷服務(wù)程序使用。
|
|