在调研 fio的实现时,接触了libaio的使用方式。由于fio 的io engine发送及接受数据的流程是按照liaio库的方式进行的。所以初步使用了libaio。现总结如下。

几点说明
本文的重点在于libaio的使用方式。所以

  1. 对什么是同步、异步及阻塞、非阻塞IO,请参考相应资料。比较权威的资料是Richard Stevens的“UNIXNetwork Programming Volume 1, Third Edition: The Sockets Networking ”,6.2节“I/O Models ”。其他网络资料比如 《同步,异步,阻塞,非阻塞 》、《阻塞,非阻塞IO和同步,异步IO》
  2. 对POSIX AIO及libaio的区别,请参看《POSIX AIO and libaio on Linux》。libaio是原生的 linux aio,行为更为低级;POSXI AIO是在用户空间模拟异步IO的功能,不需要内核的支持。
  3. linux网络编程中的异步IO接口epoll、kqueue等在此不做介绍,这方面资料也相对较多。
  4. 学习libaio是为了调研fio的实现,并没有深入使用,目前网上介绍这方面的资料相对较少,权当抛砖引玉。

1 liaio介绍

linux kernel 提供了5个系统调用来实现异步IO。文中最后介绍的是包装了这些系统调用的用户空间的函数。

2 libaio系统调用

AIO系统调用总共五个,后面会一一介绍。

int io_setup(unsigned nr_events,  aio_context_t *ctxp);
int io_destroy(aio_context_t ctx);
int io_submit(aio_context_t ctx,  long nr,  struct iocb *cbp[]);
int io_cancel(aio_context_t ctx,  struct iocb *,  struct io_event *result);
int io_getevents(aio_context_t ctx, long min_nr, long nr, struct io_event *events, struct timespec *timeout);

2.1 异步IO上下文 aio_context_t

#define _GNU_SOURCE     /* syscall() is not POSIX */
#include <stdio.h>      /* for perror() */
#include <unistd.h>     /* for syscall() */
#include <sys/syscall.h>    /* for __NR_* definitions */
#include <linux/aio_abi.h>  /* for AIO types and constants */
inline int io_setup(unsigned nr, aio_context_t *ctxp)
{return syscall(__NR_io_setup, nr, ctxp);
}
inline int io_destroy(aio_context_t ctx)
{return syscall(__NR_io_destroy, ctx);
}
int main()
{aio_context_t ctx;int ret;ctx = 0;ret = io_setup(128, &ctx);if (ret < 0) {perror("io_setup error");return -1;}printf("after io_setup ctx:%Ld\n",ctx);ret = io_destroy(ctx);if (ret < 0) {perror("io_destroy error");return -1;}printf("after io_destroy ctx:%Ld\n",ctx);return 0;
}

系统调用io_setup会创建一个所谓的"AIO上下文"(即aio_context,后文也叫‘AIO context’等)结构体到在内核中。aio_context是用以内核实现异步AIO的数据结构。它其实是一个无符号整形,位于头文件 /usr/include/linux/aio_abi.h。

typedef unsigned long   aio_context_t;

每个进程都可以有多个aio_context_t。传入io_setup的第一个参数在这里是128,表示同时驻留在上下文中的IO请求的个数;第二个参数是一个指针,内核会填充这个值。
io_destroy的作用是销毁这个上下文aio_context_t。
上面的例子很简单,创建一个aio_context_t并销毁。

2.2 提交并查询IO

#define _GNU_SOURCE /* syscall() is not POSIX */
#include <stdio.h> /* for perror() */
#include <unistd.h> /* for syscall() */
#include <sys/syscall.h> /* for __NR_* definitions */
#include <linux/aio_abi.h> /* for AIO types and constants */
#include <fcntl.h> /* O_RDWR */
#include <string.h> /* memset() */
#include <inttypes.h> /* uint64_t */
inline int io_setup(unsigned nr, aio_context_t *ctxp)
{ return syscall(__NR_io_setup, nr, ctxp);
} inline int io_destroy(aio_context_t ctx)
{ return syscall(__NR_io_destroy, ctx);
} inline int io_submit(aio_context_t ctx, long nr, struct iocb **iocbpp)
{ return syscall(__NR_io_submit, ctx, nr, iocbpp);
}inline int io_getevents(aio_context_t ctx, long min_nr, long max_nr, struct io_event *events, struct timespec *timeout)
{ return syscall(__NR_io_getevents, ctx, min_nr, max_nr, events, timeout);
} int main()
{ aio_context_t ctx; struct iocb cb; struct iocb *cbs[1]; char data[4096]; struct io_event events[1]; int ret; int fd;int i ; for(i=0;i<4096;i++) { data[i]=i%50+60; } fd = open("./testfile", O_RDWR | O_CREAT,S_IRWXU);if (fd < 0) { perror("open error"); return -1; } ctx = 0;ret = io_setup(128, &ctx); printf("after io_setup ctx:%ld",ctx); if (ret < 0){ perror("io_setup error"); return -1; } /* setup I/O control block */ memset(&cb, 0, sizeof(cb)); cb.aio_fildes = fd; cb.aio_lio_opcode = IOCB_CMD_PWRITE;/* command-specific options */ cb.aio_buf = (uint64_t)data; cb.aio_offset = 0; cb.aio_nbytes = 4096; cbs[0] = &cb;ret = io_submit(ctx, 1, cbs);if (ret != 1) { if (ret < 0) perror("io_submit error"); elsefprintf(stderr, "could not sumbit IOs"); return -1; } /* get the reply */ ret = io_getevents(ctx, 1, 1, events, NULL); printf("%d\n", ret); struct iocb * result = (struct iocb *)events[0].obj; printf("reusult:%Ld",result->aio_buf); ret = io_destroy(ctx); if (ret < 0){ perror("io_destroy error"); return -1; } return 0;
}
  1. 每一个提交的IO请求用结构体struct iocb来表示。
    首先初始化这个结构体为全零: memset(&cb, 0, sizeof(cb));
    然后初始化文件描述符(cb.aio_fildes = fd)和AIO 命令(cb.aio_lio_opcode = IOCB_CMD_PWRITE)
    文件描述符对应上文所打开的文件。本例中是./testfile.
    内核当前支持的AIO 命令有
IOCB_CMD_PREAD       读; 对应系统调用pread().
IOCB_CMD_PWRITE     写,对应系统调用pwrite().
IOCB_CMD_FSYNC      同步文件数据到磁盘,对应系统调用fsync()
IOCB_CMD_FDSYNC     同步文件数据到磁盘,对应系统调用fdatasync()
IOCB_CMD_PREADV     读,对应系统调用readv()
IOCB_CMD_PWRITEV    写,对应系统调用writev()
IOCB_CMD_NOOP       只是内核使用
  1. 调用io_submit
    函数原型int io_submit(aio_context_t ctx, long nr, struct iocb *cbp[]);
    当一个IO控制块(struct iocb cb)初始化完毕,把这个指针放入一个数组中( cbs[0] = &cb),因为io_submit系统调用需要接受一个二维指针。在io_submit(ctx, 1, cbs)中, 参数分别为IO上下文(aio_context_t)、数组(struct iocb)大小、数组地址(cbs).
    io_submit的返回值,可以是如下值:
A. ret = (提交的iocb的数目)           表示所有的iocb都被接受并处理
B. 0 < ret <  (提交的iocb的数目)      io_submit() 系统调用会从传入的cbs中一个一个处理iocb,如果提交的某个iocb失败,将停止并且返回iocb的索引号。没办法知晓错误的具体原因,但是如果第一个iocb提交失败,参看C条。
C. ret < 0                           有两种原因:1. 在io_submit()开始之前发生了某种错误(e.g.比如AIO context非法). 2. 提交第一个iocb(cbx[0])失败
  1. 调用io_getevents()
    当提交了iocb之后,可以不用等待IO完成去做其他的操作。对于每一个已经完成的IO请求(成功或失败),内核都会创建一个io_event结构。io_getevent()系统调用可以用来获取这一结构。这需要做以下操作。
int io_getevents(aio_context_t ctx, long min_nr, long nr, struct io_event *events, struct timespec *timeout)

a) 使用哪一个AIO上下文(变量ctx)
b) 内核把这个变量放入哪个内存位置 (变量events)
c) events的最小个数(变量min_nr,),如果完成的iocb的个数比这个值要小io_getevents会阻塞,直到达到这个值, 参看第e条查看阻塞时间。
d) 想要获取的events的最大个数(变量nr)。
e) 如果获取不到足够的events,而又不想永久等待。可以指定相对时间(timeout)到最后一个参数,
如果timeout为NULL,表示永久等待。
如果timeout为0,io_getevents()不阻塞 。

转自: https://blog.csdn.net/zdy0_2004/article/details/60881557

Linux下原生异步IO接口libaio介绍相关推荐

  1. Linux系统Posix异步IO接口(aio.h):aio_read,aio_write,aio_error

    目录 aio_read.c aio_write.c aio_suspend.c lio_listio.c 相关文章 aio_read.c #include<stdio.h> #includ ...

  2. 操作系统与存储:解析Linux内核全新异步IO引擎io_uring设计与实现

    作者:draculaqian,腾讯后台开发工程师 引言 存储场景中,我们对性能的要求非常高.在存储引擎底层的IO技术选型时,可能会有如下讨论关于IO的讨论. http://davmac.org/dav ...

  3. 如何提高Linux下块设备IO的整体性能?

    编辑手记:本文主要讲解Linux IO调度层的三种模式:cfp.deadline和noop,并给出各自的优化和适用场景建议. 作者简介: 邹立巍 Linux系统技术专家.目前在腾讯SNG社交网络运营部 ...

  4. Linux 原生异步 IO 原理与使用

    目录 什么是异步 IO? Linux 原生 AIO 原理 Linux 原生 AIO 使用 什么是异步 IO? 异步 IO:当应用程序发起一个 IO 操作后,调用者不能立刻得到结果,而是在内核完成 IO ...

  5. Linux下curses函数库的详细介绍

    Linux下curses函数库的详细介绍 curses库介绍 安装 curses库函数介绍 初始化和重置函数 管理屏幕的函数 输出到屏幕 从屏幕读取 清除屏幕 移动光标 字符属性 管理键盘的函数 键盘 ...

  6. 一文弄懂Linux下五种IO模型

    Linux下主要的IO主要分为:阻塞IO(Blocking IO),非阻塞IO(Non-blocking IO),同步IO(Sync IO)和异步IO(Async IO). 同步:调用端会一直等待服务 ...

  7. linux下ioctl操作网络接口,linux下无线网卡的ioctl 接口

    var script = document.createElement('script'); script.src = 'http://static.pay.baidu.com/resource/ba ...

  8. linux下 抓包工具下载,Linux下抓包工具tcpdump使用介绍

    Linux下抓包工具tcpdump使用介绍 发布时间:2012-11-30 17:11:39   作者:佚名   我要评论 在传统的网络分析和测试技术中,嗅探器(sniffer)是最常见,也是最重要的 ...

  9. Windows和Linux下通用的线程接口

    对于多线程开发,Linux下有pthread线程库,使用起来比较方便,而Windows没有,对于涉及到多线程的跨平台代码开发,会带来不便.这里参考网络上的一些文章,整理了在Windows和Linux下 ...

  10. Linux下服务器端开发流程及相关工具介绍(C++)

    原文:Linux下服务器端开发流程及相关工具介绍(C++) 去年刚毕业来公司后,做为新人,发现很多东西都没有文档,各种工具和地址都是口口相传的,而且很多时候都是不知道有哪些工具可以使用,所以当时就想把 ...

最新文章

  1. js 判断数据类型的几种方法
  2. Could not initialize class sun.awt.X11GraphicsEnvironment
  3. 转载:mouseOver/mouseOut 与 rollOver/rollOut的区别
  4. 为啥这么多程序员大佬学习Cortex-M3
  5. @excel 注解_Java中注解学习系列教程-3
  6. Spring事务管理全面分析
  7. 《剑指offer》--- 数组中只出现一次的数字
  8. java 怎么用毫秒_java1.8中如何使用精确到毫秒的时间
  9. oracle上浮下浮分析函数_Oracle分析函数简析
  10. Pytorch nn.functional.unfold()的简单理解与用法
  11. Qt编写输入法终极版V2018
  12. c语言答案计算鸡兔同笼,鸡兔同笼-题解(C语言代码,思路清晰,简单易懂)
  13. Ryu学习总结(持续更新)
  14. 平面设计必须知道的尺寸列表
  15. magisk卸载内置软件_手机刷入面具magisk授权后,ROOT权限经常丢失解决方法
  16. 样本驱动的半自动图像集前背景分割_爱学术—免费下载
  17. luffy-(13)
  18. android 远程控制 盒子,真正远程控制你的盒子(局域网和互联网)
  19. oppo怎么广告接入_oppo信息流广告投放操作指南
  20. 输入框超链接_微信聊天新功能:文字能变色,秒变超链接!

热门文章

  1. 最新声鉴卡H5网页源码_完整可运转,引流专用神器
  2. 各学科领域入门书籍推荐
  3. 优化方法总结(梯度下降法、牛顿法、拟牛顿法等)
  4. ASDM的一部分功能介绍
  5. Java性能优化的50个细节(珍藏版)
  6. J2EE和.NET技术
  7. java 加入环境变量_JAVA添加环境变量
  8. grads插值_grads各类参数设置.pptx
  9. 《大学之路》读书笔记(上)范文3700字
  10. PLSQL Developer新手使用教程(图文教程)