io_uring以及liburing介绍

io_uring简介

io_uring是linux于2019年引入内核的异步IO,支持普通的任务提交模式和轮询模式,用户向其一次性提交多个需要完成的系统调用任务,然后内核会对任务进行收割并返回任务完成的结果,用户只需获取任务完成的结果并进行相应的处理,而无需一直等待系统调用的完成。

io_uring 系统调用API

  • io_uring_setup()
  • io_uring_register()
  • io_uring_enter()

io_uring_setup()

设置上下文

int io_uring_setup(u32 entries, struct io_uring_params *p);
  • 创建一个提交队列(submit queue, SQ)和一个完成队列(complete queue, CQ).
  • 指定io_uring 的入口数目,即同时处理的 I/O 事件数目
  • 参数p 用来配置io_uring,内核返回的SQ/CQ配置信息也通过它带回来
  • 返回一个文件描述符,随后用于在这个 io_uring 实例上执行操作
  1. 使用mmap避免频繁的数据copy

io_uring_register()

注册用于异步 I/O 的文件描述符或内存区域

int io_uring_register(unsigned int fd, unsigned int opcode, void *arg, unsigned int nr_args);

该函数用于将文件描述符或内存区域与io_uring关联起来。该函数将返回注册的文件描述符或内存区域的索引,以便后续的 I/O 操作可以使用。

fd:	io_uring文件描述符。
opcode:	指定注册操作的类型,如文件描述符的注册或内存区域的注册。
arg:	指向相关数据结构的指针,用于传递需要注册的文件描述符或内存区域的信息。
nr_args:指定相关参数的数量。

io_uring_enter()

该函数用于提交 I/O 事件并等待其完成,返回已完成的 I/O 事件数量

int io_uring_enter(unsigned int fd, unsigned int to_submit, unsigned int min_complete, unsigned int flags, sigset_t *sig);

单次调用同时执行:

  1. 提交新的 I/O 请求
  2. 等待 I/O 完成
fd: io_uring文件描述符,即io_uring_setup() 返回的文件描述符
to_submit: 要提交的 I/O 事件数量
min_complete: 指定在返回之前至少完成的 I/O 事件数量,为0即不阻塞

liburing简介

由于io_uring要实现强大的功能和最优的效率,因此其接口和使用方式会比较复杂。但对于大部分不需要极致IO性能的场景和开发者来说,只使用io_uring的基本功能就能获得大部分的性能收益。当只需要基本功能时,io_uring的复杂接口中很大一部分是不会使用的,同时一部分初始化操作也是基本不变的。因此,io_uring的作者又开发了liburing来简化一般场景下io_uring的使用。使用liburing后,io_uring初始化时的大部分参数都不再需要填写,也不需要自己再做内存映射,内存屏障和队列管理等复杂易错的逻辑也都封装在liburing提供的简单接口中,大幅降低了使用难度。

liburing 常见 API

io_uring_queue_init_params()

执行io_uring_setup()系统调用来初始化io_uring队列,生成SQ和CQ

int io_uring_queue_init_params(unsigned entries, struct io_uring *ring, const struct io_uring_params *p);
  • entries:指定 io_uring 的入口数目,即同时处理的 I/O 事件数目
  • ring:指向 struct io_uring 结构的指针,用于接收初始化后的 I/O uring 环境
  • p:指向 struct io_uring_params 结构的指针,包含了自定义的初始化参数

示例:

unsigned short port = 8096;
int listen_fd = init_server(port);

struct io_uring_params ring_params;
memset(&ring_params, 0, sizeof(ring_params));

struct io_uring ring;
io_uring_queue_init_params(1024, &ring, &ring_params);

io_uring_get_sqe()

用于从 SQ 中获取下一个 Submission Queue Entry (SQE)。通过获取 SQE,你可以添加请求。

struct io_uring_sqe *io_uring_get_sqe(struct io_uring *ring);

ring: 指向 struct io_uring 结构的指针,表示要操作的io_uring对象

io_uring_prep_accept()

用于添加 执行 accept 操作的 请求到 SQE 中

void io_uring_prep_accept(struct io_uring_sqe *sqe, int fd, struct sockaddr *addr, socklen_t *addrlen, int flags);

注意到除了参数sqe,其它参数和accept()一样

示例程序:

struct sockaddr_in clientaddr;
socklen_t len = sizeof(clientaddr);

struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
io_uring_prep_accept(sqe, sockfd, (struct sockaddr*)&clientaddr, &len, 0);

io_uring_prep_recv()

用于添加 执行 recv 操作的 SQE

void io_uring_prep_accept(struct io_uring_sqe *sqe, int sockfd,  void *buf, size_t len, int flags);

注意到除了参数sqe,其它参数和recv()一样

io_uring_prep_send()

void io_uring_prep_send(struct io_uring_sqe *sqe, int sockfd,  void *buf, size_t len, int flags);

注意到除了参数sqe,其它参数和send()一样

io_uring_submit()

把所有的请求提交进去进行处理

int io_uring_submit(struct io_uring *ring);

io_uring_wait_cqe()

阻塞当前线程,直到有已完成的 CQE 可用。一旦有 CQE 可用,函数将填充 cqe_ptr 指向的指针,并返回0

int io_uring_wait_cqe(struct io_uring *ring, struct io_uring_cqe **cqe_ptr);
  1. ring:指向 struct io_uring 的指针,表示I/O uring环境。
  2. cqe_ptr:指向 CQE 指针的指针,用于存储返回的已完成CQE。

io_uring_peek_batch_cqe()

批量获取已完成的 CQE, 不阻塞

int io_uring_peek_batch_cqe(struct io_uring *ring, struct io_uring_cqe **cqes, unsigned int count);
  1. ring:指向 struct io_uring 的指针,表示 io_uring 环境
  2. cqes:一个指向指针数组的指针,用于存储返回的已完成CQE。
  3. count:要获取的 CQE 数量。

示例程序

io_uring_submint(&ring);

struct io_uring_cqe *cqe;
io_uring_wait_cqe(&ring, &cqe);

struct io_uring_cqe *cqes[128];
int nready = io_uring_peak_batch_cqe(&ring, cqes, 128);

int i = 0;
for(;i < nready; i++){
	//处理
}

io_uring_cq_advance(&ring, nready);

io_uring_cq_advance()

void io_uring_cq_advance(struct io_uring *ring, unsigned int steps);

推进 CQ 中的指针位置,以告知 io_uring 已经成功处理了一定数量的完成事件,并且可以释放这些事件所占用的资源

  • 15
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值