异步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. IE浏览器兼容问题总结

    IE浏览器兼容问题总结 引自掘金:https://juejin.cn/post/6844903825854185480 一.标准盒模型和怪异盒模型 浏览器的盒子模型分为两类: 标准的W3C盒子模型. ...

  2. uni-app开发经验分享二十一: 图片滑动解锁插件制作解析

    在开发用户模块的时候,相信大家都碰到过一个功能,图片滑动解锁后发送验证码,这里分享我用uni-app制作的一个小控件 效果如下: 需要如下图片资源 template <template> ...

  3. MapReduce过程源码分析

    MapReduce过程源码分析 Mapper   首先mapper完成映射,将word映射成(word,1)的形式.   MapReduce进程,Map阶段也叫MapTask,在MapTask中会通过 ...

  4. Java关键字及作用解释

    访问控制 1) private 私有的 private 关键字是访问控制修饰符,可以应用于类.方法或字段(在类中声明的变量). 只能在声明 private(内部)类.方法或字段的类中引用这些类.方法或 ...

  5. 关于webservice实现web接口

    package service; import java.util.List; import javax.jws.WebMethod;import javax.jws.WebService; /** ...

  6. 26.Apache

    1.Apache简介 Apache HTTP Server(简称Apache)是Apache软件基金会的一个开放源代码的网页服务器软件,可以在大多数电脑操作系统中运行,由于其跨平台和安全性(尽管不断有 ...

  7. dedecms万能SQL标签使用方法大全

    注意:dede_archives这是系统默认的数据库表,如果你修改过表前缀dede_,请自行更改表名.在以下示例的标签中,有一部分只写出了SQL语句,具体的完整标签写法请参考:织梦SQL标签调用方法. ...

  8. mysql:如何利用覆盖索引避免回表优化查询

    说到覆盖索引之前,先要了解它的数据结构:B+树. 先建个表演示(为了简单,id按顺序建): id name 1 aa 3 kl 5 op 8 aa 10 kk 11 kl 14 jk 16 ml 17 ...

  9. Jenkins(3)拉取git仓库代码,执行python自动化脚本

    前言 python自动化的脚本开发完成后需提交到git代码仓库,接下来就是用Jenkins拉取代码去构建自动化代码了 新建项目 打开Jenkins新建一个自由风格的项目 源码管理 Repository ...

  10. vue-cli3移动端自适应配置 Vant组件库

    module.exports = { presets: [ '@vue/app' ], plugins: [ ['import', { libraryName: 'vant', libraryDire ...