博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux 内核101:异步IO
阅读量:6412 次
发布时间:2019-06-23

本文共 3497 字,大约阅读时间需要 11 分钟。

本文参考了:

  • 《Understanding the Linux Kernel, Third Edition》16.4章

简述

POSIX 异步 IO interface(AIO)定义了允许进程创建一个或多个异步的 IO 操作的接口。进程可以在 IO 操作完成之后得到操作系统的通知,手段包括:不通知、信号、实例化thread。

POSIX 标准

注意:这只是 POSIX(The Portable Operating System Interface)定义的接口,并不是实现。Linux 内核对异步 IO 的具体实现在后面。(This is an API, not implementation!

POSIX 1003.1标准定义了异步访问文件的 library function:

系统调用 描述
aio_read() 异步读取文件
aio_write() 异步写入文件
aio_fsync 发出对当前所有 outstanding 的异步IO操作进行 flush 的请求 (不会阻塞)
aio_error() 获取一个处于 outstanding 状态异步 IO 操作的 error code
aio_return() 获取一个已经完成的异步 IO 操作的返回码
aio_cancel() 取消一个outstanding的异步 IO 操作
aio_suspend() 暂停进程,直到至少有一个outstanding的异步 IO 操作完成

使用异步 IO 其实是很简单的。大致来说分为三步:

  1. 程序先是使用普通的open()系统调用。
  2. 然后创建一个叫做aiocb的 control block填满,比较重要的一些字段如下:
  • aio_fildes: 对应文件的 fd(open()系统调用返回的)
  • aio_buf : 为此文件准备的User mode buffer
  • aio_nbytes : 有多少 bytes 应该被传输
  • aio_offset : read、write 操作应该从哪个 offset 开始(注意这个和同步的 IO 操作是独立)
  • aio_sigevent : 调用者想要什么方式获取 IO 成功的回调通知,包括SIGEV_NONESIGEV_SIGNALSIGEV_THREAD,分别对应上文提到的三个通知方式。
  • aio_lio_opcode : IO 操作类型:read write sync

具体的定义如下:

#include 
struct aiocb { /* The order of these fields is implementation-dependent */ int aio_fildes; /* File descriptor */ off_t aio_offset; /* File offset */ volatile void *aio_buf; /* Location of buffer */ size_t aio_nbytes; /* Length of transfer */ int aio_reqprio; /* Request priority */ struct sigevent aio_sigevent; /* Notification method */ int aio_lio_opcode; /* Operation to be performed; lio_listio() only */ /* Various implementation-internal fields not shown */};/* Operation codes for 'aio_lio_opcode': */enum { LIO_READ, LIO_WRITE, LIO_NOP };复制代码
  1. 最后把aiocb这个 control block 的地址传给aio_read()或者 aio_write()

这两个函数都会在kernel或library将对应 IO 的数据传输加入传输队列之后立即退出。

之后进程可以用aio_error()检查异步 IO 的进行状态:

aio_error()返回值 描述
EINPROGRESS 还在传输中
0 成功完成
其他错误码 操作失败

可以用aio_return()获取成功read或write了多少个 bytes,或者-1表示失败。

Linux 内核支持

在操作系统内核不支持异步 IO 的情况下,异步 IO 也能够实现,实现思路如下:aio_read()aio_write()先克隆当前进程,让子进程执行同步的read()write()系统调用,然后父进程结束aio_read()aio_write(),从而实现非阻塞,主进程可以开始做其他事情。显然,这种没有得到内核支持的异步 IO 操作是比较低效的。

Linux 内核从2.6版本起开始支持下面这些系统调用:

系统调用 描述
io_setup() 为当前进程创建一个异步IO上下文(asynchronous i/o contex)
io_submit() 提交一个或多个异步 IO 操作
io_getevents() 获取一些 outstanding 异步 IO 的运行状态
io_cancel() 取消一个异步 IO
io_destroy() 摧毁当前进程的异步 IO 上下文

异步 IO上下文(AIO context)

用户态的进程要调用io_submit()之前,先得调用io_setup()创建异步 IO 上下文。

基本上来说,一个 AIO context 就是一个用于追踪所有进行中的异步IO操作的数据结构,这个 struct 叫做kioctx。一个应用可能会创建多个 AIO context,一个进程的所有kioctx用一个链表相连:ioctx_list

这个ioctx_list保存在该进程的memory descriptor上:

来源于《Understanding the Linux Kernel, Third Edition》 P355

kioctx中有一个重要的数据结构:AIO ringAIO ring的作用是:kernel 把 outstanding 的 异步 IO 操作完成情况写到这里面,由于AIO ring是位于进程的地址空间的,所以进程可以直接从这个数据接口里面读取异步 IO 的状态,而不用执行相对较慢的系统调用。

提交异步 IO 操作

aio_submit()系统调用包含三个参数:

  • ctx_id : io_setup()返回的 id
  • iocbpp : 一个iocb指针的列表,iocb包含描述一个异步 IO 操作的信息。
  • nr : iocbpp的长度

其中iocb和 POSIX 标准中的aiocb是一样的,同样包含aio_fildes, aio_buf, aio_nbytes, aio_offset, aio_lio_opcode这些字段。

Linux kernel 有一个 service routine : sys_io_submit(),执行下列操作:

  1. 检查iocbpp列表包含的iocb descriptors是不是合法的。
  2. 通过xtx_idioctx_list 中检索出对应的kioctx
  3. 对每一个iocb descriptor,执行下列操作:
  • 通过aio_fildes获取文件 fd。
  • 为该异步 IO 操作新建一个kiocb descriptor。
  • 检查 AIO ring中是否有足够的空间来存储完成结果。
  • 根据IO 类型(aio_lio_opcode字段)设置ki_retry方法。
  • 执行aio_run_iocb()函数,这个函数本质上就是调用上一步的ki_retry方法,开始执行 IO 操作。如果ki_retry方法返回EIOCBRETRY,就表示该异步 IO 操作已经被提交了,但是还没有完成。一段时间后aio_lio_opcode之后会被再次执行,当提示 IO 完成时,就调用aio_complete()将完成状态写入到 AIO ring

转载地址:http://dzura.baihongyu.com/

你可能感兴趣的文章
centos配置golang & SVN客户端配置
查看>>
【HNOI 2017】大佬
查看>>
Appium+Robotframework实现Android应用的自动化测试-5:RIDE中AppiumLibrary的配置
查看>>
git 提交代码到开源中国
查看>>
C# 指定平台编译项目
查看>>
「Luogu3355」 骑士共存问题
查看>>
c#后台线程更新界面
查看>>
冒泡排序-----选择排序
查看>>
CRC从原理到实现
查看>>
jquery-json 插件使用方法
查看>>
List集合共性方法
查看>>
javaweb中关于转发与重定向的写法
查看>>
mariadb配置允许远程访问方式
查看>>
记 悟空传 里的一些话
查看>>
Network Stack‎ : CookieMonster
查看>>
python中的切片问题
查看>>
Elastic 技术栈之快速入门
查看>>
excel数据的处理
查看>>
Agile PLM EC 301 Workspace CAD working directory vs. EC Workspaces
查看>>
【HDOJ】1362 The Bermuda Triangle
查看>>