0%

周谈(24)-Linux内置的异步AIO使用

今天在看libkcapi源码的时候,看到了一个struct iocb的结构。注释说这个是什么AIO相关的数据结构。上网查了一下,这是Linux内置的异步I/O机制的一个概念。

三月份的时候,写了一篇关于Linux IO的select、poll、epoll接口的使用。异步IO也比较容易理解了,就是为了使程序不阻塞而实现的一种机制。

AIO的实现也就是提交一个IO请求,然后流程继续处理,过一段时间来查询一下提交IO的状态,确定IO操作是否完成。

实现及接口

AIO相关的系统调用实现在内核fs/aio.c文件中,头文件是<linux/aio_abi.h>。AIO提供了5个API:

1
2
3
4
5
6
7
#include <linux/aio_abi.h>
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 **iocbpp);
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);

每个IO请求(对应结构体struct iocb)都被提交到一个AIO的上下文(对应aio_context_t ,其实是一个数字)中,上下文通过 io_setup创建, io_destroy销毁。

io_submit函数一次可以提交多个IO请求到指定的上下文中。

在提交IO请求之后,可以去处理其它的事情。过段时间,通过io_getevents来获取一下IO请求状态。需要指定前面的上下文, 然后就是一个iocb的缓存区,等待完成IO的最少、最大数目。如果没有达到最少的IO数,则会阻塞直到满足条件。当然,也可以设置超时时间。

具体的结构定义这边就不详解了。

要使用Linux AIO的机制有几种方法:

  • 使用内核的系统调用
  • 使用用户空间上的libaio库
  • 自己在用户态模拟假的AIO,不需要内核支持。 目前有一个实现 librt

也就是说,我们在用户态不能直接使用上面的那些接口,而是使用libaio这个库提供的接口来实现,或者使用系统调用。

下面是一个简单的例子,自己封装个同名的接口,内部使用系统调用,通过AIO机制往文件写入一段字符串。

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

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>

#include <unistd.h>
#include <fcntl.h>
#include <sys/syscall.h>
#include <linux/aio_abi.h>

int io_setup(unsigned nr, aio_context_t *ctxp) {
return syscall(__NR_io_setup, nr, ctxp);
}

int io_destroy(aio_context_t ctx) {
return syscall(__NR_io_destroy, ctx);
}

int io_submit(aio_context_t ctx, long nr, struct iocb **iocbpp) {
return syscall(__NR_io_submit, ctx, nr, iocbpp);
}

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);
}


#define MAX_IO_NUM (10)
int main(const int argc, char *argv[])
{
if (argc < 3)
{
printf("param less 3\r\n");
exit(1);
}

char *data = argv[1];
char *file_name = argv[2];


printf("get data %s file_name %s\r\n", data, file_name);

int fd;
aio_context_t ctx;
struct iocb io;
struct iocb *pio[1] = {&io};
struct io_event e[1];
struct timespec timeout;

memset(&ctx, 0, sizeof(ctx));
if (io_setup(MAX_IO_NUM, &ctx))
{
printf("io setup error\r\n");
exit(1);
}

fd = open(file_name, O_CREAT|O_RDWR);
if (fd < 0)
{
perror("open error");
io_destroy(ctx);
exit(1);
}

memset(&io, 0, sizeof(io));
io.aio_fildes = fd;
io.aio_lio_opcode = IOCB_CMD_PWRITE;

// io.aio_reqprio = 0;
io.aio_buf = (uint64_t)data;
io.aio_nbytes = strlen(data);
io.aio_offset = 0;

// io.aio_data = data;
if (io_submit(ctx, 1, pio) != 1)
{
close(fd);
io_destroy(ctx);
perror("io submit error");
exit(1);
}

timeout.tv_sec = 1;
int count = 1;
while (1)
{
printf("start get events %d times\r\n", count++);
if (io_getevents(ctx, 1, 1, e, &timeout) == 1)
{
close(fd);
printf("get it\r\n");
break;
}

}

io_destroy(ctx);

return 0;
}

效果如下:

1
2
3
4
5
6
7
8
9
10
root@keep-VirtualBox:/media/sf_VM_SHARE/code/blog_code/linux-kernel# ./aio 222222222222222222222222222 /tmp/2.txt
get data 222222222222222222222222222 file_name /tmp/2.txt
start get events 1 times
get it
root@keep-VirtualBox:/media/sf_VM_SHARE/code/blog_code/linux-kernel# more /tmp/2.txt
222222222222222222222222222
root@keep-VirtualBox:/media/sf_VM_SHARE/code/blog_code/linux-kernel#
root@keep-VirtualBox:/media/sf_VM_SHARE/code/blog_code/linux-kernel#


可以看到在程序执行完之后, 文件有内容了。

好了,又Get 一个新知识。

参考链接: https://oxnz.github.io/2016/10/13/linux-aio

更多

前段时间写的一个测试框架代码初版基本完成了,这两周一直在写文档, 不断的修改演化,画那个架构图画的有点儿晕了。正常的话,下周也要转正了吧,还得写个ppt,写文档真的也是一个能力啊,好好加油!

晚上回来出去跑了个步,然后再回来洗个澡。就把手机丢一边,专心搞了这篇文章,时间贼快啊, 23:30了,晚安!


行动,才不会被动!

欢迎关注个人公众号 微信 -> 搜索 -> fishmwei,沟通交流。

博客地址: https://fishmwei.github.io

掘金主页: https://juejin.cn/user/2084329776486919