kernel 异步

来源:互联网 发布:国家药监局数据网查询 编辑:程序博客网 时间:2024/06/07 12:40

异步

一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询状态

用户空间处理一个设备释放的信号的三项工作:

/* specify handler for signal */signal(SIGIO, input_handler);/* current process owns this fd */fcntl(STDIN_FILENO, F_SETOWN, getpid());/* launch the async mechanism */flags = fcntl(STDIN_FILENO, F_GETFL);fcntl(STDIN_FILENO, F_SETFL, flags | FASYNC);

异步通知的设备驱动模版

struct xxx_dev {    struct cdev cdev;    ...    struct fasync_struct *async_queue;};static int xxx_fasync(int fd, struct file *filp, int mode){    struct xxx_dev *dev = filp->private_data;    /* when file has been set as async mode, add fd into async queue */    return fasync_helper(fd, filp, mode, &dev->async_queue);}static ssize_t xxx_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos){    struct xxx_dev *dev = filp->private_data;    ...    /* launch async read signal */    if (dev->async_queue)        kill_fasync(&dev->async_queue, SIGIO, POLL_IN);    ...}static int xxx_release(struct inode *inode, struct file *filp){    /* delete fd from async_queue */    xxx_fasync(-1, filp, 0);    ...    return 0;}

AIO

异步I/O的时序:
发起I/O动作后,并不等待I/O结束,
+ 要么过一段时间来查询之前的I/O请求完成情况
+ 要么I/O请求完成了会自动调用绑定的回调函数

AIO 多种实现

在用户空间的glibc库中实现

基于线程实现,通过 pthread_cond_signal() 实现线程间同步
1. aio_read()
2. aio_write()
3. aio_error() 确定请求的状态
4. aio_return()
5. aio_suspend()
6. aio_cancel()
7. lio_listio()

  • 采用 aio_return() 不断询问的方式
#include <aio.h>int fd, ret;struct aiocb my_aiocb;fd = open("file.txt", O_RDONLY);if (fd < 0)    printf("open failed\n");bzero(&my_aiocb, sizeof(struct aiocb));my_aiocb.aio_buf = malloc(BUFSIZE + 1);if (!my_aiocb.aio_buf)    printf("malloc failed\n");my_aiocb.aio_fildes = fd;my_aiocb.aio_nbytes = BUFSIZE;my_aiocb.aio_offset = 0;ret = aio_read(&my_aiocb);if (ret < 0)    printf("aio_read failed\n");while (aio_error(&my_aiocb) == EINPROGRESS)    continue;if ((ret = aio_return(&my_aiocb)) > 0)    /* read success */else    /* read failed */
  • 采用 aio_suspend() 阻塞的方式
struct aiocb *cblist[MAX_LIST];bzero((char *)cblist, sizeof(cblist));cblist[0] = &my_aiocb;...ret = aio_read(&my_aiocb);ret = aio_suspend(cblist, MAX_LIST, NULL);
  • 采用 lio_listio() 操作多个io control block
struct aiocb aiocb1, aiocb2;struct aiocb *cblist[MAX_LIST];aiocb1.aio_fildes = fd;aiocb1.aio_buf = malloc(BUFSIZE + 1);aiocb1.aio_nbytes = BUFSIZE;aiocb1.aio_offset = 0;aiocb1.aio_lio_opcode = LIO_READ;...bzero((char *)cblist, sizeof(cblist));cblist[0] = &aiocb1;cblist[1] = &aiocb2;.../* LIO_WAIT means block mode */ret = lio_listio(LIO_WAIT, list, MAX_LIST, NULL);

内核提供 libaio 的系统调用

AIO的读写请求都用 io_submit() 下发。下发前通过 io_prep_pwrite()io_prep_pread() 生成iocb的结构体,作为 io_submit() 的参数。这个结构体指定了读写类型、起始地址、长度和设备标识符等信息。读写请求下发之后,使用 io_getevents() 函数等待I/O完成事件。 io_set_callback() 设置一个AIO完成的回调函数。

file_operation 包含3个与AIO相关的成员函数:
* aio_read()
* aio_write()
* aio_fsync()

io_submit() 间接调用 file_operationaio_read()aio_write()

总结

内核包含对AIO的支持,为用户空间提供了统一的异步I/O接口。glibc也提供了不依赖内核的用户空间AIO支持。

0 0