502
技術社區[雲棲]
VxWorks程序指南
*******************************************
一、任務
*******************************************
任務狀態:掛起、阻塞、就緒、睡眠。
任務可以在任何一種狀態被刪除。
Wind內核裏有256種優先級,0最高,255為最低。
任務調度控製函數
kernelTimeSlice() 控製輪轉調度
taskPrioritySet() 改變任務優先級
taskLock() 禁止任務調度
taskUnlock() 允許任務調度
當任務訪問一個可能會被中斷服務程序訪問的變量或者數據結構時,可以使用intLock()實現互斥。
通過taskLock()、taskUnlock()搶占上鎖可禁止優先級的搶占,中斷服務程序仍然可以執行。
所有應用任務的優先級應該在100-250之間;但是驅動程序支持的任務(與中斷服務程序關聯的任務)優先級能夠位於51-99。
任務堆棧的空間分配:為了避免堆棧溢出和破壞任務堆棧可使用下列方法:
在最初分配堆棧空間時,分配比預先估計大一些的空間;然後周期性地調用checkStack()函數監控;若可以安全使用更小的空間,將修改分配空間的尺寸。
一般vxWorks使用任務ID號來定位任務,約定ID號為0的表示任務調用。
vxWorks操作係統不需要惟一的任務名,但為了避免混亂,建議使用惟一的任務名。
vxWorks操作係統的任務命名規則:所有從目標機啟動的任務以字母t開頭,而從主機啟動的任務以字母u開頭。
任務創建函數
taskSpawn() 創建並激活一個新任務
taskInit() 初始化一個新任務
taskActivate()激活一個初始化任務
任務名和ID函數
taskName() 得到與任務號相關的任務名
taskNameToId()尋找與任務名相關的任務ID
taskIdSelf() 獲得調用任務的ID號
taskIdVerify()檢查一個特定任務的存在性
在任務創建時,若需執行下列操作則要包括VX_FP_TASK選項:
1實行浮點操作2調用返回浮點值的函數3調用以浮點值為參數的函數
任務選項函數
taskOptionGet() 檢查任務選項
taskOptionSet() 設置任務選項 目前隻有VX_UNBREAKABLE選項可以被修改
任務信息:由於任務狀態是動態的,除非知道任務處於掛起,否則不能獲得當前信息
taskIdListGet() 用ID填充一組所有激活的任務
taskInfoGet() 得到任務的信息
taskPriorityGet() 查看任務的優先級
taskRegsGet() 檢查任務寄存器(不能使用單前任務時)
taskRegsSet() 設置任務寄存器(不能使用單前任務時)
taskIsSuspended()檢查任務是否處於掛起狀態
taskIsReady() 檢查任務是否處於就緒狀態
taskTcb() 獲得任務控製塊的指針
任務刪除函數
exit() 終止任務調用,釋放內存
taskDelete()終止指定任務,釋放內存
taskSafe() 保護調用任務免於刪除
taskUnsafe() 解除任務刪除保護
下麵的代碼表明了如何使用taskSafe()函數和taskUnsafe()函數去保護一個臨界代碼區域
taskSafe();
semTake (semId,WAIT_FOREVER);/*阻塞直至信號量可用*/
.../*臨界區域代碼*/
semGive(semId); /*釋放信號量*/
taskUnsafe();
任務控製函數
taskSuspend() 掛起任務,用來凍結任務狀態並進行檢查
taskResume() 恢複任務執行
taskRestart() 重新啟動任務
taskDelay() 延遲任務,延遲單位為“tick”
nanosleep() 延遲任務,延遲單位為納秒
下麵的代碼無需考慮時鍾速率,將使任務延時半秒:
taskDelay(sysClkRateGet()/2);/*函數sysClkRateGet()返回係統時鍾的速率,單位tick/秒*/
taskDelay()函數把作為調用者的任務移動到相同優先級隊列的尾部。
特別是,當調用taskDelay(0)時,將會把CPU交給係統中其他相同優先級任務。
taskDelay(NO_WAIT);/*允許其他相同優先級的任務運行*/
延時為零時,隻能調用taskDelay()函數,函數nanosleep()中的延時參數禁止為零。
任務擴展函數
為了允許其他相關的任務函數加入到係統中去,vxWorks提供“hook”函數。該函數允許任務在創建
、刪除和上下文交換時調用附加的函數。
taskCreateHookAdd() 增加一個在每個任務創建時都調用的函數
taskCreateHookDelete() 刪除一個以前加入的任務創建函數
taskSwitchHookAdd() 增加一個在每個任務切換時都調用的函數
taskSwitchHookDelete() 刪除一個以前加入的任務切換函數
taskDeleteHookAdd() 增加一個在每個任務被刪除時都調用的函數
taskDeleteHookDelete() 刪除一個以前加入的任務刪除函數
*******************************************
二、任務通信
*******************************************
大部分vxWorks函數使用下列重入技術:1動態堆棧變量2被信號保護的全局和靜態變量2任務變量
在編寫被多個任務內務調用的應用代碼時,建議使用這些技術。
vxWorks的任務間通信:
1共享內存,數據的簡單共享
2信號量,基本的互斥和同步
3Mutexe和條件變量,使用POSIX接口時互斥與同步操作
4消息隊列和管道,同一個CPU內任務間消息的傳遞
5sockets和遠程任務調用,任務間透明的網絡通信
6信號,用於異常處理。
信號量控製函數
semBCreate() 分配並初始化一個二進製信號量
semMCreate() 分配並初始化一個互斥信號量
semCCreate() 分配並初始化一個計數器信號量
semDelete() 終止並釋放一個信號量
semTake() 獲取一個信號量
semGive() 提供一個信號量
semFlush() 解鎖所有正在等待信號量的任務
二進製信號量
使用二進製信號量能夠滿足兩種任務的協調需要:互斥和同步。
互斥的實現:
創建一個二進製信號量,初始可用(SEM_FULL)。
當任務訪問資源時,首先必須獲得信號量。
隻要任務持有信號量,其他所有需要訪問該資源的任務將被阻塞。
#include "vxWorks.h"
#include "semLib.h"
SEM_ID semMutex;
semMutex = semBCreate(SEM_Q_PRIORITY,SEM_FULL);
...
semTake (semMutex,WAIT_FOREVER);
.../*臨界區域,任何時候僅單個任務可以訪問*/
semGive(semMutex);
同步的實現:
初始時信號量不可用(SEM_EMPTY)。
任務或中斷服務程序通過釋放信號量來表明事件的發生。
調用semTake()函數提取信號量的其他任務處於等待狀態,直至事件發生,並釋放信號量。
#include "vxWorks.h"
#include "semLib.h"
#include "arch/arch/ivarch.h"/*用結構體類型代替arch*/
SEM_ID syncSem;
init(int someIntNum)
{
/*連接中斷服務函數*/
intConnect(INUM_TO_IVEC(someIntNum),evertInterruptSvcRout,0);
/*建立信號量*/
syncSem = semBCreate(SEM_Q_FIFO, SEM_EMPTY);
/*發起用於同步的任務*/
taskSpawn("sample",100,0,20000,task1,0,0,0,0,0,0,0,0,0,0);
}
task1(void)
{
...
semTake(syncSem, WAIT_FOREVER);/*等待事件發生*/
printf("task 1 got the semaphore\n");
.../*啟動事件*/
}
eventInterruptSvcRout(void)
{
...
semGive(syncSem);/*讓任務1啟動事件*/
...
}
互斥信號量:
互斥信號量是一種用於解決內在互斥問題的特殊的二進製信號量,包括優先級倒置,刪除安區以及資源的遞歸訪問。
互斥信號量的基本行為與二進製信號量一致,不同之處如下:
1它僅用於互斥2它僅能由提取它(即調用semTake())的任務釋放3不能在中斷服務程序中釋放4semFlush()函數操作非法。
當一個高優先級任務需要等待一段不確定的時間,讓低優先級任務完成時(如低優先級通過信號量占有高優先級任務需要的資源),
需要發生優先級倒置。
下例用優先級繼承算法創建了一個互斥信號量:
semId = semMCreate(SEM_Q_PRIORITY | SEM_INVERSION_SAFE);/*使用優先級繼承選項SEM_INVERSION_SAFE的信號量必須選擇優先級順序隊列*/
下例是為防止應用臨界資源的任務被意外刪除的一個互斥信號量
semId = semMCreate(SEM_Q_FIFO | SEM_DELETE_SAFE);
計數信號量應用:計數信號量適用於保護多份複製的資源:如可以使用一個初始值為5的計數器信號量來協調5個磁帶驅動器工作。
Wind消息隊列控製
msgQCreate() 分配並初始化一個消息隊列
msgQDelete() 終止並釋放一個消息隊列
msgQSend() 向一個消息隊列發送消息
msgQReceive() 從一個消息隊列接收消息
/* In this example, task t1 creates the message queue and sends a message
* to task t2. Task t2 receives the message from the queue and simply
* displays the message.
*/
/* includes */
#include "vxWorks.h"
#include "msgQLib.h"
/* defines */
#define MAX_MSGS (10)
#define MAX_MSG_LEN (100)
MSG_Q_ID myMsgQId;
task2 (void)
{
char msgBuf[MAX_MSG_LEN];
/* get message from queue; if necessary wait until msg is available */
if (msgQReceive(myMsgQId, msgBuf, MAX_MSG_LEN, WAIT_FOREVER) == ERROR)
return (ERROR);
/* display message */
printf ("Message from task 1:\n%s\n", msgBuf);
}
#define MESSAGE "Greetings from Task 1"
task1 (void)
{
/* create message queue */
if ((myMsgQId = msgQCreate (MAX_MSGS, MAX_MSG_LEN, MSG_Q_PRIORITY))
== NULL)
return (ERROR);
/* send a normal priority message, blocking if queue is full */
if (msgQSend (myMsgQId, MESSAGE, sizeof (MESSAGE), WAIT_FOREVER,
MSG_PRI_NORMAL) == ERROR)
return (ERROR);
}
實時係統經常構造成任務的客戶機/服務器使用模式。
vxWorks事件是一種在任務和中斷處理程序間,或任務和vxWorks結構體間的通信方式。
看門狗定時器函數調用
wdCreate() 分配並初始化一個看門狗定時器
wdDelete() 終止並釋放一個看門狗定時器
wdStart() 啟動一個看門狗定時器
wdCancel() 取消當前的一個技術的看門狗定時器
/* Creates a watchdog timer and sets it to go off in 3 seconds.*/
/* includes */
#include "vxWorks.h"
#include "logLib.h"
#include "wdLib.h"
/* defines */
#define SECONDS (3)
WDOG_ID myWatchDogId;
task (void)
{
/* Create watchdog */
if ((myWatchDogId = wdCreate( )) == NULL)
return (ERROR);
/* Set timer to go off in SECONDS - printing a message to stdout */
if (wdStart (myWatchDogId, sysClkRateGet( ) * SECONDS, logMsg,
"Watchdog timer just expired\n") == ERROR)
return (ERROR);
/* ... */
}
*******************************************
三、中斷
*******************************************
中斷處理函數
intConnect() 設置中斷處理的C程序
intContext() 如果是從中斷級調用,返回真
intCount() 獲得當前中斷嵌套深度
intLevelSet(() 設置處理器的中斷屏蔽級
intLock() 禁止中斷
intUnlock() 重新允許中斷
intVecBaseSet() 設置向量基地址
intVecBaseGet() 得到向量基地址
intVecSet() 設置異常向量
intVecGet() 獲得異常向量
中斷服務程序禁止調用浮點協處理器函數。因為由intConnect()函數建立的中斷驅動代碼不能保存和恢複浮點寄存器。
*******************************************
四、輸入/輸出係統(1)
*******************************************
文件描述符(fd)的默認值:0=標準輸入設備 1=標準輸出設備 2=標準錯誤輸出設備
下例將調用此函數的任務(ID = 表示該任務本身)標準輸出文件(fd =1 )重定向到一個已打開的文件(fd = fileFd).
ioTaskStdSet(0,1,fileFd);
fd = open("name",flags,mode);
文件訪問方式標誌(flags)
O_RDONLY 0(hex) 以隻讀方式打開文件
O_WRONLY 1(hex) 以隻寫方式打開文件
O_RDWR 2(hex) 以讀寫方式打開文件
O_CREAT 200(hex)建立一個新文件
O_TRUNC 400(hex)刪除該文件
基於多文件描述符的掛起操作:選擇功能The Select Facility
選擇功能中的宏函數
FD_ZERO 將所有標誌位設置為“0”
FD_SET 對指定文件描述符的標誌位設置為“1”
FD_CLR 對指定文件描述符的標誌位設置為"0"
FD_ISSET 如果指定標誌位值為“1”,則返回“1”;否則返回“0”
/* selServer.c - select example
* In this example, a server task uses two pipes: one for normal-priority
* requests, the other for high-priority requests. The server opens both
* pipes and blocks while waiting for data to be available in at least one
* of the pipes.
*/
#include "vxWorks.h"
#include "selectLib.h"
#include "fcntl.h"
#define MAX_FDS 2
#define MAX_DATA 1024
#define PIPEHI "/pipe/highPriority"
#define PIPENORM "/pipe/normalPriority"
/************************************************************************
* selServer - reads data as it becomes available from two different pipes
*
* Opens two pipe fds, reading from whichever becomes available. The
* server code assumes the pipes have been created from either another
* task or the shell. To test this code from the shell do the following:
* -> ld < selServer.o
* -> pipeDevCreate ("/pipe/highPriority", 5, 1024)
* -> pipeDevCreate ("/pipe/normalPriority", 5, 1024)
* -> fdHi = open ("/pipe/highPriority", 1, 0)
* -> fdNorm = open ("/pipe/normalPriority", 1, 0)
* -> iosFdShow
* -> sp selServer
* -> i
* At this point you should see selServer's state as pended. You can now
* write to either pipe to make the selServer display your message.
* -> write fdNorm, "Howdy", 6
* -> write fdHi, "Urgent", 7
*/
STATUS selServer (void)
{
struct fd_set readFds; /* bit mask of fds to read from */
int fds[MAX_FDS]; /* array of fds on which to pend */
int width; /* number of fds on which to pend */
int i; /* index for fd array */
char buffer[MAX_DATA]; /* buffer for data that is read */
/* open file descriptors */
if ((fds[0] = open (PIPEHI, O_RDONLY, 0)) == ERROR)
{
close (fds[0]);
return (ERROR);
}
if ((fds[1] = open (PIPENORM, O_RDONLY, 0)) == ERROR)
{
close (fds[0]);
close (fds[1]);
return (ERROR);
}
/* loop forever reading data and servicing clients */
FOREVER
{
/* clear bits in read bit mask */
FD_ZERO (&readFds);
/* initialize bit mask */
FD_SET (fds[0], &readFds);
FD_SET (fds[1], &readFds);
width = (fds[0] > fds[1]) ? fds[0] : fds[1];
width++;
/* pend, waiting for one or more fds to become ready */
if (select (width, &readFds, NULL, NULL, NULL) == ERROR)
{
close (fds[0]);
close (fds[1]);
return (ERROR);
}
/* step through array and read from fds that are ready */
for (i=0; i< MAX_FDS; i++)
{
/* check if this fd has data to read */
if (FD_ISSET (fds[i], &readFds))
{
/* typically read from fd now that it is ready */
read (fds[i], buffer, MAX_DATA);
/* normally service request, for this example print it */
printf ("SELSERVER Reading from %s: %s\n",
(i == 0) ? PIPEHI : PIPENORM, buffer);
}
}
}
}
*******************************************
四、輸入/輸出係統(2)
*******************************************
異步輸入輸出操作(AIO)
能夠在執行普通的內部處理時,同時執行輸入/輸出操作。
異步輸入輸出操作函數
aioPxLibInit() 初始化AIO功能函數庫
aioShow() 顯示AIO功能要求
aio_read() 初始化異步讀操作
aio_write() 初始化異步寫操作
aio_listio() 初始化個數最多為LIO_MAX的AIO功能請求
aio_error() 在一個AIO操作中尋找錯誤狀態值
aio_return() 在一個已完成的AIO操作中尋找返回狀態值
aio_cancel() 取消一個AIO操作
aio_suspend() 等待一個AIO操作完成、被中斷或超時
vxWorks操作係統中的驅動程序
ttyDrv 終端設備驅動程序
ptyDrv 偽終端設備驅動程序
pipeDrv 管道設備驅動程序
memDrv 偽存儲設備驅動程序
nfsDrv NFS係統客戶機驅動程序
netDrv 用於遠程文件訪問的網絡驅動程序
ramDrv 用於創建RAM存儲盤的RAM驅動程序
scsiLib SCSI接口庫
串行I/O設備(終端和偽終端設備)
vxWorks操作係統中的I/O設備是一種緩衝型的串行字節流設備。每個設備都有一個環形緩衝區用於輸入和輸出操作。
下例是在tty設備上設置除了OPT_MON_TRAP功能外的所有功能;
status = ioctl (fd, FIOSETOPTIONS, OPT_TERMINAL & ~OPT_MON_TRAP);
tty設備的可選項
OPT_LINE 選擇線形傳輸模式
OPT_ECHO 向同一輸出通道回應輸入的字符
OPT_CRMOD 將輸入的RETURN字符翻譯成NEWLINE標誌;將輸出的NEWLINE標誌翻譯成RETURN-LINEFEED字符
OPT_TANDEM 響應軟件流量控製字符CTRL+Q和CTRL+S(XON and XOFF)
OPT_7_BIT 從所有輸入字節中取出最高位
OPT_MON_TRAP 使特殊ROM軟中斷監控程序字符有效,默認為CTRL+X
OPT_ABORT 使特殊目標機SHELL程序終止字符,默認為CTRL+Z
OPT_TERMINAL 將上述選項位設為“1”
OPT_RAW 不設置上述選項位
tyLib文件支持的I/O操作控製函數
FIOBAUDTATE 對指定參數設置傳輸速率
FIOCANCEL 取消一次讀/寫操作
FIOFLUSH 丟棄輸入和輸出緩衝區中的所有數據
FIOGETNAME 獲取指定文件描述符對應的文件名
FIOGETOPTIONS 返回當前設備選項字內容
FIONREAD 獲取輸入緩衝區中的未讀字節數
FIONWRITE 獲取輸出緩衝區中的字節數
FIOSETOPTIONS 設置設備選項字的內容
管道設備
一個任務可以向管道寫信息,其他任務可以讀取這些信息。
創建管道設備
status = pipeDevCreate("/pipe/name",maxMsgs, maxLength);
pipeDrv文件支持的I/O操作控製函數
FIOFLUSH 丟棄管道中所有信息
FIOGETNAME 獲取指定文件描述符對應的管道名
FIONMSGS 獲取管道中的信息數目
FIONREAD 獲取管道中第一條信息的字節數
偽存儲設備(memDrv)
memDrv驅動程序允許I/O係統訪問存儲器像訪問偽I/O設備一樣。
memDrv文件支持的I/O操作控製函數
FIOSEEK 在文件中設置當前字節偏移量
FIOWHERE 返回當前在文件中的位置
網絡文件係統(NFS)設備
網絡文件係統設備可以通過NFS協議存取遠程主機上的文件。
下例函數在主機"mars"中安裝名為“/usr”的係統,本地係統名為“/vxusr”。
nfsMount("mars","/usr","/vxusr");
nfsDrv文件支持的I/O控製函數
FIOFSTATGET 獲取文件狀態信息
FIOGETNAME 獲取指定文件描述符對應的文件名
FIONREAD 獲取文件中未讀取字節數
FIOREADDIR 讀取下一個目錄入口信息
FIOSEEK 在文件中設置當前字節偏移量
FIOSYNC 向遠程NFS文件刷新數據
FIOWHERE 返回文件中當前字節偏移量
非NFS網絡設備
利用遠程外殼協議(RSH)或文件傳輸協議(FTP)訪問遠程主機上的文件。這些網絡設備需要netDrv驅動程序支持。
I/O係統的功能是將用戶的I/O請求與相應驅動程序中的相應操作函數相連。I/O係統通過維護一個包括每個驅動程序中每個操作函數的地址表來完成上述工作。
drvnum = iosDrvInstall(xxCreat,0,xxOpen,0,xxRead,xxWrite,xxIoctl);
塊存取設備
塊存取設備的驅動程序不是與I/O係統直接相連,而是與文件係統相互作用,文件係統再與I/O係統相連.
塊存取設備驅動程序中通用的操作包括:
1初始化硬件2分配並初始化數據結構3建立信號量4初始化中斷向量5允許中斷操作
文件係統將自己作為驅動程序裝入驅動程序表中,並且通過使用存放於塊存取設備結構BLK_DEV(直接訪問的塊存取設備)或SEQ_DEV(順序訪問的塊存取設備)中的函數地址調用實際的驅動程序。
驅動程序支持庫(對用戶編寫驅動程序有幫助)
errnoLib 錯誤狀態函數庫
ftpLib ARPA文件傳輸協議函數庫
ioLib I/O接口函數庫
iosLib I/O係統函數庫
intLib 中斷支持函數庫
remLib 遠程命令函數庫
rngLib 環形緩衝區子程序函數庫
ttyDrv 終端驅動程序函數庫
wdLib 看門狗定時器函數庫
*******************************************
五、本地文件係統
*******************************************
dosFs文件係統:適用於塊存取設備(磁盤)的實時操作,與MS-DOS文件係統兼容;
rawFs文件係統:提供了一種簡單的原始文件係統。該文件係統將整個磁盤當作一個單獨的大文件;
tapeFs文件係統: 適用於不使用標準文件或目錄結構的磁帶設備。實際上將磁帶盤當作一個原始設備並將整個磁帶盤當作一個大文件;
cdromFs文件係統:允許應用程序從按照ISO9660標準文件係統格式化的CD-ROM設備上讀取數據;
TSFS目標服務器文件係統:通過使用Tornado軟件中的目標服務器,使得目標機可以訪問主機係統的文件。
最後更新:2017-04-03 12:55:36