您现在的位置是:亿华云 > 数据库

讲讲在Libuv中使用Io_Uring

亿华云2025-10-04 03:46:31【数据库】8人已围观

简介本文转载自微信公众号「编程杂技 」,作者theanarkh 。转载本文请联系编程杂技公众号。本文介绍如果在Libuv中使用io_uring。逻辑:1 申请一个io_uring对应的fd。2 初始化一个

 

本文转载自微信公众号「编程杂技  」,讲讲作者theanarkh 。使用转载本文请联系编程杂技公众号。讲讲

本文介绍如果在Libuv中使用io_uring。使用逻辑:

1 申请一个io_uring对应的讲讲fd。

2 初始化一个poll handle,使用封装1中的讲讲fd。

3 注册到Libuv的使用epoll中。

4 读取文件列表,讲讲给io_uring提交请求

5 io_uring完成,使用1中的讲讲fd可读,从而epoll返回。使用

6 Libuv的讲讲poll io阶段执行回调。

7 回调里获取io_uring的使用任务完成列表,拿到每个任务关联的讲讲请求,服务器租用执行回调。

#include <fcntl.h> #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <liburing.h> #include <stdlib.h> #include <uv.h> #define QUEUE_DEPTH 1 #define BLOCK_SZ    1024 // 前向声明 struct file_info; // 定义回调 typedef void (*file_callback)(struct file_info*); // 管理一个文件读取请求的结构体 struct file_info {      // 文件大小     off_t file_sz;     // 回调     file_callback cb;     // 读取的大小     int count;     // 文件名     char *name;     // 读取的数据     struct iovec iovecs[];      }; // 获取文件大小 off_t get_file_size(int fd) {      struct stat st;     if(fstat(fd, &st) < 0) {          perror("fstat");         return -1;     }     if (S_ISBLK(st.st_mode)) {          unsigned long long bytes;         if (ioctl(fd, BLKGETSIZE64, &bytes) != 0) {              perror("ioctl");             return -1;         }         return bytes;     } else if (S_ISREG(st.st_mode))         return st.st_size;     return -1; } // 向内核提交一个请求 int submit_read_request(char *file_path, file_callback cb, struct io_uring *ring) {      // 打开文件     int file_fd = open(file_path, O_RDONLY);     if (file_fd < 0) {          perror("open");         return 1;     }     // 获取大小     off_t file_sz = get_file_size(file_fd);     off_t bytes_remaining = file_sz;     int current_block = 0;     int blocks = (int) file_sz / BLOCK_SZ;     if (file_sz % BLOCK_SZ) blocks++;     // 申请内存     struct file_info *fi = malloc(sizeof(*fi) + (sizeof(struct iovec) * blocks));     // 保存文件名     fi->name = file_path;     // 计算和申请保存文件内容的内存     while (bytes_remaining) {          // 剩下的大小         off_t bytes_to_read = bytes_remaining;         // 一个buffer最大保存BLOCK_SZ大小         if (bytes_to_read > BLOCK_SZ)             bytes_to_read = BLOCK_SZ;         // 记录buffer大小         fi->iovecs[current_block].iov_len = bytes_to_read;         // 申请内存         void *buf;         if( posix_memalign(&buf, BLOCK_SZ, BLOCK_SZ)) {              perror("posix_memalign");             return 1;         }         // 记录内存地址         fi->iovecs[current_block].iov_base = buf;         // 下一块         current_block++;         // 更新剩下的大小         bytes_remaining -= bytes_to_read;     }     // 保存文件大小     fi->file_sz = file_sz;     // 获取一个io_uring的请求结构体     struct io_uring_sqe *sqe = io_uring_get_sqe(ring);     // 填充请求     io_uring_prep_readv(sqe, file_fd, fi->iovecs, blocks, 0);     // 保存请求上下文,响应的时候用     io_uring_sqe_set_data(sqe, fi);     // 保存回调     fi->cb = cb;     // 提交请求给内核     io_uring_submit(ring);     return 0; } // io_uring相关的结构体 struct io_uring_info {    int fd;   int32_t pending;   struct io_uring ring;   uv_poll_t poll_handle; }; // io_uring完成任务后,Libuv执行的回调 void uv__io_uring_done(uv_poll_t* handle, int status, int events) {      struct io_uring* ring;     struct io_uring_info* io_uring_data;     struct io_uring_cqe* cqe;     struct file_info* req;     // 获取Libuv中保存的io_uring信息     io_uring_data = uv_default_loop()->data;     ring = &io_uring_data->ring;     // 处理每一个完成的请求     while (1) {           io_uring_peek_cqe(ring, &cqe);         if (cqe == NULL)             break;         // 全部处理完则注销事件         if (--io_uring_data->pending == 0)            uv_poll_stop(handle);         // 拿到请求上下文         req = (void*) (uintptr_t) cqe->user_data;         // 记录读取的大小         req->count = cqe->res;         io_uring_cq_advance(ring, 1);         // 执行回调         req->cb(req);     }     // 处理完则退出     if (io_uring_data->pending == 0)         uv_stop(uv_default_loop()); } // 文件读取后的业务回调 void filedone(struct file_info* info) {      printf("读取的大小:%d,文件信息:%s => %d\n", (int)info->count, info->name, (int)info->file_sz);}int main(int argc, char *argv[]) {      if (argc < 2) {          fprintf(stderr, "请输入文件名称\n");         return 1;     }     // 申请一个io_uring相关的结构体     struct io_uring_info *io_uring_data = malloc(sizeof(*io_uring_data));     // 初始化io_uring     io_uring_queue_init(1, &io_uring_data->ring, 0);     // 初始化poll handle,源码库保存监听的fd     uv_poll_init(uv_default_loop(), &io_uring_data->poll_handle, io_uring_data->ring.ring_fd);     // 注册事件和回调     uv_poll_start(&io_uring_data->poll_handle, UV_READABLE, uv__io_uring_done);     // 保存io_uring的上下文在loop中     uv_default_loop()->data = (void *)io_uring_data;     // 处理每一个文件     for (int i = 1; i < argc; i++) {          submit_read_request(argv[i], filedone, &io_uring_data->ring);         io_uring_data->pending++;     }     // 开始事件循环     uv_run(uv_default_loop(), UV_RUN_DEFAULT);     // 退出     uv_loop_close(uv_default_loop());     io_uring_queue_exit(&io_uring_data->ring);     return 0; } 

编译过程

1 git clone https://github.com/axboe/liburing.git。执行./configure && make -j2 && sudo make install(make j2开启两个线程编译,根据自己的核数定)。

2 git clone https://github.com/libuv/libuv.git。执行./autogen.sh && ./configure && make -j2 && sudo make install。

3 安装完依赖后新建test.cc。然后编译 gcc -xc test2.cc -luring -luv(xc指定按c语言编译,c++的话限制不一样,会报错)。

4 新建两个测试文件hello.cc和world.cc 。执行 ./a.out hello.cc world.cc。

5 输出

读取的大小:6997,文件信息:hello.cc => 6997 读取的大小:11019,文件信息:world.cc => 11019 

代码仓库:https://github.com/theanarkh/learn-io_uring。

可以参考

1.https://github.com/shuveb/io_uring-by-example/blob/master/03_cat_liburing/main.c

2 https://github.com/libuv/libuv/pull/2322

高防服务器

很赞哦!(31199)