异步通知意味着设备可以通知应用程序自身可被访问,实现了异步IO。
在ldd3中给出了设备驱动实现异步信号的详细操作顺序:
1.当发出 F_SETOWN,什么都没发生,除了一个值被赋值给 filp->f_owner.
2.当 F_SETFL 被执行来打开FASYNC, 驱动的 fasync方法被调用.这个方法被调用无论何时 FASYNC的值在 filp->f_flags中被改变来通知驱动这个变化,因此它可正确地响应.这个标志在文件被打开时缺省地被清除.我们将看这个驱动方法的标准实现。
3.当数据到达,所有的注册异步通知的进程必须被发出一个SIGIO 信号.
主要看下第二步和第三步:
第二步:
执行F_SETFL来打开FASYNC,调用驱动的fasync方法。
当我们利用fcntl系统调用来打开FASYNC时,调用过程如下:
SYSCALL_DEFINE3(fcntl,unsigned int, fd, unsigned int, cmd, unsigned long, arg)
{
structfile *filp;
longerr = -EBADF;
filp= fget(fd);
if(!filp)
gotoout;
err= security_file_fcntl(filp, cmd, arg);
if(err) {
fput(filp);
returnerr;
}
err= do_fcntl(fd, cmd, arg, filp);
fput(filp);
out:
returnerr;
}
在do_fcntl中:
caseF_SETFL:
err= setfl(fd, filp, arg);
break;
在setfl函数中:
if(((arg ^ filp->f_flags) & FASYNC) && filp->f_op &&
filp->f_op->fasync){
error= filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0);
if(error < 0)
gotoout;
if(error > 0)
error= 0;
}
这样我们就调用驱动中的fasync函数,该函数的是调用了
intfasync_helper(int fd, struct file * filp, int on, structfasync_struct **fapp)
fasync_helper函数与kill_fasync配套使用:fasync_helper函数用来建立fasync的队列;kill_fasync函数负责发送信号,这样应用层可以响应信号,实现异步IO。