閱讀164 返回首頁    go 阿裏雲 go 技術社區[雲棲]


VxWorks 任務

任務:在執行時每個程序都被稱之為任務。VxWorks操作係統中,任務可以直接地或者以共享方式訪問大多數係統資源,為了維護各自的線程,每個任務必須保持有足夠的上下文環境。


就緒(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內核調度程序。當禁止使用調度程序時,若該任務正在執行,不會發生基於優先級的搶占。
搶占上鎖隻能阻止任務的上下文切換,並不禁止中斷。



任務優先級:所有應用任務的優先級應該在100-250之間;但是驅動程序支持的任務(與中斷服務程序關聯的任務)優先級能夠位於51-99。

(3)    任務異常處理:


VxWorks操作係統中,大多數函數是可重入的。但若存在一個對應於命名為someName_r()的函數,someName() 因作為函數重入的版本將認為是不可重入的。例如,ldiv() 有一個對應函數ldiv_r(),則ldiv() 是不可重入的。

重入技術
. 動態堆棧變量
. 被信號保護的全局和靜態變量
. 任務變量:taskVarAdd(), taskVarDelete()和taskVarGet()


.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操作係統中所有任務存在於一個單獨的線性地址空間中,所以任務間共享數據結構是很容易實現的。全局變量、線性緩衝、環形緩衝、連接鏈和指針都可以被運行在不同上下文中的代碼直接引用。


. 實現資源互斥訪問的方法包括:
中斷上鎖(中斷上鎖時不要調用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()。使用這種方式,任務在占用信號量時不會被刪除。
      .. 遞歸資源訪問:互斥信號量能夠遞歸獲得。在釋放信號量前,遞歸獲取的互斥信號量被釋放和提取的次數應該相等,這通過一個計數器跟蹤實現。

. 計數器信號量
      是實現任務同步和互斥的另一種手段,適用於保護多份複製的資源。


在VxWorks操作係統裏,單個CPU裏任務間的主要通信方式使用消息隊列。
----------------------------------------------------------
|      調用         |           描述                    |
| msgQCreate()      | 分配並初始化一個消息隊列          |
| msgQDelete()      | 終止並釋放一個消息隊列            |
| msgQSend()        | 向一個消息隊列發送消息            |
| msgQReceive()     |   從一個消息隊列接收消息          |
----------------------------------------------------------
消息的優先級:MSG_PRI_NORMAL和MSG_PRI_URGENT
中斷服務程序能夠向消息管道中寫入,但不能從消息管道中讀取。


管道使用VxWorks操作係統中的I/O係統,並提供替換消息隊列的接口。管道是由驅動程序pipeDrv管理的虛擬I/O設備,任務能夠使用標準I/O 對管道進行打開、讀取或寫入等操作,另外也可以調用函數ioctl。
與消息管道類似,中斷服務程序能夠向管道寫入,但不能從管道讀取。


套接字Sockets

遠程程序調用RPC


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事件上下文中,這些結構體被用作為資源,包括信號量和消息隊列。隻有任務能夠接收事件;然而任務、中斷處理程序或資源都可以發送事件。


. 發送和接收事件
任務、中斷服務程序以及資源都使用同一個應用編程接口ev_send()來發送事件。
對於從資源接收事件的任務來說,任務必須用資源寄存,而且請求資源在空閑時發送一係列指定的事件;這種資源可以使信號量,也可以是消息隊列。

. 等待事件
任務能夠從一個或多個資源等待多個事件。每個資源可以發送多個事件,同樣任務也可以等待接收一個或多個事件。

. 事件的寄存
從資源接收事件時,資源隻能寄存一個任務。如果另一個任務隨後用同樣的資源寄存,那麼不會通知原先寄存的任務就自動解除原有的寄存。VxWorks事件寄存的處理與pPOS事件則不同。

. 空閑資源
當資源給任務發送事件表明空閑時,不意味著資源的空閑狀態可以保留。因此,從資源等待事件的任務在資源空閑時被解除阻塞;但同時資源也可能被取走。
對於兩個或兩個以上的任務持續交換資源所有權的情況,資源雖然被釋放,但並不處於空閑狀態,所以資源將不會發送事件。

. 應用編程接口
---------------------------------------------------------------------
| 函數          |                     描述                         |
| ev_send()     | 給任務發送事件                                   |
| ev_receive()  | 等待事件                                         |
| sm_notify()   | 寄存一個被信號量告知可用的任務                   |
| q_notify()    | 寄存一個被消息隊列告知有消息到來的任務           |
| q_vnoify      | 寄存一個被可變長度的消息隊列告知有消息到來的任務 |
---------------------------------------------------------------------



VxWorks事件執行以pPOS事件為基石。

. 空閑資源定義
     互斥信號量:當一個互斥信號量被釋放並且在其上沒有任務阻塞
     二進製信號量:當沒有任務占有或等待一個二進製信號量
     計數器信號量:一個計數器信號量在其計數值非零且其上沒有阻塞任務時
     消息隊列:隊列中有消息存在,且沒有等待該隊列中消息而阻塞的任務

. VxWorks對pPOS事件的擴展
    單任務資源寄存:在pPOS係統中一個任務用資源寄存發送pSOS事件時,它會無意地取消另一個已用該資源寄存的任務寄存,第一個用該資源寄存的任務將無限期地被阻止。VxWorks事件則提供了一個選項,在該選項中如果另一個任務已經用某個資源寄存了,則不允許第二個任務用該資源再寄存。如果第二個任務用該資源寄存,將返回一個錯誤。
    立即發送選項:當一個pPOS任務用資源寄存時,即使寄存時資源處於空閑狀態,也不會立即給任務發送時間。對於VxWorks事件,默認行為與之相同。然而,VxWorks事件提供了一個選項,即若該資源在寄存時處於空閑狀態,該選項允許任務請求資源立即給其發送事件。
     自動取消寄存選項:pPOS執行過程序要任務在從資源接收任務後明確地取消寄存。VxWorks執行提供一個選項,該選項可以通知資源僅發送一次事件,然後在發送後自動取消寄存。
    自動解除資源堵塞:當刪除資源(一個信號量或者消息隊列時),調用函數semDelete()和msgQDelete()解除所有任務的掛起。在任務等待被刪除資源發送事件時,該措施保護任務避免無限期地堵塞。然後任務繼續執行,導致任務掛起的函數eventReceive()返回一個ERROR值。

事件25到32(VXEV25或0x01000000到VXEV32或0x80000000)用作係統保留用,VxWorks用戶不可以使用這些事件。


------------------------------------------------------------------------------------------------------------------
| 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函數庫,像連接鏈和環形緩衝器,都可以被中斷服務程序使用。

最後更新:2017-04-03 16:48:36

  上一篇:go 第1章 PCI總線的基本知識
  下一篇:go vxWorks 命令