linux设备驱动的异步通知和异步I/O
异步通知是设备一旦就绪,则主动通知应用程序,而不需要应用程序一直查询设备状态,这类似于硬件上“中断”的概念。在linux中提供了阻塞与非阻塞和轮询的设备访问机制,但如果加上异步通知机制,则设备访问的机制将变得更加完善。
异步通知机制不同于轮询机制,它是建立在信号的基础上的。在linux中定义了许多具有特定意义的信号(参考),因此异步通知机制可以说就是linux的信号机制,接下来将针对信号机制进行讨论。
信号的接收
对于用户程序来讲,为了捕捉信号,可以使用signal()函数来设置对应信号的处理函数。
1 | void (*signal(int sig, void (*func)(int)))(int); |
这两个接口都是在应用程序中接受并处理信号所依赖的函数接口。
信号的释放
但对于信号机制来说,只有接受显然是不够的,而信号的释放则是有设备的驱动程序来完成的。在设备驱动程序中增加信号释放的相关代码,使设备具有异步通知机制涉及到3项工作。
- 支持F_SETOWN命令,能在这个控制命令处理中设置filp->f_owner为对应进程ID
- 支持F_SETFL命令的处理,每当FASYNC标志改变时驱动程序的fasync()函数将得以执行。
- 在设备资源可用时调用kill_fasync()函数激发相应信号。
因此要完成一个支持异步通知机制的设备驱动,应该实现如下代码。
1 | struct xxx_dev { |
异步I/O
linux中常用的I/O模型是同步I/O,但为了提高CPU和I/O的吞吐率,异步I/O模型逐渐产生。
在linux中,AIO有多种实现,其中一种实现时在用户空间中的glibc库中实现的。它本质上借用了多线程模型,用开启新线程以同步的方法来做I/O,新的AIO辅助线程与发起AIO的线程以条件变量的方式来实现线程间同步。
glibc的aio实现主要提供了如下接口。
1 | int aio_read(struct aiocb *aiocbp); |
在用户空间实现AIO的缺点时增加了线程的负载和上下文切换的开销。因此linux 2.6版本以后,AIO已经成为了内核的一个标准特性。
对于内核AIO的调用,在用户空间通常使用libaio来做的。
而对于驱动程序来说,AIO的实现则要实现相应的file_operations中的相关接口。
1 | ssize_t (*read_iter) (struct kiocb *, struct iov_iter *); |
AIO一般由内核的通用代码处理,对于块设备和网络设备而言,一般在linux的核心层的代码已经解决。字符设备驱动一般不需要实现AIO支持。linux内核中对字符设备驱动实现AIO的特例包括drivers/char/mem.c里实现的null和zero等,因此对于AIO支持关于驱动的实现可参考之。
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 yxhlfx@163.com
文章标题:linux设备驱动的异步通知和异步I/O
本文作者:红尘追风
发布时间:2016-07-03, 18:32:53
原始链接:http://www.micernel.com/2016/07/03/linux%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E7%9A%84%E5%BC%82%E6%AD%A5%E9%80%9A%E7%9F%A5%E5%92%8C%E5%BC%82%E6%AD%A5I_O/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。