1.异步IO简介:
Linux 异步 I/O 是Linux 2.6 中的一个标准特性,其本质思想就是进程发出数据传输请求之后,进程不会被阻塞,也不用等待任何操作完成,进程可以在数据传输的时候继续执行其他的操作.相对于同步访问文件的方式来说,异步访问文件的方式可以提高应用程序的效率,并且提高系统资源利用率.直接 I/O 经常会和异步访问文件的方式结合在一起使用.
如下:
2.内核中关于异步IO的API:
实际上,异步IO在驱动中很少会涉及.它也属于fpos中的一个成员.如下:
ssize_t (*aio_read) (struct kiocb *iocb, char *buffer,size_t count, loff_t offset); ssize_t (*aio_write) (struct kiocb *iocb, const char *buffer,size_t count, loff_t offset); int (*aio_fsync) (struct kiocb *iocb, int datasync);aio_fsync 操作只对文件系统代码感兴趣, 因此我们在此不必讨论它. 其他 2 个, aio_read 和 aio_write, 看起来非常象常规的 read 和 write 方法, 但是有几个例外. 一个是 offset 参数由值传递; 异步操作从不改变文件位置, 因此没有理由传一个指针给它.
这里比较核心的参数是iocb,它是由内核创建、传递的,专门用于异步IO操作的.
异步IO状态查询:
int is_sync_kiocb(struct kiocb *iocb);如果这个函数返回一个非零值, 你的驱动必须同步执行这个操作.
完成一个异步IO操作:
int aio_complete(struct kiocb *iocb, long res, long res2);iocb 是起初传递给你的同一个 IOCB,并且 res 是这个操作的通常的结果状态.res2 是将被返回给用户空间的第2个结果码;大部分的异步 I/O 实现作为 0 传递 res2. 一旦你调用 aio_complete,你不应当再碰 IOCB 或者用户缓冲.
3.示例模板:
下面的示例模板来自LDD3.
static ssize_t scullp_aio_read(struct kiocb *iocb, char *buf, size_t count, loff_t pos) { return scullp_defer_op(0, iocb, buf, count, pos); } static ssize_t scullp_aio_write(struct kiocb *iocb, const char *buf, size_t count, loff_t pos) { return scullp_defer_op(1, iocb, (char *) buf, count, pos); }其中,scullp_aio_read()和scullp_aio_write()分别对应用户空间的异步读写的系统调用.两函数只调用了scullp_defer_op()函数:
struct async_work { struct kiocb *iocb; int result; struct work_struct work; }; static int scullp_defer_op(int write, struct kiocb *iocb, char *buf, size_t count, loff_t pos) { struct async_work *stuff; int result; /* Copy now while we can access the buffer */ if (write) result = scullp_write(iocb->ki_filp, buf, count, &pos); else result = scullp_read(iocb->ki_filp, buf, count, &pos); /* If this is a synchronous IOCB, we return our status now. */ if (is_sync_kiocb(iocb)) return result; /* Otherwise defer the completion for a few milliseconds. */ stuff = kmalloc (sizeof (*stuff), GFP_KERNEL); if (stuff == NULL) return result; /* No memory, just complete now */ stuff->iocb = iocb; stuff->result = result; INIT_WORK(&stuff->work, scullp_do_deferred_op, stuff); schedule_delayed_work(&stuff->work, HZ/100); return -EIOCBQUEUED; }注意到上述对iocb进行了状态的轮询,见上述语句:
if (is_sync_kiocb(iocb)) return result;一个异步IO的完成在等待队列里面:
static void scullp_do_deferred_op(void *p) { struct async_work *stuff = (struct async_work *) p; aio_complete(stuff->iocb, stuff->result, 0); kfree(stuff); }