异步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. Visual Studio中自定义代码段!

    Visual Studio中自定义代码段! 第一步:在编辑器中进行快捷键的输入[ctrl + shift + p] 或者 点击 查看 第一个选项就是!请看下图 第二步:选择你要配置代码段的语言, 这里 ...

  2. 关于BI测试

    BI测试: BI是从数据接入.数据准备.数据分析.数据可视化到数bai据分发应用的一系列过程,目的是为了辅助企业高效决策.而报表虽然最终也实现了数据可视化,但是对于数据分析的维度.深度.颗粒度.实时性 ...

  3. Spring Data JPA基本增删改查和JPQL查询(含完整代码和视频连接)

    问题:SpringDataJPA怎么使用? 一.考察目标 主要考核SpringDataJPA的用法 二.题目分析 spring data jpa 的使用步骤(下面有具体实现细节) 1.创建maven工 ...

  4. 如何在Redis中实现事务

    如何在Redis中实现事务 - 微店技术团队 - SegmentFault 思否 https://segmentfault.com/a/1190000007429197

  5. Privacy-Enhanced Mail (PEM) Privacy Enhancement for Internet Electronic Mail

    小结 1. 加密基本流程 本地格式标准格式认证(填充与完整性检查)与加密可打印编码 Privacy-Enhanced Mail (PEM) RFC 2313 - PKCS #1: RSA Encryp ...

  6. C++ Primer Plus读书笔记(十)对象和类

    1.类 不废话,上定义 class ClassName { public: xxx; private: xxx; protected: xxx; } private部分数据只能通过public 提供的 ...

  7. Linux 安装mysql总结

    第一步:mysql安装包准备 mysql官网下载地址:https://downloads.mysql.com/ 第二步:将mysql安装包上传到服务器 第三步:解压 tar -zxvf mysql-5 ...

  8. 图文并茂-超详解 CS:APP: Lab3-Attack(附带栈帧分析)

    CS:APP:Lab3-ATTACK 0. 环境要求 关于环境已经在lab1里配置过了.lab1的连接如下 实验的下载地址如下 说明文档如下 http://csapp.cs.cmu.edu/3e/at ...

  9. (四)整合 RocketMQ ,实现请求异步处理

    整合 RocketMQ ,实现请求异步处理 1.RocketMQ简介 1.1 架构图片 1.2 角色分类 1.3 通信机制 2.实现案例 2.1 项目结构图 2.2 配置文件 2.3 生产者配置 2. ...

  10. Nacos服务心跳和健康检查源码介绍

    服务心跳 Nacos Client会维护一个定时任务通过持续调用服务端的接口更新心跳时间,保证自己处于存活状态,防止服务端将服务剔除,Nacos默认5秒向服务端发送一次,通过请求服务端接口/insta ...