异步通知概念: 异步通知的意识是,一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,这一点非常类似于硬件上的“中断”概念,比较准确的称谓是“信号驱动的异步IO”,信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求是一样的。信号是异步的,一个进进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。

异步通知与设备访问: 阻塞IO意味着一直等待设备可访问后访问;非阻塞IO使用poll意味着查询设备是否可以访问;而异步通知则意味着设备通知自身可访问,实现了异步I/O

 用kill -l 命令可以查看Linux可用的信号
信号的接收
signal()函数来设置对应信号的处理函数。
void (*signal(int signum,void(*handler))(int)))(int);
//第一个参数指定信号的值;第二个参数指定针对前面信号值的处理函数,若位SIN_IGN,表示忽略该信号;若位SIG_DFL,表示采用系统默认方式处理信号;若位用户自定义
函数,则信号被捕获到后,该函数将被执行
//该函数原型比较难理解,可以分解为:typedef void(*sighandler_t)(int); sighandler_t signal(int signum,sighandler_t handler));
如果signal调用成功,它返回最后一次信号signum绑定的处理函数handler值,失败则返回SIG_ERR.
sigaction()函数可用于改变进程接收到特定信号后的行为。
int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));
//该函数的第一个参数是信号的值,可以为除SIGKILL及SIGSTOP外的任何一个特定有效的信号;第二个参数是指向结构体sigaction的一个实例的指针,在sigaction的实例中
指定了对特定信号的处理函数,若为空,则进程会以缺省方式对信号处理;第三个参数oldact指向的对象用来保存原来对相应信号的处理函数,可指定oldact为NULL.
如果把第二和第三个参数都设为NULL,那么该函数用来检测信号的有效性。
使用信号实现异步通知的应用程序实例:
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#define MAX_LEN 100
void input handler(int num)
{
char data[MAX_LEN];
int len;
len=read(STDIN_FILENO,&data,MAX_LEN); //读取并输出STDIN_FILENO上的输入。
data[len]=0;
printf("input available:%s\n",data);
}
main()
{
int oflags;
//启动信号驱动机制
signal(SIGIO,input_handler); //为SIGIO信号安装input_handler()作为处理函数
fcntl(STDIN_FILENO,F_SETOWN,getpid());//这里的getpid()是获得当前进程,注意,没有这一步,内核不知道应该将信号发给哪个进程。
在 Linux 中,实现文件上锁的函数有lock和fcntl,其中flock用于对文件施加建议性锁,而fcntl不仅可以施加建议性锁,还可以施加强制锁。同时,fcntl还能对文件的某一记录进行上锁,也就是记录锁。
记录锁又可分为读取锁和写入锁,其中读取锁又称为共享锁,它能够使多个进程都能在文件的同一部分建立读取锁。而写入锁又称为排斥锁,在任何时刻只能有一个进程在文件的某个部分上建立写入锁。当然,在文件的同一部分不能同时建立读取锁和写入锁。
注意:

fcntl是一个非常通用的函数,它还可以改变文件进程各方面的属性,在本节中,主要介绍它建立记录锁的方法,关于它其他用户感兴趣的读者可以参看fcntl手册。

oflags=fcntl(STDIN_FILENO,F_GETFL); //为了启动一步通知机制,还需对设备设置FASYNC标志

fcntl(STDIN_FILENO,F_SETFL,oflags|FASYNC);

//最后进入一个死循环,仅为保持进程不终止,如果程序中没有死循环会立即执行完毕

while(1);

}

 信号释放:

在设备驱动程序与应用程序的异步通知交互中,应用程序捕获信号,驱动程序释放信号。

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

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

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

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

异步通知处理过程中用户空间和设备驱动的交互。

异步通知变成主要用到一项数据结构和两个函数。数据结构是fasync_struct结构体,两个函数是fasync_helper,kill_fasync。

int fasync_helper(int fd,struct file *filp,int mode,struct fasync_struct **fa);  //处理FASYNC标志变更

void kill_fasync(struct fasync_struct **fa,int sig,int band);  //释放信号

支持异步通知的设备结构体模板

struct xxx_dev{

struct cdev cdev;  //cdev结构体

...

struct fasync_struct *async_queue;          //异步结构体指针

};

支持异步通知的设备驱动fasync()函数模板

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

{

struct xx_dev *dev=filp->private_data;

...

//产生异步读信号

if(dev->async_queue)

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

...

}

最后在关闭文件时候,即在release函数中,应该将文件从异步通知的列表中删除。

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

{

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

xxx_fasync(-1,filp,0);

...

return 0;

}

												

Linux设备驱动中的异步通知与异步I/O的更多相关文章

  1. Linux设备驱动中的阻塞和非阻塞I/O

    [基本概念] 1.阻塞 阻塞操作是指在执行设备操作时,托不能获得资源,则挂起进程直到满足操作所需的条件后再进行操作.被挂起的进程进入休眠状态(不占用cpu资源),从调度器的运行队列转移到等待队列,直到 ...

  2. Linux设备驱动中的阻塞和非阻塞I/O <转载>

    Green 博客园 首页 新随笔 联系 订阅 管理 Linux设备驱动中的阻塞和非阻塞I/O   [基本概念] 1.阻塞 阻塞操作是指在执行设备操作时,托不能获得资源,则挂起进程直到满足操作所需的条件 ...

  3. 蜕变成蝶~Linux设备驱动中的阻塞和非阻塞I/O

    今天意外收到一个消息,真是惊呆我了,博客轩给我发了信息,说是俺的博客文章有特色可以出本书,,这简直让我受宠若惊,俺只是个大三的技术宅,写的博客也是自己所学的一些见解和在网上看到我一些博文以及帖子里综合 ...

  4. Linux设备驱动中的IO模型---阻塞和非阻塞IO【转】

    在前面学习网络编程时,曾经学过I/O模型 Linux 系统应用编程——网络编程(I/O模型),下面学习一下I/O模型在设备驱动中的应用. 回顾一下在Unix/Linux下共有五种I/O模型,分别是: ...

  5. Linux设备驱动中的软件架构思想

    目录 更新记录 一.Linux驱动的软件架构 1.1 出发点 1.2 分离思想 1.3 分层思想 二.platform设备驱动 2.1 platform设备 2.2 platform驱动 2.3 pl ...

  6. Linux设备驱动中的ioctl

    memdev.h #ifndef _MEMDEV_H #define _MEMDEV_H #define MEM_MAGIC 'm' #define MEM_RESTART _IO(MEM_MAGIC ...

  7. Linux设备驱动中的并发控制

    1.并发是指多个执行单元同时.并行的执行.并发的执行单元对共享资源的访问很容易导致竞态. 在 Linux 内核中,主要的竞态发生于如下几种情况: ①对称多处理器(SMP)的多个 CPU ②单CPU内进 ...

  8. 蜕变成蝶~Linux设备驱动中的并发控制

    并发和竞争发生在两类体系中: 对称多处理器(SMP)的多个CPU 内核可抢占的单CPU系统 访问共享资源的代码区域称为临界区(critical sections),临界区需要以某种互斥机制加以保护.在 ...

  9. linux设备驱动中的并发控制【转】

    转自:http://www.cnblogs.com/plinx/archive/2013/01/28/2873121.html 在linux内核中,主要的静态发生于以下几种情况: 1.对称多处理器(S ...

随机推荐

  1. (转载)c++builder/delphi中透明panel及透明窗口的实现方法_delphi教程

    c++builder/delphi中透明panel及透明窗口的实现方法_delphi教程 可能大多数程序员会问:透明窗口,特别是透明Panel有什么应用价值呢?可别小看它们哦,下面我就来讲讲他们的巨大 ...

  2. 虚拟内存设备驱动memdev及实例代码

    驱动: #include <linux/module.h> #include <linux/types.h> #include <linux/fs.h> #incl ...

  3. Django路由

    一.路由流程 1. 用户浏览器发出请求后,通过根url设置,去找urlpattern变量.在setting.py中对 ROOT_URLCONF进行配置,以确定根URLconf(URL configur ...

  4. Ubuntu Vim YouCompleteMe 安装

    0. 必要工具安装 sudo apt-get install build-essential cmake 1. 安装 vundle mkdir ~/.vim/bundle git clone http ...

  5. bug - colorWithPatternImage:

    // 在ios5之前, 再通过以下方法设置背景时, 有闪屏bug self.view.backgroundColor = [UIColor colorWithPatternImage:<#(no ...

  6. 20 个最棒的 jQuery Tab 插件

    jQuery Tab 常用来做网页上的选项设置界面和导航,本文向你推荐最棒的 20 个 jQuery Tab 插件.Enjoy !! 1. Slider Tabs SliderTabs 是一个可定制的 ...

  7. BT5之网络配置

    输入ifconfig命令,可以查看当前IP地址设置情况.查看路由表的命令(用来检查默认网关是否设置正确):netstat -r 一.让BT5自动获取IP地址 自动获取IP地址,使用dhclient命令 ...

  8. 双缓冲(Double Buffer)原理和使用

    转自双缓冲(Double Buffer)原理和使用 一.双缓冲作用            双缓冲甚至是多缓冲,在许多情况下都很有用.一般需要使用双缓冲区的地方都是由于"生产者"和& ...

  9. 10行Python代码解决约瑟夫环(模拟)

    http://blog.csdn.net/dengyaolongacmblog/article/details/39208675 #!/usr/bin/env python # coding: utf ...

  10. ANDROID_MARS学习笔记_S02_004_ExpandableListActivity

    1.main.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" x ...