目錄
異步輸入輸出允許在執行輸入輸出操作的同時併發地執行原始任務。在任務與I/O操作在邏輯上是相互獨立的情況下,可以使用AIO將I/O操作從任務中分離出來。VxWorks的AIO實現符合POSIX1003.1標準。
AIO的可以帶來更高的處理效率:它允許在資源可用時進行I/O操作,而不用等待相關事件完成。AIO避免了 同步I/O中的一些不必要的任務阻塞,從而減少了I/O與內部處理之間對資源的競爭,同時也提高了吞吐量。
VxWorks配置
爲了使用AIO,需要添加INCLUDE_POSIX_AIO和INCLUDE_POSIX_AIO_SYSDRV組件。第二個組件使能了輔助AIO系統驅動,當前所有的VxWorks設備都需要這個驅動以進行AIO操作。
POSIX AIO函數
VxWorks的aioPxLib庫提供了POSIX AIO函數。爲了異步訪問一個文件,可以使用open()函數打開該文件。然後使用open()返回的文件描述符調用AIO函數。POSIX AIO函數(包括兩個非POSIX函數)如下表所示:
當VxWorks配置了INCLUDE_POSIX_AIO之後,內核初始化代碼將自動條用aioPxLibInit()函數。aioPxInit()函數使用MAX_LIO_CALLS作爲其唯一參數。當MAX_LIO_CALLS配置參數被設置爲0(默認爲0),將會使用AIO_CLUST_MAX宏,該宏的值在privateaioPxLibP.h中定義爲100。
當在VxWorks中同時使用了INCLUDE_POSIX_AIO和INCLUDE_POSIX_AIO_SYSDRV組件時,內核函數aioSysInit()函數將自動初始化AIO系統驅動aioSysDrv。aioSysDrv驅動提供了與任何特定設備驅動相獨立的請求隊列,因此任意VxWorks設備驅動都可以使用AIO。AioSysInit()函數需要有三個參數:待創建的AIO系統任務數、任務優先級、任務棧大小。AIO系統任務數與能夠並行處理AIO請求的數量相同。aioSysInit()函數的三個參數由VxWorks的配置參數MAX_AIO_SYS_TASK、AIO_TASK_PRIORTY和AIO_TASK_STACK_SIZE設定。默認情況下,這些配置參數均設置爲0,此時實際獲取的是宏AIO_IO_TASK_DEFAULT、AIO_IO_PRIO_DELT、AIO_IO_STACK_DELT中定義的值,分別爲2,50,0x700。
AIO控制塊
每個AIO調用都將使用一個AIO控制塊(aiocb)作爲參數。調用函數必須爲aiocb分配空間,在進行AIO操作的過程中,這些空間必須保持有效(除非調用函數不會再AIO操作完成並調用aio_return()之前返回,否則不應該在任務棧中創建aiocb()。每個aiocb描述了一個AIO操作。因此,同時使用同一個aiocb執行AIO操作是無效的,並且會產生未定義的後果。
aiocb結構體在aio.h中定義,包括如下元素:
- aio_fildes:I/O文件描述符;
- aio_offset:從文件頭部的偏移量;
- aio_buf:從AIO中讀取或存放數據的緩衝區地址;
- aio_nbytes:讀或寫的字節數;
- aio_reqprio:爲AIO請求所減少的優先級;
- aio_sigevent:操作完成時返回的信號(可選);
- aio_lio_opcode:由lio_listio()函數執行的操作;
- aio_sys:由VxWorks指定的數據地址(非POSIX)。
使用AIO
函數aio_read()、aio_write()、lio_listio()將初始化AIO操作。lio_listio()函數用於設置可以同時進行異步讀寫請求的數量。通常,並不是在產生AIO請求後就能立刻用這三個函數完成I/O(讀寫)初始化。因此,它們的返回值不能反映實際的I/O操作結果,僅僅能夠說明一個請求是否成功。
可以使用aio_error()和aio_return()函數獲取I/O操作是否成功的信息。
帶週期檢查完成的AIO
如下內核代碼使用管道進行AIO操作。示例中創建了一個管道,提交了一個AIO讀請求,驗證讀請求是否還在處理狀態中,並提交了一個AIO寫請求。在一般情況下,對一個空管道進行同步讀的話,將不能夠繼續執行後續的寫操作。但是在AIO中,初始化了讀請求後將會繼續執行。當寫請求提交之後,示例任務將進入循環,週期性地檢查AIO請求的狀態,直到讀寫完成爲止。因爲AIO控制塊是在任務棧空間分配的,所以必須在aioExample()函數返回之前調用aio_return()函數。
示例如下:
測試AIO完成的其他方法
一個任務可以通過如下方式確定一個AIO請求是否完成:
- 像前一個示例中一樣,週期性地檢查aio_error()的返回值,直到一個AIO請求的狀態不再是EINPROGRESS。、
- 使用aio_suspend()函數將一個任務掛起,直到AIO請求完成。
- 當AIO請求完畢後,使用信號進行通知。
下面的示例內核代碼與之前的aioExample()類似,區別在於它使用了信號來通知寫操作的完成。如果從shell進行測試,需要使用比AIO系統任務更低的低優先級創建該任務,以免AIO請求被測試函數阻塞。