本文參考了:
POSIX 非同步 IO interface(AIO)定義了允許進程創建一個或多個非同步的 IO 操作的介面。進程可以在 IO 操作完成之後得到操作系統的通知,手段包括:不通知、信號、實例化thread。
注意:這只是 POSIX(The Portable Operating System Interface)定義的介面,並不是實現。Linux 內核對非同步 IO 的具體實現在後面。(This is an API, not implementation!)
POSIX 1003.1標準定義了非同步訪問文件的 library function:
系統調用描述aio_read()非同步讀取文件aio_write()非同步寫入文件aio_fsync發出對當前所有 outstanding 的非同步IO操作進行 flush 的請求 (不會阻塞)aio_error()獲取一個處於 outstanding 狀態非同步 IO 操作的 error codeaio_return()獲取一個已經完成的非同步 IO 操作的返回碼aio_cancel()取消一個outstanding的非同步 IO 操作aio_suspend()暫停進程,直到至少有一個outstanding的非同步 IO 操作完成
使用非同步 IO 其實是很簡單的。大致來說分為三步:
open()
aiocb
aio_fildes
aio_buf
aio_nbytes
aio_offset
aio_sigevent
SIGEV_NONE
SIGEV_SIGNAL
SIGEV_THREAD
aio_lio_opcode
具體的定義如下:
#include <aiocb.h>
struct aiocb { /* The order of these fields is implementation-dependent */
int aio_fildes; /* File descriptor */ off_t aio_offset; /* File offset */ volatile void *aio_buf; /* Location of buffer */ size_t aio_nbytes; /* Length of transfer */ int aio_reqprio; /* Request priority */ struct sigevent aio_sigevent; /* Notification method */ int aio_lio_opcode; /* Operation to be performed; lio_listio() only */
/* Various implementation-internal fields not shown */ };
/* Operation codes for aio_lio_opcode: */
enum { LIO_READ, LIO_WRITE, LIO_NOP };
3. 最後把 aiocb這個 control block 的地址傳給 aio_read()或者 aio_write()。
aio_read()
aio_write()
這兩個函數都會在kernel或library將對應 IO 的數據傳輸加入傳輸隊列之後立即退出。
之後進程可以用 aio_error()檢查非同步 IO 的進行狀態:
aio_error()
aio_error()返回值描述EINPROGRESS還在傳輸中0成功完成其他錯誤碼操作失敗
可以用 aio_return()獲取成功read或write了多少個 bytes,或者-1表示失敗。
aio_return()
在操作系統內核不支持非同步 IO 的情況下,非同步 IO 也能夠實現,實現思路如下: aio_read()和 aio_write()先克隆當前進程,讓子進程執行同步的 read()和 write()系統調用,然後父進程結束 aio_read()或 aio_write(),從而實現非阻塞,主進程可以開始做其他事情。顯然,這種沒有得到內核支持的非同步 IO 操作是比較低效的。
read()
write()
Linux 內核從2.6版本起開始支持下面這些系統調用:
系統調用描述io_setup()為當前進程創建一個非同步IO上下文(asynchronous i/o contex)io_submit()提交一個或多個非同步 IO 操作io_getevents()獲取一些 outstanding 非同步 IO 的運行狀態io_cancel()取消一個非同步 IOio_destroy()摧毀當前進程的非同步 IO 上下文
用戶態的進程要調用 io_submit()之前,先得調用 io_setup()創建非同步 IO 上下文。
io_submit()
io_setup()
基本上來說,一個 AIO context 就是一個用於追蹤所有進行中的非同步IO操作的數據結構,這個 struct 叫做 kioctx。一個應用可能會創建多個 AIO context,一個進程的所有 kioctx用一個鏈表相連: ioctx_list。
kioctx
ioctx_list
這個 ioctx_list保存在該進程的memory descriptor上:
來源於《Understanding the Linux Kernel, Third Edition》 P355
kioctx中有一個重要的數據結構: AIO ring。 AIO ring的作用是:kernel 把 outstanding 的 非同步 IO 操作完成情況寫到這裡面,由於 AIO ring是位於進程的地址空間的,所以進程可以直接從這個數據介面裡面讀取非同步 IO 的狀態,而不用執行相對較慢的系統調用。
AIO ring
aio_submit()系統調用包含三個參數:
aio_submit()
ctx_id
iocbpp
iocb
nr
其中 iocb和 POSIX 標準中的 aiocb是一樣的,同樣包含 aio_fildes,aio_buf,aio_nbytes,aio_offset,aio_lio_opcode這些欄位。
aio_fildes,aio_buf,aio_nbytes,aio_offset,aio_lio_opcode
Linux kernel 有一個 service routine : sys_io_submit(),執行下列操作:
sys_io_submit()
xtx_id
kiocb
ki_retry
aio_run_iocb()
EIOCBRETRY
aio_complete()
推薦閱讀: