Linux内核开发之异步通知与异步I/O(一)
“小王,听说过锦上添花吧..”我拍拍下王的头说。
“还锦上添花你,为你上次提的几个东东,我是头上长包..”小王气愤地瞪着我。
“啊,为啥这样呢,本来还特意拒绝了MM的月份,抽出时间打算给你说点高级的东东,看来现在是不行了”我吃惊道,“这样吧,这次就给你讲些和前边有关的东西,也不失为锦上添花不是?”。
“好,我也是这么打算的,就是没好意思说,今天讲些啥呢?”小王暗淡的眼光总算闪了闪。(为啥这么难受呢,好像跟什么会嚎叫的特像,哈哈)
那就言归正传,今天我们讲---Linux设备驱动程序之异步通知与异步I/O.”
小王,前边不是讲了阻塞与非阻塞访问,poll()函数等提供的较好的解决设备访问的机制,那么通过这次有关异步通知整套机制的配合,就更相得益彰,锦上添花了。
啥叫异步通知:很简单,一旦设备准备好,就主动通知应用程序,这种情况下应用程序就不需要查询设备状态,这是不是特像硬件上常提的“中断的概念”。上边比较
准确的说法其实应该叫做“信号驱动的异步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);
}
int main(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()链接信号和信号处理函数。
当然,如果你了解linux/Unix信号机制的话,你可能会问为啥没说sigaction函数,其实没关系,作用差不多,想知道的话,自己看书Apue的P261.
有了信号的发送,那么就一定得有信号的释放了:
在设备驱动和应用程序的异步通知交互中,仅仅在应用程序端捕获信号是不够的,因为信号没有的源头是在驱动端,因此要在适当的时机让设备驱动释放信号。
为了使设备支持异步通知机制,驱动程序中涉及三个操作:
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);
}
..
}
static int xxx_release(struct inode *inode, struct file *filp)
{
struct xxx_dev *dev = filp->private_data;
//将文件从异步通知列表中删除
xxx_fasync(-1,filp,0);
...
return 0;
}
“等等,我知道你明白,你是想向我个例子,我知道你啥意思,没关系,我下次补上 。”没等小王,我立刻给她堵上“你啊,心里几根小九九,我还不知道啊..”
Linux内核开发之异步通知与异步I/O(一)的更多相关文章
- arm驱动linux异步通知与异步IO【转】
转自:http://blog.csdn.net/chinazhangzhong123/article/details/51638793 <[ arm驱动] linux异步通知与 异步IO> ...
- Linux设备驱动中的异步通知与异步I/O
异步通知概念: 异步通知的意识是,一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,这一点非常类似于硬件上的“中断”概念,比较准确的称谓是“信号驱动的异步IO”,信号是在软件层次 ...
- 如何参与Linux内核开发(转)
本文来源于linux内核代码的Document文件夹下的Hoto文件.Chinese translated version of Documentation/HOWTO If you have any ...
- 嵌入式系统Linux内核开发工程师必须掌握的三十道题(转)
嵌入式系统Linux内核开发工程师必须掌握的三十道题 如果你能正确回答以下问题并理解相关知识点原理,那么你就可以算得上是基本合格的Linux内核开发工程师,试试看! 1) Linux中主要有哪几种内核 ...
- 如何参与linux 内核开发
如果想评论或更新本文的内容,请直接联系原文档的维护者.如果你使用英文 交流有困难的话,也可以向中文版维护者求助.如果本翻译更新不及时或者翻 译存在问题,请联系中文版维护者. 英文版维护者: Gre ...
- 如何参与linux内核开发
如何参与linux 内核开发 如果想评论或更新本文的内容,请直接联系原文档的维护者.如果你使用英文 交流有困难的话,也可以向中文版维护者求助.如果本翻译更新不及时或者翻 译存在问题,请联系中文版维 ...
- 嵌入式Linux内核开发工程师必须掌握的三十道题
如果你能正确回答以下问题并理解相关知识点原理,那么你就可以算得上是基本合格的Linux内核开发工程师. 1. Linux中主要有哪几种内核锁?(进程同步与互斥) (1)自旋锁:非睡眠锁 (2)信号量: ...
- Linux内核开发进阶书籍推荐(不适合初学者)
Linux内核开发进阶书籍推荐(不适合初学者) 很早之前就想写一篇文章总结一下Linux Kernel开发的相关资料,项目的原因,再加上家里的一些事情,一直没能找到闲暇,今天终于有些时间,希望可以完成 ...
- Linux内核开发
Linux内核开发 https://www.cnblogs.com/pugang/p/9728983.html 很早之前就想写一篇文章总结一下Linux Kernel开发的相关资料,项目的原因,再加上 ...
随机推荐
- hihocoder1310 岛屿
hihocoder1310 岛屿 题意: 中文题意 思路: dfs,面积和数量都很好求,问题在岛屿形状上,感觉让人比较麻烦,用vector保存各个点,只要两个岛之间每个点距离一样就好了,这里的形状的定 ...
- iOS 反反注入 修改__RESTRICT,__restrict工具
通过在 Xcode 里的 Other Linker Flags 设置参数,可以防止App被注入dylib(仅限于iOS 10 以下系统) 比如,某艺,XX音乐等 dylib无法注入,也就意味着没办法 ...
- Swift使用NSKeyedArchiver进行数据持久化保存的经验
iOS提供了几种数据持久化保存的方法,有NSKeyedArchiver,Property List,NSUserDefaults和CoreData.我学习下来,觉得保存应用内的诸如列表,记录这些东西, ...
- ASM相关视图
oracle asm对于我们并非一个黑盒子 ,我们能够通过对应视图查看asm instance信息,和oracle系统视图一样. v$asm_diskgroup x$kfgrp 记录diskgrou ...
- Druid 配置_配置WebStatFilter
https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_%E9%85%8D%E7%BD%AEWebStatFilter WebStatFilt ...
- C#各种结束进程的方法详细介绍
Process类的CloseMainWindow, Kill, Close Process.CloseMainWindow是GUI程序的最友好结束方式,从名字上就可以看出来它是通过结束主窗体,相当于用 ...
- WPF: 使用CommandManager.InvalidateRequerySuggested手动更新Command状态
WPF判断命令(Command)是否能够执行是通过ICommand.CanExecute事件,在实际程序中路由命令一般是通过CommandBinding来使命令得到实际操作代码,但是这个CanExec ...
- linux查看文件有多少行(WC)
使用wc命令 具体通过wc --help 可以查看. 如:wc -l filename 就是查看文件里有多少行 wc -w filename 看文件里有多少个word. wc -L filename ...
- .a 库文件信息查看
在Linux 下经常需要链接一些 *.a的库文件,那怎么查看这些*.a 中包 含哪些文件.函数.变量: 1. 查看文件:ar -t *.a 2. 查看函数.变量:nm *.a
- 将matlab的figure保存为pdf,避免图片太大缺失
有时画的matlab图太大,或者有太多的子图,导致图太宽,如果直接保存成pdf的话,会导致左右边丢失,显示不下.一个有效又简单的办法是: 1.在matlab figure里面,Edit -> ...