目錄
在VxWorks中,基礎I/O是最底層的I/O。基礎I/O的接口同標準C庫中的I/O原語是源碼級兼容的。最基礎的I/O調用有7個,如下圖所示。
1.文件描述符
在基礎I/O層級,文件通過文件描述符引用。一個文件描述符是一個由open()或creat()函數返回的整數。其他I/O調用使用一個文件描述符作爲參數,以操作某個特定的文件。
文件描述符不是全局的。內核與RTP均有其獨有的文件描述符集合。內核中的任務或某個任務中的子任務將共享文件描述符。例如:
- 如果任務A和任務B運行在進程foo中,然後它們均使用write()函數對文件描述符7進行操作,那麼它們將對同一個文件(設備)進行寫操作。
- 如果一個進程bar與進程foo獨立運行(bar不是foo的孩子),然後進程bar的任務X和任務Y使用文件描述符7進行write()操作,那麼這個文件將與進程foo的任務A和任務B所操作的文件描述符7指定的文件不同。
- 如果進程foobar由進程foo創建,然後進程foobar的任務M和任務B分別調用write()對文件描述符7進行操作,那麼它們所操作的文件將同進程foo中的任務A和任務B按照文件描述符7操作的文件相同。然而,如果任務將該文件關閉了,後續再次打開文件描述符7時,該文件描述符將指向另外的文件。
當文件打開時,將分配並返回一個文件描述符;當文件關閉時,文件描述符將被釋放。
2.內核中的文件描述符表
內核中可用的文件描述符數量由宏NUM_FILES定義。這個數量也定義了文件描述符表的大小,該表控制了同時可以使用多少個文件描述符。默認大小是50,但是可以根據系統需要進行修改。
爲了避免用盡文件描述符,導致創建文件時出現錯誤,應用程序應該在不再使用一個文件描述符時將其關閉。
內核的文件描述符表大小也可以通過編程的方式進行修改。rtpIoTablesizeGet()函數用於獲取文件描述符表的大小,rtpIoTableSizeSet()函數用於對其進行修改。注意:這些函數在內核與RTP中均可使用(I/O系統將內核看做一類特殊的進程)。
3.RTP中的文件描述符表
在RTP中的文件描述符表的大小,定義了一個進程中可以同時打開的最大文件數量。該最大值是從其創建環境繼承而來的。如果該進程由一個內核任務創建,那麼新進程將繼承內核任務的文件描述符表的最大值。
4.打開和關閉函數
在對一個設備執行I/O操作之前,必須使用open()或creat()函數打開一個文件描述符。open()函數所需的參數爲:文件名、訪問類型、文件權限。語法如下:
fd=open("name",flags,mode);
對於open()函數,參數mode是可選的,如果對文件權限並不關心,就可以將mode設置爲0。
對於用戶級與內核級調用,open()函數的flags參數可以指定爲如下值:
在使用文件的訪問與模式參數調用open()函數時,需要注意如下情況:
- 通常,僅能使用open()打開一個已經存在的設備和文件。然而,對於NFS、網絡、dosFs和HRFS設備,可以通過帶O_CREAT的標記使用open()函數。
- 可以使用open()函數打開HRFS目錄,但是僅能使用O_RDONLY標誌。
- 對於dosFs和NFS設備,可以使用O_CREAT標記和FSTAT_DIR模式創建一個子目錄。dosFs將忽略其他mode參數。
- 對於HRFS設備,不能使用O_CREAT標記和FSTAT_DIR模式選項創建一個子目錄。HRFS將忽略mode選項,僅創建一個普通文件。
- netDrv默認文件系統不支持F_STAT_DIR mode選項或O_CREAT標記。
- 對於NFS設備,open()的第三個參數通常用於指定文件模式。
- 儘管HRFS支持爲一個文件設定權限模式,但是在VxWorks中並不這麼使用。
- 文件可以使用O_SYNC標記打開,表明每次寫操作都將立即把內容寫到底層介質中。當前dosFs文件系統支持這個標記,可以用於同步FAT與目錄條目。
- O_SYNC標記對HRFS文件系統不起作用,因爲HRFS本身總是進行同步。HRFS總是更新文件,就好像O_SYNC標記被設置了一樣。
注意:驅動或文件系統可能不會完全遵守flag值或mode值。如果驅動允許,一個按照O_RDONLY模式打開的文件實際上可能是可寫的。
5.創建和刪除函數
面向文件的設備,除了能夠打開已經存在的文件,還要能夠創建和刪除文件。
面向文件的設備可以使用creat()函數創建一個文件,並返回其文件描述符。creat()的參數與open()的參數類似,區別是creat()傳入的文件名指向一個新文件,而open()傳入的文件名指向的是一個已經存在的文件。
注意,在HRFS文件系統中,creat()函數是POSIX兼容的,其第二個參數用於指定文件權限;文件將按照O_RDWR模式打開。
對於dosFs,creat()函數不是POSIX兼容的,第二個參數用於指定打開模式標記。
remove()函數將刪除文件系統中的一個命名文件。再刪除文件之前,需要先關閉文件。
對於非文件系統設備,creat()函數與open()函數等效。remove()函數將不起作用。
6.讀和寫函數
當通過open()或creat()函數得到一個文件描述符之後,可以調用read()或write()函數向文件中讀取或寫入數據。read()函數的參數包括:文件描述符、存放待讀取數據的緩衝區地址,待讀取數據的最大長度。
read()函數等待從指定文件讀取數據,並返回實際讀取到的字節數。對於一個文件系統設備,如果讀取到的字節數比指定的字節數少,那麼後續的read()調用將返回0,表明已經讀取到文件的末尾。對於非文件系統設備,讀取到的字節數可以比指定的大小要少,就算還有可讀的數據也是允許的。後續的read()調用可能返回0.對於串口設備和TCP套接字,爲了讀取指定大小的數據,可能需要重複調用read()函數。讀取失敗時將返回ERROR(-1)。
write()函數的參數爲:文件描述符,待寫入數據的緩衝區地址,待寫數據長度。語法如下:
actualBytes=write(fd,&buffer,nBytes);
write()函數保證在返回到調用函數之前,至少會將所有指定的數據緩存到輸出緩衝區中,所以有可能數據還沒有真正的寫到設備中(因驅動而異)。write()函數返回寫入的字節數大小;如果返回的大小不等於需要寫入的大小,將返回錯誤。
RTP的read()和write()函數時POSIX兼容的。
7.文件截斷函數
有時需要丟棄文件中的一部分數據。當打開一個文件後,可以使用ftruncate()函數將文件截斷爲一個指定的大小。其參數爲:文件描述符、期望的文件字節長度。語法如下:
status=ftruncate(fd,length);
如果截斷成功,將返回OK。
如果一個文件描述符所指向的設備是不可截斷的,那麼ftruncate()將返回ERROR,並將errno設置爲EINVAL。
如果指定大小比文件實際的大小還要大,其結果將取決於具體的文件系統。對於dosFs和HRFS,文件的大小將擴展到指定的大小然而,對於其他文件系統,ftruncate()將返回ERROR,並將errno設置爲EINVAL。
ftruncate()函數時POSIX1003.1b標準的一部分。HRFS將完全支持,dosFs的實現則是部分兼容:創建和修改的次數不會改變。
對於HRFS,截斷不會修改seek的位置,但是在dosFs中,seek的位置將被設置爲文件末尾。
8.使用select()等待多個文件描述符
VxWorks的select()函數提供了一種等待多個文件描述的方法(允許任務等待多個設備可用)。VxWorks的select()同UNIX和Windows是兼容的。
內核的selectLib庫包括了select()和相關的函數,需要使用INCLUDE_SELECT組件。
對於RTP的select()函數,需要配置INCLUDE_IO_BASIC組件。
任務級的select()函數,不僅允許任務可以同時等待多個設備I/O,還允許任務制定等待多長時間。一個典型的例子就是客戶端-服務器模型,服務器端同時等待多個文件描述符,以同時爲本地和遠端的客戶端提供服務。服務器任務使用管道同本地客戶通信,使用一個套接字同遠端的客戶端通信。服務器任務必須儘快響應客戶端。如果服務器阻塞等待一個通信流,那麼除非這個通信流被處理,否則其他通信流將得不到服務。select機制具有同時監控套接字和管道的能力,所以可以用於解決該問題。
任務將阻塞直到數據可用或設備可寫。select()函數將在一個或多個文件描述符就緒或發生超時時返回。使用select()函數,任務可以制定等待哪些文件描述符的活動。在select()函數中使用位域指定感興趣的讀和寫文件描述符。當select()函數返回時,位域將修改爲反映當前哪些文件描述符可用。用於構建和操作位域的宏如下所示:
9.在內核中使用select()
10.在RTP中使用select()
11.POSIX文件系統函數
對於內核和RTP應用程序,VxWorks針對多種文件操作提供了相應的POSIX I/O和文件系統函數。如下所示: