【io_uring】简介和使用

io_uring是Linux 5.1引入的新型异步IO机制,由内核专家Jens Axboe创建,提供优于AIO的性能。它包括io_uring_setup、io_uring_enter和io_uring_register三个系统调用。liburing库简化了io_uring的用户态使用,提供了如io_uring-test、io_uring-cp等示例程序。使用流程涉及文件操作、io_uring结构体初始化、SQE填充及CQE处理。编译时需指定_GNU_SOURCE宏、头文件路径和liburing库。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介

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_setupio_uring_enterio_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 的一般流程如下:

  • 利用 openfstat 等函数来打开文件以及元数据查看等操作
    • 因为 io_uring 替换的是读写接口,后续 io_uring 操作的对象是 fd(由 open 函数执行返回的)
  • 利用 io_uring_queue_init 初始化 struct io_uring ring 结构体
  • 初始化 struct iovec *iovecs 结构体用于存放用户态 buffer 指针和长度
  • 通过 io_uring_get_sqe 获取 sqe
  • 通过 io_uring_prep_#OPsqe 填充命令,buffer 以及 offset 信息
    • 【可选】 通过 io_uring_sqe_set_datasqe 附加 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_exitring 销毁

编译

根据官方 Makefile 可以看出编译时有额外的三个条件

  • 定义 _GNU_SOURCE 宏,-D 宏定义
  • 指定额外的头文件目录,-I 指定头文件目录位置
  • 使用 liburing 库,-L 指定库位置,-l 指定库名

gcc -D_GNU_SOURCE -I../src/include/ -L../src/ -luring -o test test.c

其中头文件目录下主要有三个头文件:

$ tree src/include/
src/include/
├── liburing
│   ├── barrier.h
│   └── io_uring.h
└── liburing.h

1 directory, 3 files

liburing 库也需要编译生成,推荐直接在 liburing 的顶层目录直接 make all

参考资料

本文作者: ywang_wnlo
本文链接: https://ywang-wnlo.github.io/posts/c142853f/
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

`io_uring_prep_writev`是Linux内核提供的异步I/O(Asynchronous I/O)框架io_uring中的一个系统调用准备函数。它用于在用户空间通过环形队列(Ring Buffer,简称ringbuf)发起一次或多次writev操作,而无需直接阻塞进程。这个接口允许一次性提交多个缓冲区到一个套接字,提高了并发性能。 以下是`io_uring_prep_writev`的基本使用方法: 1. **初始化**: 首先,需要创建一个`io_uring`结构体,以及一个对应的控制环形队列。 2. **分配描述符**: 使用`io_uring_queue_init`分配描述符,这是提交请求的基础。 3. **填充描述符**: 对于每个写入操作,创建一个`io_uring_cqe`描述符,并使用`io_uring_prep_writev`进行准备: - `cqe->flags`:标志位,比如设置`IOURING_F_DONTCOPY`表示数据不需要复制到内核空间。 - `cqe->u64.flags`:可能包含其他选项,如`IOURING_COPY_USER`用于数据复制等。 - `cqe->u.writev.buf`:指向`iovec`数组,存储了要写入的数据。 - `cqe->u.writev.len`:数组元素的数量。 4. **提交任务**: 将描述符添加到`io_uring`的队列中,通常使用`io_uring_submit`函数。 5. **等待完成**: 当所有操作完成后,可以调用`io_uring_get_event()`检查是否有已完成的任务,然后使用`io_uring_cqe_seen`、`io_uring_cqe_status`获取结果。 ```cpp struct iovec iov[] = { ... }; // 数据缓冲区 int ret; ret = io_uring_queue_entry(ring, cqe, IOURING_CMD_WRITEV, sizeof(iov), (uintptr_t)iov); if (ret < 0) // 处理错误 ret = io_uring_submit(ring); // 提交队列 while (io_uring_wait_cqe(ring, &cqe, -1 /* 没有特定超时 */)) { if (cqe->res == 0) // 操作成功 else { int status = cqe->res; // 处理错误 } } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值