用戶:pdeantihuman/沙盒liburing
io_uring 是一個新的 Linux IO 介面,2019年1月8日提交修補程式,2019年3月8日合併到了 Linux v5.1-rc1,旨在成為 Linux 的非同步檔案 IO 介面[1],替代 Linux 的舊非同步檔案 IO 介面 AIO。io_uring 利用兩個迴圈緩衝區在核心和用戶態程式之間交換數據,一個用來提交IO請求,另一個用來接收IO結果,前者稱為提交佇列(SQ),後者稱為完成佇列(CQ)。
從新介面的名字 io_uring 也可看出,該介面是 「yet another ring buffer「。
程式介面
編輯io_uring 現在的狀態是開發中,介面一直在變化中。
int io_uring_setup(int entries, struct io_uring_params *params);
新增的 io_uring 實例,entries 表示與該io_uring實例相對應的迴圈緩衝區應有多大。entries 必須是一個 2 的冪次,大小必須在 1-4096 之間。返回值是一個與 io_uring 實例相對應的檔案描述子。 因為提交佇列和完成佇列是用戶態程式與核心共用的,你需要 MMAP 來訪問這兩個佇列。將這兩個
int io_uring_enter(unsigned int fd, unsigned int to_submit, unsigned int min_complete, unsigned int flags, sigset_t sig);
io_uring_enter 用來通知核心收割提交佇列上已經就緒的IO請求。fd 指的是 io_uring 相對應的檔案描述子,to_submit 指已經提交了多少個請求,min_complete 指的是等待多少個請求完成後返回。因此,發起IO請求和等待IO完成事件可以用同一個系統呼叫。
提交佇列排序
編輯提交到提交佇列中的IO請求稱為SQE(Submission Queue Entry)。
SQE 之間預設是獨立的,意思是任何一個 SQE 的執行不影響另一個 SQE 的執行或者排序。因此 SQE 的排序實際上很自由。
io_uring 支援通過同步指令清空請求佇列。方式是開發者可以提交一個必須等待前面所有 SQE 完成後才能開始執行的 SQE,在這個SQE的 flags 屬性設置IOSQE_IO_DRAIN
即可實現。不過注意這會暫停所有後續的IO請求,它創造的管線化空泡可能比想像中大得多。如果你需要經常為了數據完整性使用這類排序操作,應當使用一個單獨的 IO 上下文來避免對無關IO操作的影響。IOSQE_IO_DRAIN
是一個非常重量級的管線化屏障。
SQE 鏈
編輯開發者如果希望兩個SQE之間有依賴關係,io_uring 支援通過SQE鏈的方式表示一個SQE與另一個SQE之間的依賴關係。如果SQE的flags上設置了IOSQE_IO_LINK
,那麼這個SQE就會等待它前面一個SQE完成後才會開始執行。
比如,需要將數據從一個檔案讀出寫入緩衝區,然後緩衝區向另一個檔案寫入,是一個非常常見的需求,這種時候你就可以建立一個 SQE 鏈。
範例
編輯應用程式通過 MMAP 訪問提交佇列
編輯struct app_sq_ring app_setup_sq_ring(int ring_fd, struct io_uring_params *p)
{
// 应用程序需要一个结构体变量 sring 存放循环缓冲区的指针
struct app_sq_ring sqring;
void *ptr;
ptr = mmap(NULL, p→sq_off.array + p→sq_entries * sizeof(__u32),
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
ring_fd, IORING_OFF_SQ_RING);
sring→head = ptr + p→sq_off.head;
sring→tail = ptr + p→sq_off.tail;
sring→ring_mask = ptr + p→sq_off.ring_mask;
sring→ring_entries = ptr + p→sq_off.ring_entries;
sring→flags = ptr + p→sq_off.flags;
sring→dropped = ptr + p→sq_off.dropped;
sring→array = ptr + p→sq_off.array;
return sring;
}
相關條目
編輯參考資料
編輯- ^ io_uring.pdf (PDF).