讲讲在Libuv中使用Io_Uring

git clone https://github.com/axboe/liburing.git。执行
首页 新闻资讯 行业资讯 讲讲在Libuv中使用Io_Uring

 [[410623]]

本文转载自微信公众号「编程杂技  」,作者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.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

  • 25.

  • 26.

  • 27.

  • 28.

  • 29.

  • 30.

  • 31.

  • 32.

  • 33.

  • 34.

  • 35.

  • 36.

  • 37.

  • 38.

  • 39.

  • 40.

  • 41.

  • 42.

  • 43.

  • 44.

  • 45.

  • 46.

  • 47.

  • 48.

  • 49.

  • 50.

  • 51.

  • 52.

  • 53.

  • 54.

  • 55.

  • 56.

  • 57.

  • 58.

  • 59.

  • 60.

  • 61.

  • 62.

  • 63.

  • 64.

  • 65.

  • 66.

  • 67.

  • 68.

  • 69.

  • 70.

  • 71.

  • 72.

  • 73.

  • 74.

  • 75.

  • 76.

  • 77.

  • 78.

  • 79.

  • 80.

  • 81.

  • 82.

  • 83.

  • 84.

  • 85.

  • 86.

  • 87.

  • 88.

  • 89.

  • 90.

  • 91.

  • 92.

  • 93.

  • 94.

  • 95.

  • 96.

  • 97.

  • 98.

  • 99.

  • 100.

  • 101.

  • 102.

  • 103.

  • 104.

  • 105.

  • 106.

  • 107.

  • 108.

  • 109.

  • 110.

  • 111.

  • 112.

  • 113.

  • 114.

  • 115.

  • 116.

  • 117.

  • 118.

  • 119.

  • 120.

  • 121.

  • 122.

  • 123.

  • 124.

  • 125.

  • 126.

  • 127.

  • 128.

  • 129.

  • 130.

  • 131.

  • 132.

  • 133.

  • 134.

  • 135.

  • 136.

  • 137.

  • 138.

  • 139.

  • 140.

  • 141.

  • 142.

  • 143.

  • 144.

  • 145.

  • 146.

  • 147.

  • 148.

  • 149.

  • 150.

  • 151.

  • 152.

  • 153.

  • 154.

  • 155.

  • 156.

  • 157.

  • 158.

  • 159.

  • 160.

  • 161.

  • 162.

  • 163.

  • 164.

  • 165.

  • 166.

  • 167.

  • 168.

  • 169.

  • 170.

  • 171.

  • 172.

  • 173.

  • 174.

  • 175.

  • 176.

  • 177.

编译过程

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
  • 1.

  • 2.

代码仓库: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

 

18    2021-07-11 23:25:29    Libuv epoll 文件