异步通知:很简单,一旦设备准备好,就主动通知应用程序,这种情况下应用程序就不需要查询设备状态,这是不是特像硬件上常提的“中断的概念”。上边比较准确的说法其实应该叫做“信号驱动的异步I/O”,信号是在软件层次上对中断机制的一种模拟。

阻塞I/O意味着一直等待设备可访问再访问,非阻塞I/O意味着使用poll()来查询是否可访问,而异步通知则意味着设备通知应用程序自身可访问。

上面三种方式,其实本身是没有优劣的,应该根据不同的应用场景合理选择罢了。

说到信号,在应用程序中,为了捕获信号(还捕获呢,不就是一个处理吗)可以使用signal()函数来设置对应的信号的处理函数。函数原型是void (*signal(int signo,void (*func)(int))) (int) 这个看起来费劲吧,不光你,我看着也费劲,没关系,给你来个例子:

void sigterm_handler(int signo) { char data[MAX_LEN]; int len; len=read(STDIN_FILENO, &data,MAX_LEN); data[len]=0; printf("Input available:%s\n",data); exit(0); } intmain(void) { int oflags; //启动信号驱动机制 signal(SIGIO, sigterm_handler);fcntl(STDIN_FILENO, F_SETOWN, getpid()); oflags = fcntl(STDIN_FILENO, F_GETFL);fcntl(STDIN_FILENO, F_SETFL, oflags | FASYNC); //建立一个死循环,防止程序结束 while(1);return 0; }
看了这段代码明白啥意思了吧,我也不多少了,咱们继续往下走..为了一个用户在用户空间中能处理一个设备释放的信号,它必须完成一下3份工作:
1)通过F_SETOWN控制指令设置设备文件的拥有者为本进程,这样从设备驱动中发出的信号才能被本进程收到。
2)通过F_SETFLIO控制命令设置设备文件支持FASYNC,即异步通知模式。
3)通过signal()链接信号和信号处理函数。
有了信号的发送,那么就一定得有信号的释放了:
在设备驱动和应用程序的异步通知交互中,仅仅在应用程序端捕获信号是不够的,因为信号没有的源头是在驱动端,因此要在适当的时机让设备驱动释放信号。
为了使设备支持异步通知机制,驱动程序中涉及三个操作
1)支持F_SETOWN命令,能在这个控制命令处理中设置filp->f_owner为对应的进程ID。不过此项工作已由内核完成,设备驱动无须处理。
2)支持F_SETFL命令的处理,每当FASYNC标志改变时,驱动程序中fasync()函数将得以进行。因此,驱动程序必须实现fasync()函数。
3)在设备资源可获得时,调用kill_fasync()函数激发相应的信号
驱动程序中上面的三步是和应用程序是一一对应的。如下图:

设备驱动中异步通知编程还是比较简单的,主要就是一些数据结构,和两个函数:

数据结构:fasync_struct结构体

函数:

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结构体指针的指针作为第四个参数传给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信号,可读时第三个参数设置为POLL_IN,可写时第三个参数设置为POLL_OUT,下边是释放信号的典型模版
static ssize_t xxx_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_ops) { 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; }
使用信号可以实现设备驱动与用户程序之间的异步通知,总体而言,设备驱动和用户空间要分别完成以下工作:用户空间设置文件的拥有者、FASYNC标志及捕获信号内核空间响应对文件的拥有者、FASYNC标志的设置,并在资源可获得时释放信号。 
Linux  2.6内核包含对AIO 的支持为用户空间提供统一的异步I/O 接口。在AIO中,信号和回调函数是实现内核空间用户空间应用程序通知的两种机制。

最新文章

  1. 用angular怎么缓存父页面数据
  2. TortoiseGit:记住用户名和密码
  3. Using python to process Big Data
  4. MVC 修饰标签
  5. scala学习资料
  6. HDU 3853LOOPS(简单概率DP)
  7. 关于Ajax&初见Ajax
  8. Linux下的sudo及其配置文件/etc/sudoers的详细配置说明
  9. android studio sexy editor性感编辑器设置
  10. Kafka详细的设计和生态系统
  11. flask开发用户管理系统wtf版
  12. IntelliJ IDEA编辑器光标定位错误的问题!
  13. 图片上传组件webuploader
  14. Spring Boot+Jsp启动异常
  15. TypeScript 快速学习
  16. sed命令实现文件内容替换总结案例
  17. angular笔记_3
  18. Android Activity学习笔记——Activity的启动和创建
  19. 获取AFP服务信息
  20. RN 获取地理位置

热门文章

  1. Shell 概述、截取字符操作等
  2. yii2:模块
  3. Autolayout .Compact or .Regular [iPhone/iPad]
  4. uva-11020-平衡树
  5. tflearn kears GAN官方demo代码——本质上GAN是先训练判别模型让你能够识别噪声,然后生成模型基于噪声生成数据,目标是让判别模型出错。GAN的过程就是训练这个生成模型参数!!!
  6. [eShopOnContainers 学习系列] - 01 - Roadmap and Milestones for future releases
  7. 3个IO口8个按键
  8. bat中for /f 如何截取任意行
  9. nginx结合tomcat一起使用
  10. 【Android】Android 学习记录贴