异步通知的意思是:一旦设备就绪,则主动通知应用程序进行访问。这样,使用无阻塞IO的应用程序无需轮询的查询设备是否可访问,达到减少CPU消耗的目的。相似于硬件上的“中断”的概念,比较准确的称谓是“信号驱动的异步IO”。
信号:是在软件层次上对中断机制的模拟。
在原理上,进程接收到一个信号(软件层)<==>(硬件层)处理器接收到一个中断。
假设假设recvfrom函数是一个系统调用:
阻塞IO,结合poll()的非阻塞IO及异步通知的区别
node
Linux中可用的信号及含义
信号被捕获时,有相应的信号处理函数进行处理<==>当中断产生时,有相应的中断处理函数进行处理。web
在用户程序中,使用signal()函数来设置对应信号的处理函数
原型:编程
void (*signal(int signum, void (*handler))(int)))(int);
能够分解为app
typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler));
含义:
当接收到signum信号时,执行handler函数指针指向的信号处理函数
为了在用户空间中处理一个设备释放的信号,需完成一下几项工做:
(1)经过IO控制命令(F_SETOWN)设置设备文件的拥有者为本进程,这样从设备驱动发出的信号才能被本进程接收
(2)经过IO控制命令(F_SETFL)设置设备文件支持FASYNC(异步通知),即调用驱动层的xxx_fasync()
(3)经过signal()函数链接信号和信号处理函数异步
为了使设备支持异步通知,驱动程序须要作如下几项工做:
(1) 支持F_SETOWN命令,能在这个控制命令处理中设置filp->fowner为对应进程ID。
(2) 支持F_SETFL命令的处理,每当FASYNC标志改变时,驱动程序中的fasync()函数将获得执行。
(3) 在设备资源可得到时,调用kill_fasync()函数激发相应的信号
处理FASYNC标志变动的函数async
int fasync_helper(int fd, struct file *filp, int mode, struct fasync_struct **fapp) { if(!on) { /* 将文件从异步通知中移除 */ return fasync_remove_entry(filp, fapp); } return fasync_add_entry(fd, filp, fapp); --> fasync_insert_entry(fd, filp, fapp, new); /* fa_fd指向应层打开此驱动时获得的FD.这也就是后面发送信号时能找到程号的缘由。*/ --> new->fa_fd = fd; rcu_assign_pointer(*fapp, new); --> smp_store_release (&p, RCU_INITIALZER(V)) --> WRITE_OWCE(*p, v) *p = v }
通知应用程序资源可用的函数==>其实就是内核给应用程序发信号svg
void kill_fasync(struct fasync_struct **fp, int sig, int band) { ... kill_fasync_rcu(rcu_dereference(*fp), sig, band); --> fown = &fa->fa_file->f_owner; /* 内核想应用程序发送信号,通知应用程序资源可用 */ send_sigio(fown, fa->fa_fd, band); }
支持异步通知的设备驱动模板函数
struct xxx_dev { struct cdev cdev; ... struct fasync_struct *async_queue; } 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); } 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); } static int xxx_release(struct inode *inode, struct file *filp) { /* 将文件从异步通知列表中删除 */ xxx_fasync(-1, filp, 0); ... } static const struct file_operation xxx_fops = { ... .fasync = xxx_fasync, };
应用程序直接调用fcntl3d
SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, unsigned long, arg) --> do_fcntl(fd, cmd, arg, f.file) --> switch(cmd) --> case F_SETOWN: --> f_setown(filp, arg, 1) --> __f_setown(filp, pid, type, force) --> f_modown(filp, pid, type, force) -->filp->f_owner.pid = get_pid(pid);//绑定进程号 --> case F_SETFL: --> setl(fd, filp, arg) --> filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0)