linux aio参数,Linux 异步 IO 之 Native AIO

Linux Native AIO

来看看 Linux 提供的 AIO 系统调用(自行封装的头文件 native_aio.h):

#ifndef __NATIVE_AIO_H__

#define __NATIVE_AIO_H__

#define _GNU_SOURCE

#include

#include

#include

#include

static inline int io_setup(unsigned nr_events, aio_context_t* ctx_idp)

{

return syscall(__NR_io_setup, nr_events, ctx_idp);

}

static inline int io_destroy(aio_context_t ctx)

{

return syscall(__NR_io_destroy, ctx);

}

static inline int io_submit(aio_context_t ctx, long nr, struct iocb** iocbpp)

{

return syscall(__NR_io_submit, ctx, nr, iocbpp);

}

static inline int io_getevents(aio_context_t ctx, long min_nr, long nr,

struct io_event* events, struct timespec* timeout)

{

return syscall(__NR_io_getevents, ctx, min_nr, nr, events, timeout);

}

static inline int io_cancel(aio_context_t ctx, struct iocb* iocb,

struct io_event* result)

{

return syscall(__NR_io_cancel, ctx, iocb, result);

}

#endif

通过 man 能够查到函数的描述,但是这些函数不是跨平台的,因此 libc 没有对这些函数进行封装,这里手动封装了一下。下面是一个使用示例:

#include "native_aio.h"

#include

#include

#include

#include

#include

#define NR_EVENT 1024

#define BUFSIZE 4096

int main(void)

{

int fd, ret = -1;

char* buf;

aio_context_t ctx;

struct io_event event;

struct iocb cb;

struct iocb* cblist[] = {&cb};

fd = open(__FILE__, O_RDONLY | O_DIRECT);

if (fd == -1) {

fprintf(stderr, "open(%s) failed: %s.\n", __FILE__, strerror(errno));

return -1;

}

buf = aligned_alloc(512, BUFSIZE);

if (!buf) {

fprintf(stderr, "aligned_alloc(%u) failed: %s.\n", BUFSIZE,

strerror(errno));

goto err1;

}

memset(&ctx, 0, sizeof(ctx));

ret = io_setup(NR_EVENT, &ctx);

if (ret != 0) {

fprintf(stderr, "io_setup failed: %s.\n", strerror(errno));

goto err2;

}

memset(&cb, 0, sizeof(cb));

cb.aio_data = (__u64)buf;

cb.aio_fildes = fd;

cb.aio_lio_opcode = IOCB_CMD_PREAD;

cb.aio_buf = (__u64)buf;

cb.aio_offset = 0;

cb.aio_nbytes = BUFSIZE;

ret = io_submit(ctx, 1, cblist);

if (ret != 1) {

fprintf(stderr, "io_submit failed: %s.\n", strerror(errno));

goto err3;

}

ret = io_getevents(ctx, 1, 1, &event, NULL);

if (ret != 1) {

fprintf(stderr, "io_getevents failed: %s.\n", strerror(errno));

goto err3;

}

if (event.res <= 0) {

fprintf(stderr, "io error: %s.\n", strerror(-(event.res)));

} else {

printf("read %lld byte(s):\n", event.res);

write(1, (const void*)(event.data), event.res);

}

err3:

io_destroy(ctx);

err2:

free(buf);

err1:

close(fd);

return ret;

}

程序首先打开一个只读文件,注意这里加了选项“O_DIRECT”,直接从磁盘读取文件。因为绕过了 page cache,所以一般程序都会自己来实现 cache;接着使用 aligned_alloc() 申请存放读取内容的 buffer,起始地址需要和磁盘逻辑块大小对齐(一般是 512 字节)。

准备工作完成后,调用 io_setup() 来初始化一个 aio_context_t 标识符,用于后续的 aio 操作。描述 aio 信息的主要是结构体 struct iocb(在 /usr/include/linux/aio_abi.h 中定义):

struct iocb {

/* these are internal to the kernel/libc. */

__u64 aio_data; /* data to be returned in event's data */

__u32 PADDED(aio_key, aio_reserved1);

/* the kernel sets aio_key to the req # */

/* common fields */

__u16 aio_lio_opcode; /* see IOCB_CMD_ above */

__s16 aio_reqprio;

__u32 aio_fildes;

__u64 aio_buf;

__u64 aio_nbytes;

__s64 aio_offset;

/* extra parameters */

__u64 aio_reserved2; /* TODO: use this for a (struct sigevent *) */

/* flags for the "struct iocb" */

__u32 aio_flags;

/*

* if the IOCB_FLAG_RESFD flag of "aio_flags" is set, this is an

* eventfd to signal AIO readiness to

*/

__u32 aio_resfd;

}; /* 64 bytes */

需要填充的字段包括:

aio_data:事件完成后随着 struct io_event 返回的内容,后面详细介绍;

aio_lio_opcode:IO 类型,可能包含以下取值:

IOCB_CMD_PREAD:对应系统调用 pread(),读取从指定位置开始的指定长度的内容,但是不改变文件偏移;

IOCB_CMD_PWRITE:对应系统调用 pwrite(),从指定位置写入指定长度的内容,但是不改变文件偏移;

IOCB_CMD_FSYNC:对应系统调用 fsync(),将元数据和文件内容写到磁盘;

IOCB_CMD_FDSYNC:对应 fdatasync(),将文件内容和必需的元数据写到磁盘;

IOCB_CMD_NOOP:不确定,据说还没被使用;

IOCB_CMD_PREADV:对应 preadv(),从当前位置读取指定数量和长度的 buffer,但不改变文件偏移;

IOCB_CMD_PWRITEV:对应 pwritev(),从当前位置写入指定数量和长度的 buffer,但不改变文件偏移。

aio_fildes:要操作的文件描述符;

aio_buf:要操作的 buffer 起始地址;

aio_nbytes:要读写的长度;

aio_offset:要读写的起始位置。

其它字段一定要置 0。

填充完成后就可以调用 io_submit() 提交请求了,请求提交后 io_submit() 会立即返回。接着可以调用 io_getevents() 获取在 aio_context_t 上提交的事件,函数的第二个参数是最少需要获取多少个事件,第三个参数是最多获取多少个事件,第四个参数是超时设置,如果超过指定事件还没等到最少个数的事件就返回,返回值就是实际返回的事件个数。

从 io_getevents() 返回后从 struct io_event 获取事件执行的结果:

struct io_event {

__u64 data; /* the data field from the iocb */

__u64 obj; /* what iocb this event came from */

__s64 res; /* result code for this event */

__s64 res2; /* secondary result */

};

其中的 data 字段就是 struct iocb 里的 aio_data;obj 就是 iocb 本身;res 小于等于 0 表示出错,-res 的值就是 errno,res 大于 0 表示读写成功的字节数;res2 不知道干啥用的。

最后用 io_destroy() 释放资源。

参考资料

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值