io_uring 简介和使用
目录
警告
本文最后更新于 2022-11-17,文中内容可能已过时。
简介
io_uring 是 Linux 在 5.1 版本引入的一套新的异步 IO 实现。相比 Linux 在 2.6 版本引入的 AIO,io_uring 性能强很多,接近 SPDK[1],同时支持 buffer IO
io_uring 的作者 Jens Axboe 是 Linux 内核块层和其他块设备的维护者,同时也是 CFQ、Noop、Deadline 调度器、blktrace 以及 FIO 的作者,对内核块层非常熟悉
使用
系统调用
io_uring 只增加了三个 Linux 系统调用分别是 io_uring_setup
,io_uring_enter
和 io_uring_register
他们的入口都在 Linux 内核源码的 fs/io_uring.c
文件中
用户程序可以直接使用 syscall(__NR_xxx, ……)
的方式直接调用,使用起来很麻烦
liburing
由于直接使用系统调用较为复杂,Jens Axboe 还提供了封装好的用户态库 liburing,简化了 io_uring 的使用,代码位置在 github 上
样例
liburing 仓库的 examples/
目录下提供了几个简单的样例程序:
文件 | 功能 | 其他 |
---|---|---|
io_uring-test.c |
读取一个文件的全部内容 | - |
io_uring-cp.c |
复制一个文件的内容到另一个文件 | 使用 user_data 手动处理读写 IO 之间的依赖,读 IO 返回之后才下发写 IO |
link-cp.c |
复制一个文件的内容到另一个文件 | 同时下发读写,使用 IOSQE_IO_LINK 保证读写之间的依赖[2] |
ucontext-cp.c |
复制 n 个文件的内容到另 n 个文件 | 使用 ucontext 进行上下文切换,模拟 协程 |
代码流程
仔细阅读前三个用例,可以看出使用 io_uring 的一般流程如下:
- 使用
open
、fstat
等函数来打开文件以及元数据查看等操作- 因为 io_uring 替换的是读写接口,后续 io_uring 操作的对象是
fd
(由open
函数执行返回的)
- 因为 io_uring 替换的是读写接口,后续 io_uring 操作的对象是
- 使用
io_uring_queue_init
初始化struct io_uring ring
结构体 - 初始化
struct iovec *iovecs
结构体用于存放用户态 buffer 指针和长度 - 通过
io_uring_get_sqe
获取sqe
- 通过
io_uring_prep_#OP
对sqe
填充命令,buffer 以及 offset 信息- 【可选】 通过
io_uring_sqe_set_data
对sqe
附加user_data
信息(该信息会在cqe
中进行返回)
- 【可选】 通过
- 通过
io_uring_submit
对整个ring
的所有sqe
进行下发 - 通过
io_uring_wait_cqe
或者io_uring_peek_cqe
来获取cqe
io_uring_wait_cqe
会阻塞当前线程直到有一个cqe
返回io_uring_peek_cqe
不会阻塞,如果当前没有cqe
,就会返回错误io_uring_cqe_get_data
可以从cqe
中获取user_data
- 通过
io_uring_cqe_seen
对当前cqe
进行清除,避免被二次处理 - 所有 IO 完成后,通过
io_uring_queue_exit
将ring
销毁
编译
根据官方 Makefile
可以看出编译时有额外的三个条件
- 定义
_GNU_SOURCE
宏,-D
宏定义 - 指定额外的头文件目录,
-I
指定头文件目录位置 - 使用
liburing
库,-L
指定库位置,-l
指定库名
即 gcc -D_GNU_SOURCE -I../src/include/ -L../src/ -o test test.c -luring
其中头文件目录下主要有三个头文件:
|
|
而 liburing
库也需要编译生成,推荐直接在 liburing
的顶层目录直接 make all
参考资料
- 本文链接: https://ywang-wnlo.github.io/posts/c142853f/
- 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 4.0 许可协议。转载请注明出处!
相关内容
请我一杯咖啡吧!
支付宝
微信