异步通知:即设备准备就绪时主动通知设备
基本实现原理:
1,当设备可读时,发送一个信号通知应用程序
2,应用程序接收到信号后,执行读操作
举例:异步通知编程:
void input_handler(int num)
{
char data[MAX_LEN];
int len;
//读取并输出STDIN_FILENO 上的输入
len = read(STDIN_FILENO, &data, MAX_LEN);
data[len] = 0;
printf("input available:%s\n", data);
}
int main()
{
int oflags;
//启动信号驱动机制
signal(SIGIO, input_handler);
fcntl(STDIN_FILENO, F_SETOWN, getpid());
oflags = fcntl(STDIN_FILENO, F_GETFL);
fcntl(STDIN_FILENO, F_SETFL, oflags | FASYNC);
//最后进入一个死循环,仅为保持进程不终止,如果程序中没有这个死循环
//会立即执行完毕
while (1);
}
由此可见,为了在用户空间中能处理一个设备释放的信号,它必须完成以下3 项工作。
通过F_SETOWN IO 控制命令设置设备文件的拥有者为本进程,这样从设备驱动发出的信号才能
被本进程接收到。
通过F_SETFL IO 控制命令设置设备文件支持FASYNC,即异步通知模式。
通过signal()函数连接信号和信号处理函数。
为了使设备支持异步通知机制,驱动程序中涉及以下3 项工作。
支持F_SETOWN 命令,能在这个控制命令处理中设置filp->f_owner 为对应进程ID。不过此项工
作已由内核完成,设备驱动无须处理。
支持F_SETFL 命令的处理,每当FASYNC 标志改变时,驱动程序中的fasync()函数将得以执行。
因此,驱动中应该实现fasync()函数。
在设备资源可获得时,调用kill_fasync()函数激发相应的信号。
设备驱动中异步通知:
1,数据结构是fasync_struct 结构体;
2,两个函数分别如下:
1 )处 理 FASYNC 标志变更的函数。
int fasync_helper(int fd, struct file *filp, int mode, struct fasync_struct **fa);
2 )释 放信号用的函数。void kill_fasync(struct fasync_struct **fa, int sig, int band);
基本编程模板
在设备结构体中加入fasync_struct 结构体指针
struct xxx_dev{
struct cdev cdev;
...
struct fasync_struct * async_queue; /*异步结构体指针*/
};
在设备驱动的fasync()函数中,只需要简单地将该函数的3 个参数以及fasync_struct 结构体指针的指针作为第4 个参数传入fasync_helper()函数即可。
static int xxx_fasync (int fd, struct file *filp, int mode)
{
struct xxx_dev *dev = filp->private_data;
return fasync_helper(fd, filp, mode, &dev->async_queue);
}
在设备资源可以获得时,应该调用kill_fasync()释放SIGIO 信号,可读时第3 个参数设置为POLL_IN,可写时第3 个参数设置为POLL_OUT.
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;
...
/* 产生异步读信号 */
if (dev->async_queue)
kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
...
}
最后,在文件关闭时,即在设备驱动的release()函数中,应调用设备驱动的fasync()函数将文件从异步通知的列表中删除。
static int xxx_release(struct inode *inode, struct file *filp)
{
struct xxx_dev *dev = filp->private_data;
/* 将文件从异步通知列表中删除 */
xxx_fasync(-1, filp, 0);
...
return 0;
}