在设备驱动中使用异步通知可以使得对设备的访问可进行时,由驱动主动通知应用程序进行访问。因此,使用无阻塞I/O的应用程序无需轮询设备是否可访问,而阻塞访问也可以被类似“中断”的异步通知所取代。异步通知类似于硬件上的“中断”概念,比较准确的称谓是“信号驱动的异步I/O”。

9.1 异步通知的概念和作用

异步通知:一旦设备就绪,则主动通知应用程序,该应用程序无需查询设备状态

几种通知方式比较:

阻塞I/O :一直等待设备可访问后开始访问

非阻塞I/O:使用poll()查询设备是否访问

异步通知 :设备主动通知用户应用程序

-

9.2 linux异步通知编程

9.2.1 linux信号

作用:linux系统中,异步通知使用信号来实现

SIGHUP 终止进程 终端线路挂断

SIGINT 终止进程 中断进程

SIGQUIT 建立CORE文件终止进程,并且生成core文件

SIGILL 建立CORE文件 非法指令

SIGTRAP 建立CORE文件 跟踪自陷

SIGBUS 建立CORE文件 总线错误

SIGSEGV 建立CORE文件 段非法错误

SIGFPE 建立CORE文件 浮点异常

SIGIOT 建立CORE文件 执行I/O自陷

SIGKILL 终止进程 杀死进程

SIGPIPE 终止进程 向一个没有读进程的管道写数据

SIGALARM 终止进程 计时器到时

SIGTERM 终止进程 软件终止信号

SIGSTOP 停止进程 非终端来的停止信号

SIGTSTP 停止进程 终端来的停止信号

SIGCONT 忽略信号 继续执行一个停止的进程

SIGURG 忽略信号 I/O紧急信号

SIGIO 忽略信号 描述符上可以进行I/O

SIGCHLD 忽略信号 当子进程停止或退出时通知父进程

SIGTTOU 停止进程 后台进程写终端

SIGTTIN 停止进程 后台进程读终端

SIGXGPU 终止进程 CPU时限超时

SIGXFSZ 终止进程 文件长度过长

SIGWINCH 忽略信号 窗口大小发生变化

SIGPROF 终止进程 统计分布图用计时器到时

SIGUSR1 终止进程 用户定义信号1

SIGUSR2 终止进程 用户定义信号2

SIGVTALRM 终止进程 虚拟计时器到时

9.2.2 信号的接收

信号捕获函数signal()

参数:

signum:信号值

handler:针对signum的处理函数

若为SIG_IGN:忽略该信号

若为SIG_DFL:系统默认方式处理

若为用户自定义函数:信号被捕获,该函数被执行

返回值

成功:最后一次为信号signum绑定的处理函数的handler值

失败:返回SIG_ERR

sigaction()

作用:改变进程接收到特定信号后的行为

参数

signum:信号值

除SIG_KILL及SIG_STOP以外的一个特定有效的信号

act:指向结构体sigaction的一个实例的指针

在结构体sigaction中,指定了处理信号的函数,若为空则进程会以缺省值的方式处理信号

oldact:保存原来对应的信号的处理函数,可设为NULL

int sigaction(int signo,const struct sigaction *restrict act, struct sigaction *restrict oact);

实例:使用信号实现异步通知

在用户空间处理设备释放信号的准备工作

通过F_SETOWN IO控制命令设置设备文件的拥有者为本进程,以使信号被本进程捕获

通过F_SETFL IO控制命令设置设备文件以支持FASYNC,及异步通知模式

通过signal()函数连接信号和信号处理函数

//启动信号机制

void sigterm_handler(int sigo)

{

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);

fctcl(STDIN_FILENO,F_SETFL,oflags | FASYNC);

//建立一个死循环,防止程序结束

whlie(1);

return 0;

}

9.2.3 信号的释放 (在设备驱动端释放信号)

为了是设备支持异步通知机制,驱动程序中涉及以下3项工作

支持F_SETOWN命令,能在这个控制命令处理中设置filp->f_owner为对应的进程ID。不过此项工作已由内核完成,设备驱动无须处理

支持F_SETFL命令处理,每当FASYNC标志改变时,驱动函数中的fasync()函数得以执行。因此,驱动中应该实现fasync()函数

在设备资源中可获得,调用kill_fasync()函数激发相应的信号

-

设备驱动中异步通知编程:

处理FASYNC标志变更函数:fasync_helper()

释放信号的函数:kill_fasync()

int fasync_helper(int fd,struct file *filp,int mode,struct fasync_struct **fa);

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 *ppos)

{

struct xxx_dev *dev = filp->private_data;

...

//产生异步读信息

if(dev->async_queue)

kill_fasync(&dev->async_queue,GIGIO,POLL_IN);

...

}

最后在文件关闭时,要将文件从异步通知列表中删除

int xxx_release(struct inode *inode,struct file *filp)

{

//将文件从异步通知列表中删除

xxx_fasync(-1,filp,0);

...

return 0;

}

9.4 linux异步I/O

9.4.1 AIO概念与GNU C库 AIO

9.4.1.1 AIO概念

同步I/O:linux系统中最常用的输入输出(I/O)模型是同步I/O,在这个模型中,当请求发出后,应用程序就会阻塞,知道请求满足

异步I/O:I/O请求可能需要与其它进程产生交叠

Linux 系统中最常用的输入/输出(I/O)模型是同步 I/O

在这个模型中,当请求发出之后,应用程序就会阻塞,直到请求满足为止

调用应用程序在等待 I/O 请求完成时不需要使用任何中央处理单元(CPU)

在某些情况下,I/O 请求可能需要与其他进程产生交叠,可移植操作系统接口(POSIX)异步 I/O(AIO)应用程序接口(API)就提供了这种功能

9.4.1.1 AIO系列API:

aio_read–异步读

作用:请求对一个有效的文件描述符进行异步读写操作

请求进行排队之后会立即返回

这个文件描述符可以表示一个文件、套接字,甚至管道

参数aiocb:结构体包含了传输的所有信息,以及为AIO操作准备的用户空间缓存区

返回值

成功:返回0

失败:返回-1,并设置errno的值

int aio_read( struct aiocb *aiocbp );

aio_write–异步写

作用:请求一个异步写操作

请求进行排队之后会立即返回

这个文件描述符可以表示一个文件、套接字,甚至管道

参数aiocb:结构体包含了传输的所有信息,以及为AIO操作准备的用户空间缓存区

返回值

成功:返回0

失败:返回-1,并设置errno的值

int aio_write( struct aiocb *aiocbp );

aio_error

作用:确定请求的状态

参数aiocb:结构体包含了传输的所有信息,以及为AIO操作准备的用户空间缓存区

返回值

EINPROGRESS:说明请求尚未完成

ECANCELED:说明请求被应用程序取消

失败:返回-1,并设置errno的值

int aio_error( struct aiocb *aiocbp );

aio_return–获得异步操作的返回值

异步 I/O 和标准块 I/O 之间的另外一个区别是不能立即访问这个函数的返回状态,因为并没有阻塞在 read()调用上

在标准的 read()调用中,返回状态是在该函数返回时提供的。但是在异步 I/O 中,我们要使用 aio_return()函数

只有在 aio_error()调用确定请求已经完成(可能成功,也可能发生了错误)之后,才会调用这个函数

参数aiocb:结构体包含了传输的所有信息,以及为AIO操作准备的用户空间缓存区

返回值

成功:返回所传输的字节数

失败:返回-1

ssize_t aio_return( struct aiocb *aiocbp );

aio_suspend–挂起异步操作,直到异步请求完成为止

作用:挂起(或阻塞)调用进程,直到异步请求完成为止,调用者提供了一个 aiocb 引用列表,其中任何一个完成都会导致 aio_suspend()返回

int aio_suspend( const struct aiocb *const cblist[], int n, const struct timespec *timeout );

aio_cancel–取消异步请求

作用:允许用户取消对某个文件描述符执行的一个或所有 I/O 请求

要求:

如果要取消一个请求,用户需提供文件描述符和 aiocb 引用

函数返回AIO_CANCELED:请求被成功取消

函数返回AIO_NOTCANCELED:请求完成

如果要取消对某个给定文件描述符的所有请求,用户需要提供这个文件的描述符以及一个对 aiocbp 的 NULL 引用

函数返回AIO_CANCELED:表明所有的请求都取消了

函数返回AIO_NOTCANCELED:表明至少有一个请求没有被取消

函数返回AIO_ALLDONE:表明没有一个请求可以被取消

使用 aio_error()来验证每个 AIO 请求

aio_error()返回-1并且设置了errno被设置为ECANCELED:表明某个请求已经被取消了

int aio_cancel( int fd, struct aiocb *aiocbp );

lio_listio–同时发起多个传输(一次系统调用可以启动大量的I/O操作)

作用:这个函数非常重要,它使得用户可以在一个系统调用(一次内核上下文切换)中启动大量的 I/O 操作

参数

mode:可以是 LIO_WAIT 或 LIO_NOWAIT

LIO_WAIT 会阻塞这个调用,直到所有的 I/O 都完成为止

在操作进行排队之后,LIO_NOWAIT 就会返回

list :是一个 aiocb 引用的列表,最大元素的个数是由 nent 定义的

如果 list 的元素为 NULL,lio_listio()会将其忽略。

int lio_listio( int mode, struct aiocb *list[], int nent, struct sigevent *sig );

9.4.2 Linux内核AIO与libaio

linux AIO也可以由内核空间实现,异步I/O是linux2.6以后版本内核的标准特性

对于块设备,AIO可以一次性发出大量的read/write调用并且通过通用块层的I/O调度来获得更好的性能,用户也可以减少过多的同步负载

对网络设备而言,在socket层面上,也可以使用AIO,让CPU和网卡的收发充分交叠以改善吞吐性能

用户空间中一般要结合libaio来进行内核AIO的系统调用

io_setup( )

//Initializes an asynchronous context for the current process

io_submit( )

//Submits one or more asynchronous I/O operations

io_getevents( )

//Gets the completion status of some outstanding asynchronous I/O operations

io_cancel( )

//Cancels an outstanding I/O operation

io_destroy( )

//Removes an asynchronous context for the current process

9.4.3 AIO与设备驱动

用户空间调用io_submit()之后,对应于用户传递的每个iocb结构,内核会生成一个与之对应的kiocb结构

通过is_sync_kiocb判断某kiocb是否为同步I/O请求

如果是返回真,表示为异步I/O请求

字符设备:必须明确应支持AIO(极少数是异步I/O操作)

字符设备驱动程序中file_operations 包含 3 个与 AIO 相关的成员函数,

ssize_t (*aio_read) (struct kiocb *iocb, char *buffer, size_t count, loff_t offset);

ssize_t (*aio_write) (struct kiocb *iocb, const char *buffer, size_t count, loff_t offset);

int (*aio_fsync) (struct kiocb *iocb, int datasync);

块设备和网络设备:本身是异步的

linux编写驱动后write已杀死_《Linux4.0设备驱动开发详解》笔记--第九章:Linux设备驱动中的异步通知与同步I/O...相关推荐

  1. Linux设备驱动开发详解 第3版 (即 Linux设备驱动开发详解 基于最新的Linux 4 0内核 )前言

    Linux从未停歇脚步.Linus Torvalds,世界上最伟大的程序员之一,Linux内核的创始人,Git的缔造者,仍然在没日没夜的合并补丁,升级内核.做技术,从来没有终南捷径,拼的就是坐冷板凳的 ...

  2. ADI Blackfin DSP处理器-BF533的开发详解7:SPI接口的驱动和应用(含源代码)

    硬件准备 ADSP-EDU-BF533:BF533开发板 AD-HP530ICE:ADI DSP仿真器 软件准备 Visual DSP++软件 硬件链接 接口功能介绍 SPI 接口是 4 线串口,可以 ...

  3. Linux 笔记 - 第九章 Linux 中软件的安装

    博客地址:http://www.moonxy.com 一.前言 在 Linux 系统中,应用程序的软件包主要分为两种: 1)第一种是二进制的可执行软件包,也就是解开包后就可以直接运行.在 Window ...

  4. ADI Blackfin DSP处理器-BF533的开发详解9:UART串口的驱动和应用(含源码)

    硬件准备 ADSP-EDU-BF533:BF533开发板 AD-HP530ICE:ADI DSP仿真器 软件准备 Visual DSP++软件 硬件链接 接口功能介绍 UART(Universal A ...

  5. ADI Blackfin DSP处理器-BF533的开发详解8:Timer定时器的驱动和应用(含源代码)

    硬件准备 ADSP-EDU-BF533:BF533开发板 AD-HP530ICE:ADI DSP仿真器 软件准备 Visual DSP++软件 硬件链接 接口功能介绍 ADSP-BF53x 上有 3 ...

  6. 张孝祥java邮件开发_张孝祥java邮件开发详解笔记(生成文本邮件)

    package zxx.createMessage; import java.io.FileOutputStream; import java.util.Date; import java.util. ...

  7. Kali linux无线网络渗透详解笔记

    Kali linux无线网络渗透详解笔记 第一章:搭建渗透环境测试环境 第二章:WiFi网络的构成 第三章:监听WiFi网络 第四章:捕获数据包 第五章: 分析数据包 第六章:获取信息 第七章:WPS ...

  8. linux 设备驱动 ppt,linux设备驱动开发详解讲座ppt

    PPT内容 这是linux设备驱动开发详解讲座ppt下载,主要介绍了设备驱动简介:建立和运行模块:字符驱动:调试技术:并发和竞争:分配内存:硬件通讯:中断处理:块设备驱动,欢迎点击下载. 嵌入式Lin ...

  9. 《Linux设备驱动开发详解(第2版)》隆重出版

    Linux设备驱动开发详解(第2版)(前一版狂销3万册,畅销书最新升级) [新品] 点击看大图     基本信息 * 作者: 宋宝华       * 出版社:人民邮电出版社     * ISBN:97 ...

最新文章

  1. day04_07-三个函数的区别
  2. 前阿里资深运营王殿进:SaaS产品经理所面临的苦恼
  3. 常规流之块级格式化上下文(Block Formatting Contexts)
  4. 课堂笔记——Data Mining(1)
  5. 超级抖音腾讯视频V3.6.0小程序源码 前端+后端 支持视频采集和上传
  6. 大数据之-Hadoop3.x_MapReduce_WordCount案例_Debug调试---大数据之hadoop3.x工作笔记0092
  7. dell服务器系统备份到另一台,已解决: Re: Networker 备份服务器 备份软件配置文件备份? - Dell Community...
  8. Failed to parse the output of 'adb version'
  9. 量子电动力学和量子场论,多体系统的量子场论
  10. Java对比两个json 的数据结构和内容是否一样
  11. 数学建模之matlab软件学习04——专题四MATLAB绘图
  12. 运行内存扩展器(RAM)扩大,最高达2.5g
  13. 7、万国觉醒建筑白天黑夜效果(Shader Graph)
  14. 西门子real是什么数据类型_西门子数据类型REAL转WORD和S5TIME的方法
  15. 太牛了,搜狐快站上线微信插件 电商插件升级
  16. tensorflow实现数据增强(随机裁剪、翻转、对比度设置、亮度设置)
  17. thinkphp6教程笔记
  18. 【学习记录】QQZone项目 part1
  19. 液晶面板里面有些什么配件_液晶模组和液晶面板有什么区别?
  20. 003--北大考研计算机--考研经验贴

热门文章

  1. 弃玩《列王的纷争》之感
  2. 工作学习 -- 总结内容供搜索
  3. 蓝牙模块:使用问题集锦
  4. 芝麻叶泡水的营养价值 芝麻叶泡水的功效与作用
  5. 使用mirDeep2进行miRNA-seq数据分析
  6. [转载]J2me技术——跟我学制作Pak文件
  7. Android Audio开发——音频设备管理(十四)
  8. reactos源码下载地址
  9. python--忽略讨厌的 warning
  10. 超强Video深度学习开源工具集,来了!