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;
}
阅读(1505) | 评论(0) | 转发(0) |