Linux设备驱动程序 之 异步通知
尽管大多数时候阻塞型和非阻塞型操作的组合以及select方法可以有效的查询设备,但是某些时候用这种技术处理就效率不搞了;
例如:一个进程在低优先级执行长的循环计算,但又需要尽可能快的处理输入数据,如果该进程正在响应来自数据收集外设新观测的数据,则应该在新数据可用时理解知晓并处理;我们可以使用poll来检查,但是跟好的做法是通过异步通知,应用程序可以再数据可用时收到一个信号,而不需要不停的使用轮询来关注数据;
从应用程序的角度
启用文件的异步通知机制,用户程序必须执行两个步骤:
1. 需要制定一个进程作为文件的“属主(owner)”;当进程使用fcntl系统调用执行F_SETOWN命令时,属主进程的ID号就被保存在filp->f_owner中,这样做的目的是为了让内核知道该通知哪个进程;
2. 为了真正启用异步通知机制,用户程序还必须在设备中设置FASYNC标志,这是通过fcntl的F_SETFL命令完成的;
执行完这两个步骤之后,输入文件就可以在新数据到达时发送一个SIGIO信号,该信号被发送到存放在filp->f_owner中的进程,如果f_owner是负值,信号会被发送到该进程组;
使用事例如下:
signal(SIGIO, &input_handler);
fcntl(STDIN_FILENO, F_SETOWN, getpid());
oflags = fcntl(STDIN_FILENO, F_GETFL);
fcntl(STDIN_FILENO, F_SETFL, oflags|FASYNC);
不是所有设备都支持异步通知,我们可以选择不提供异步通知功能;应用程序通常假设只有套接字和终端才有异步通知能力;
当进程收到SIGIO信号时,并不知道是那个输入文件有了新的输入,如果有多个文件可以异步通知输入进程,则应用程序仍然需要借助poll或者select来确定输入的源;
从驱动程序角度
驱动程序实现异步通知的步骤如下:
1. F_SETOWN被调用时对filp->f_owner赋值;
2. 在执行F_SETFL启用FASYNC时,调用驱动程序的fasync方法,只要filp->f_flags中的FASYNC标志发生了变化,就会调用该方法,以便把这个变化通知驱动程序,使其能正确响应;文件打开时,FASYNC标志被默认为是清除的;
其中fasync方法即为file_operations中的fasync方法:
int (*fasync) (int, struct file *, int);
3. 当数据到达时,在所有注册为异步通知的进程都会被发送一个SIGIO信号;
驱动程序需要调用下面两个函数来完成异步通知功能:
int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
void kill_fasync(struct fasync_struct **fp, int sig, int band)
当一个打开的文件的FASYNC标志被修改时,调用fasync_helper以便从相关的进程列表中增加或者删除文件;除了最后一个参数之外,其他参数都是提供给fasync方法相同的参数,可以直接传递;
在数据到达时,可以调用kill_fasync通知所有相关进程,它的参数包括要发送的信号(通常是SIGIO)和带宽(band),后者几乎总是POLL_IN,但是在网络待命中,可以用来发送紧急或者带外数据;
当文件关闭时必须调用fasync方法,以便从活动的异步读取进程列表中删除该文件;尽管调用只在filp->f_flags设置了FASYNC标志时才是必须的,但不管什么情况,调用它不会有坏处,并且也是普遍的实现方法;
Linux设备驱动程序 之 异步通知的更多相关文章
- 蜕变成蝶~Linux设备驱动之异步通知和异步I/O
在设备驱动中使用异步通知可以使得对设备的访问可进行时,由驱动主动通知应用程序进行访问.因此,使用无阻塞I/O的应用程序无需轮询设备是否可访问,而阻塞访问也可以被类似“中断”的异步通知所取代.异步通知类 ...
- Linux内核开发之异步通知与异步I/O(一)
“小王,听说过锦上添花吧..”我拍拍下王的头说. “还锦上添花你,为你上次提的几个东东,我是头上长包..”小王气愤地瞪着我. “啊,为啥这样呢,本来还特意拒绝了MM的月份,抽出时间打算给你说点高级的东 ...
- 【转】linux设备驱动程序中的阻塞机制
原文网址:http://www.cnblogs.com/geneil/archive/2011/12/04/2275272.html 阻塞与非阻塞是设备访问的两种方式.在写阻塞与非阻塞的驱动程序时,经 ...
- Linux设备驱动程序 第三版 读书笔记(一)
Linux设备驱动程序 第三版 读书笔记(一) Bob Zhang 2017.08.25 编写基本的Hello World模块 #include <linux/init.h> #inclu ...
- Linux设备驱动程序学习之分配内存
内核为设备驱动提供了一个统一的内存管理接口,所以模块无需涉及分段和分页等问题. 我已经在第一个scull模块中使用了 kmalloc 和 kfree 来分配和释放内存空间. kmalloc 函数内幕 ...
- Linux设备驱动程序学习----2.内核模块与应用程序的对比
内核模块与应用程序的对比 更多内容请参考Linux设备驱动程序学习----目录 1. 内核模块与应用程序的对比 内核模块和应用程序之间的不同之处: 大多数中小规模的应用程序是从头到尾执行单个任务,而模 ...
- 嵌入式Linux设备驱动程序:编写内核设备驱动程序
嵌入式Linux设备驱动程序:编写内核设备驱动程序 Embedded Linux device drivers: Writing a kernel device driver 编写内核设备驱动程序 最 ...
- linux设备驱动程序该添加哪些头文件以及驱动常用头文件介绍(转)
原文链接:http://blog.chinaunix.net/uid-22609852-id-3506475.html 驱动常用头文件介绍 #include <linux/***.h> 是 ...
- 教你写Linux设备驱动程序:一个简短的教程
教你写Linux设备驱动程序:一个简短的教程 http://blog.chinaunix.net/uid-20799298-id-99675.html
随机推荐
- Pytorch报错:cuda runtime error (59) : device-side assert triggered at /pytorch/aten/src/THC/generic/THCTensorMath.cu:26
Pytorch报错:cuda runtime error (59) : device-side assert triggered at /pytorch/aten/src/THC/generic/TH ...
- javascript 利用数组制作分页效果
代码 参数: pageSize:一页的总数 currentPage:当前的页数 skipNum:跳过的数量 arr:数组 返回值: newArr分页后的数组 var pagination = func ...
- vue组件之间的传值
vue中组件之间的传值有好几种情况 1.父向子传值 父组件向子组件传值使用props,直接上实例 city.vue是父组件,list.vue是子组件city.vue里定义cities和hotCitie ...
- 关于操作git
手册:http://www.yiibai.com/git/ 一.安装git,可以通过git bash执行命令行:安装tortoiseGit执行git相关操作,在那之前需要了解下git命令行操作 二.在 ...
- vscode 踩坑汇总
gopls 提示 update 将 "go.useLanguageServer": true 改为 "go.useLanguageServer": false
- 接收端通过Request.InputStream读取流
以下有两种方式可以获取响应的数据流 1. 接收端通过Request.InputStream读取流 public static string StreamRead() { byte[] byts = n ...
- java——java跨平台原理
不同操作系统不同的虚拟机,屏蔽不同系统指令集的差异. 开发程序只需要遵循java规范:
- zencart价格筛选插件
1.首先,新建文件includes\modules\sideboxes\price_range.php <?php function zen_count_products_in_price($p ...
- Python3+Appium学习笔记04-自动下载apk
在项目中,app更新后,都会发布新的apk版本,然后去蒲公英对应的网站上扫码下载对应的apk进行测试.所以就在想,通过app参数进行安装时,是否可以先通过代码去拉取一遍最新的apk安装包. 因为学 ...
- docker: Error response from daemon: invalid mount config for type "bind": bind source path does not exist: /tmp/tfserving/
注意要是当前的完整路径 pwd查看到完整路径,再加入到source里面即可