fasync这个东西就是为了使驱动的读写和application的读写分开,使得application可以在驱动读写时去做别的事,通过kill_fasync
(kill_fasync(&async, SIGIO, POLL_IN);)发SIGIO信号给应用,应用通过fcntl把自己这个SIGIO的信号换成自己的响应函数,当驱动发
(kill_fasync(&async, SIGIO, POLL_IN);)给应用时应用就调用了自己的handler去处理。fasync_helper作用就是初始化fasync这个东西,包括分配内存和设置属性。最后记得在驱动的release里把fasync_helper初始化的东西free掉。
POLL_IN POLL_OUT
=================================================================================
驱动程序向用户程序发信号 --------------------------------------------- 当设备有IO事件发生,就有机制保证向应用进程发送信号,显然设备驱动程序扮演重要角色,实际终端tty、网络socket等的标准实现已经包括了实时信号驱动的支持,所以,在Linux中它们可以如上直接使用。但有些设备的驱动程序还并没有支持,所以需要定制设备驱动程序。以下两个API应该是可以屏蔽所有相关琐碎操作(类似send_sig())的标准接口: int fasync_helper (int fd, struct file *filp, int mode, struct fasync_struct **fa); void kill_fasync (struct fasync_struct **fa, int sig, int band); 如果需要支持异步通知机制,如下设备结构中需要有异步事件通知队列(它应该与睡眠队列类似),并且增加fasync()接口的实现(该函数将本进程登记到async_queue上去)。 当一个打开的文件FASYNC标志变化时(调用fcntl()函数,设置FASYNC文件标志时),fasync()接口将被调用。
struct kpp_dev { struct cdev cdev; struct fasync_struct *async_queue; }; static int kpp_fasync(int fd, struct file *filp, int mode) { struct kpp_dev *dev = filp->private_data; return fasync_helper(fd, filp, mode, &dev->async_queue); }
事件发生的时机,就是中断服务程序或相应的软中断中调用kill_fasync(): if (dev->async_queue) kill_fasync(&dev->async_queue, SIGIO, POLL_IN); 如果是写操作,就是POLL_OUT。注意,无论用户进程设定了什么期望的信号,在这个环节,发送的一般就是SIGIO。注意在设备文件关闭(release方法)时,注意执行fasync(),使得本文件的操作从上述的设备异步事件等待链表中剥离。
static int kpp_release(struct inode *inode, struct file *filp) { kpp_fasync(-1, filp, 0); return 0; }
|