一、异步的概念
在使用阻塞或者非阻塞IO时,都是由应用程序询问设备是否空闲。使用异步时,可以由设备驱动通知应用程序,设备变成可用状态。
二、操作过程
1、应用程序
①注册信号处理函数
sighandler_t signal(int signum, sighandler_t handler)
signum:要设置处理函数的信号。
handler :信号的处理函数。
返回值:设置成功的话返回信号的前一个处理函数,设置失败的话返回 SIG_ERR。
通过signal函数,使得signal实现设置指定信号的信号处理函数。
②将本应用程序的进程号告诉内核
fcntl(fd, F_SETOWN, getpid())
③开启异步通知
flags = fcntl(fd, F_GETFL); /* 获取当前的进程状态 */
fcntl(fd, F_SETFL, flags | FASYNC); /* 开启当前进程异步通知功能 */
2、驱动程序
①、在设备结构体中定义一个 fasync_struct 类型的结构体:
struct fasync_struct {
spinlock_t fa_lock;
int magic;
int fa_fd;
struct fasync_struct *fa_next;
struct file *fa_file;
struct rcu_head fa_rcu;
};
struct imx6uirq_dev {
............................
struct fasync_struct *async_queue; /* 异步相关结构体 */
}
②、实现 fileoperations 操作集里的 fasync 函数,并使用 fasync_helper 来初始化 fasync_struct 结构体。
int (*fasync) (int fd, struct file *filp, int on)
int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
fasync_helper 函数的前三个参数就是 fasync 函数的那三个参数,第四个参数就是要初始化
的 fasync_struct 结构体指针变量。当应用程序通过“fcntl(fd, F_SETFL, flags | FASYNC)”改变
fasync 标记的时候,驱动程序 file_operations 操作集中的 fasync 函数就会执行。
static int xxx_fasync(int fd, struct file *filp, int on)
{
struct xxx_dev *dev = (xxx_dev)filp->private_data;
if (fasync_helper(fd, filp, on, &dev->async_queue) < 0)
return -EIO;
return 0;
}
static struct file_operations xxx_ops = {
......
.fasync = xxx_fasync,
......
};
③当设备可以访问的时候,驱动程序需要向应用程序发出信号
void kill_fasync(struct fasync_struct **fp, int sig, int band)
fp:要操作的 fasync_struct。
sig :要发送的信号。
band :可读时设置为 POLL_IN,可写时设置为 POLL_OUT。
返回值:无。
④、在release函数里,释放 fasync_struct 结构体
static int xxx_release(struct inode *inode, struct file *filp)
{
return xxx_fasync(-1, filp, 0); /* 删除异步通知 */
}