异步IO是对阻塞和轮询IO的机制补充,所谓异步IO就是在设备数据就绪时主动通知所属进程进行处理的机制。之所以说是异步是相对与被通知进程的,因为进程不知道也无法知道什么时候会被通知;这一机制非常类似于硬件上的中断。异步IO的实现也依赖于Linux内核进程的信号机制,因为异步IO就是通过SIGIO信号通知的进程,而进程在收到信号后就会像中断一样直接跳转去执行之前就注册好的信号处理接口。

用户空间  

注册信号接口函数有两个版本的接口signal(int signal,sighandler_t handler)其中signal为内核定义的信号类型目前支持30种信号,每种信号也有其缺省的处理方式如果当前进程未指定某一信号的处理方式,系统就会按系统缺省的方式处理。还有一个比较新接口他功能也更加强大是 int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact))他们的详细使用和定义内容如下:

//接口
typedef void (*sighandler_t)(int);
//原型
sighandler_t signal(int signum, sighandler_t handler));
//定义
void (*signal(int signum, void (*handler))(int)))(int);

第一个参数指定信号的值,第二个参数指定针对前面信号的处理方式或接口,可以设置为如下值:

忽略该信号(参数设为SIG_IGN)

采用系统默认方式处理信号(参数设为SIG_DFL)

可以自己实现处理方式(参数指定一个函数地址)signal()

调用成功,返回上一次为成功安装信号signum而调用signal()时的handler值,失败则返回SIG_ERR。

sigaction:

int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));

//struct sigaction 结构体
struct sigaction {
union {
__sighandler_t _sa_handler;
void (*_sa_sigaction)(int, struct siginfo *, void *);
} _u;
sigset_t sa_mask;
unsigned long sa_flags;
void (*sa_restorer)(void);
}; //__sighandler_t
void (*__sighandler_t)(int );

sigaction的第一个参数和signal相同,第二和第三个参数都是 struct sigaction类型的指针,第一个为给这个信号新安插的处理接口,而第三个用来接收之前给这个信号安插的处理接口的返回。这个结构体中的union 是信号处理接口函数,使用的是哪一种取决与flags变量的bit标志,而sa_mask则负责在信号处理过程中对指定信号的掩蔽类似避免中断嵌套。最后一个sa_restorer现在已经废弃不建议再使用最后就是siginfo_t 结构体他是sigaction接口高级于signal接口的另一个力证。其中主要的成员是意义使用起来比较复杂在专门的地方学习,今天主要学习驱动部分的异步IO实现机制。

内核空间     

前面说了应用层的信号使用和异步IO的工作原理,接下来就是说明驱动也就是内核空间的异步IO实现机制了。在用户空间是负责接收信号那么内核空间肯定就是负责信号的释放,但是要能释放信号给指定的进程还要满足几个条件:

  1. 文件是异步方式打开的。
  2. 当前进程是文件的属主。

其中第一个条件可以同通过打开文件时指定FASYNC标志或通过fcntl(fd,F_SETFL,...)接口修改文件标志以支持异步通知。第二个则是通过使用接口fcntl(fd,F_SETOWN,getpid());进行设置。

而在内核部分的实现主要依赖一个数据结构和两个接口

struct fasync_struct {
spinlock_t fa_lock;
int magic;
int fa_fd;
struct fasync_struct *fa_next; /* singly linked list */
struct file *fa_file;
struct rcu_head fa_rcu;
};
//释放信号
void kill_fasync(struct fasync_struct **, int, int);
//处理文件FASYNC 状态变更的接口
int fasync_helper(int, struct file *, int, struct fasync_struct **);

文件操作接口中有一个fasync接口函数在文件ASYNC状态变更时会被调用所以需要实现它,的实现模版大致如下:

ststic int xxx_async(int fd,struct file* filp,int mode)
{
...
...
//async 为struct fasync_struct 的指针
return fasync_helper(fd,filp,mode,&async) }

然后就是释放信号的的操作,这一部分有可能发生在中断也有可能发生的其他的接口函数中,比如写接口中可以释放IO可以读的就绪信号给进程,而读接口可以释放可以写的接口给进程等,具体的使用就是:

ststic int xxx(int fd,struct file* filp,...)
{
...
...
//async 为struct fasync_struct 的指针
kill_fasync(&async,signum,POLL_IN);
...
...
}

kill_fasync 第一个接口参数为 异步结构体指针而 第二个参数为信号值一般为SIGIO,第三个为IO事件可为如下值或如下的值的或组合
//events可以是以下几个宏的:

EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭);
EPOLLOUT:表示对应的文件描述符可以写;
EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);
EPOLLERR:表示对应的文件描述符发生错误;
EPOLLHUP:表示对应的文件描述符被挂断;
EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。
EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里

最后需要注意的是,在通过xxx_async接口把文件加入到异步通知列表后如果关闭文件或取消异步时需要通过这个接口把FD文件描述符设置为-1,并把async_queue设为None将文件从异步通知列表中移除。

//如
static int xxx_release(struct inode* inode,struct file *filp)
{
...
xxx_fasync(-1,filp,0);
...
return 0;

参考:

https://blog.csdn.net/Fury97/article/details/83041810

Linux 驱动框架---驱动中的异步的更多相关文章

  1. Linux 驱动框架---驱动中的阻塞

    描述和API 阻塞IO和非阻塞IO的应用编程时的处理机制是不同的,如果是非阻塞IO在访问资源未就绪时就直接返回-EAGAIN,反之阻塞IO则会使当前用户进程睡眠直到资源可用.从应用场景来说两种方式分别 ...

  2. Linux 驱动框架---驱动中的中断

    在单片机开发中中断就是执行过程中发生了一些事件需要及时处理,所以需要停止当前正在运行的处理的事情转而去执行中断服务函数,已完成必要的事件的处理.在Linux中断一样是如此使用但是基于常见的中断控制器的 ...

  3. Linux 驱动框架---驱动中的时间相关

    内核中的时间 Linux 系统内核对于时间的管理依赖于硬件,硬件按一定的周期产生中断,周期由内核的一个配置值HZ决定在系统启动时会将定时器配置为HZ值指定的频率产生中断:同时内核和维护一个64位(X8 ...

  4. Linux 驱动框架---驱动中的并发

    并发指多个执行单元被同时.并行的执行,而并发执行的单元对共享资源的访问就容易导致竟态.并发产生的情况分为抢占和并行(多核)和硬抢占(中断).Linux为解决这一问题增加了一系列的接口来解决并发导致的竟 ...

  5. 驱动框架入门——以LED为例[【转】

    本文转载自;http://blog.csdn.net/oqqHuTu12345678/article/details/72783903 以下内容源于朱有鹏<物联网大讲堂>课程的学习,如有侵 ...

  6. I2C驱动框架(四)

    参考:I2C子系统之platform_driver初始化——I2C_adap_s3c_init() 在完成platform_device的添加之后,i2c子系统将进行platform_driver的注 ...

  7. Linux驱动框架之framebuffer驱动框架

    1.什么是framebuffer? (1)framebuffer帧缓冲(一屏幕数据)(简称fb)是linux内核中虚拟出的一个设备,framebuffer向应用层提供一个统一标准接口的显示设备.帧缓冲 ...

  8. linux驱动基础系列--linux spi驱动框架分析

    前言 主要是想对Linux 下spi驱动框架有一个整体的把控,因此会忽略某些细节,同时里面涉及到的一些驱动基础,比如平台驱动.设备模型等也不进行详细说明原理.如果有任何错误地方,请指出,谢谢! spi ...

  9. Linux下USB驱动框架分析【转】

    转自:http://blog.csdn.net/brucexu1978/article/details/17583407 版权声明:本文为博主原创文章,未经博主允许不得转载. http://www.c ...

随机推荐

  1. Java流程控制与Scanner类的使用

    Java流程控制与Scanner类的使用 Scanner类 Scanner类可以使程序接受键盘输入,实现人机交互 一个完整的Scanner的使用例子: //创建一个扫描器对象,用于接收键盘数据 Sca ...

  2. Memcached与Redis对比及其优劣分析

    国外讨论 本文主要总结缓存Redis和Memcached的区别,总结之前先参考外国知乎上的一篇问答:<Is memcached a dinosaur in comparison to Redis ...

  3. 并发编程:Actors 模型和 CSP 模型

    https://mp.weixin.qq.com/s/emB99CtEVXS4p6tRjJ2xww 并发编程:Actors 模型和 CSP 模型 ImportNew 2017-04-27    

  4. Zookeeper C API的学习 以及样例 很赞

    https://www.cnblogs.com/haippy/archive/2013/02/21/2920280.html

  5. HTML5 初学者一步一步攀爬 努力加油学习

    Html 5 Html:Hyper Text MarKup Language超文本标签语言 Html:网页的源码 浏览器:"解释和执行"HTMl源码的工具 Head 标签内的信息用 ...

  6. 六:SpringBoot-引入JdbcTemplate,和多数据源配置

    SpringBoot-引入JdbcTemplate,和多数据源配置 1.JdbcTemplate对象 1.1 JdbcTemplate核心方法 2.SpringBoot中使用JDBCTemplate ...

  7. Web信息收集-目标扫描-Nmap

    Web信息收集-目标扫描-Nmap 一.Nmap简介 二.扫描示例 使用主机名扫描: 使用IP地址扫描: 扫描多台主机: 扫描整个子网 使用IP地址的最后一个字节扫描多台服务器 从一个文件中扫描主机列 ...

  8. jQuery.qrcode二维码插件生成网页二维码

    如果是一个固定的二维码,我们只需要在网上找个地方生成图片,然后放上图片就可以了.但如果是地址不固定需要根据页面来生成的话.就有两种做法,一个是后端根据页面做一个动态的二维码.一种是前端使用插件生成. ...

  9. Scala安装后,在IDEA中配置

    IDEA中配置Scala 一.设置Module 二.添加Scala的SDK 三.寻找本地scala安装路径 四.测试是否可以新建有Scala Class 五.踩坑填坑记录 5.1:Error:(4, ...

  10. Mysql 基本操作命令

    1.添加用户 1.1 登录MYSQL: @>mysql -u root -p @>密码 1.2 创建用户: 格式:grant select on 数据库.* to 用户名@登录主机 ide ...