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