Linux 设备驱动学习之 异步通知

转载 2012年06月16日 13:06:31

From:http://blog.csdn.net/ypoflyer/article/details/6131334

 

异步通知:

 

使用poll轮询方式的时候,相当于应用程序在需要的时候询问设备“准备好了吗?”,如果有这样一种情况,一个进程在低优先级正在执行长的循环计算,但又需要“尽可能快”的处理输入数据,如果采用poll的方式,那么需要这个应用程序周期性的调用poll来检测数据,也就是周期性的询问设备“准备好了吗?”,显然这种情况下poll并不是最佳的方法。更好的方法应该是一旦设备准备好了就发出一个“我准备好了”的信号给应用程序,然后应用程序再去处理。这样显然更高效。这种方法就是:异步通知。

 


通过上面的描述,显然如果想要异步通知,首先设备就要有发信号的功能,这就要启动文件的异步通知机制。为了启动这个机制,用户程序需要进行两个步骤:
1.指定一个进程作为文件的owner(“所有者”或者“属主”),用来接收“我准备好了”这个信号。该进程的ID好被保存到filp->f_owner中。通过调用fcntl执行F_SETOWN来完成这一步。
2.在设备中设置FASYNC标志来真正启动异步通知机制。通过调用fcntl执行F_SETFL命令完成这一步。

 


执行完这两个步骤以后,当有新数据到达时设备文件会发送一个SIGIO信号(“我准备好了”),该信号被发送到存放在file->f_owner中的进程。
注:显然进程如果只接受到“我准备好了”这个信号,它就会问“那个‘我’是谁阿”,所以如果有多于一个文件可以异步通知输入的进程,那么当应用程序接收到信号时还是要借助poll轮询一次,以便真正确定输入的来源。


下面分别从驱动程序角度和应用程序角度分别总结一下我们应该进行哪些工作。
一、 驱动方面:
1. 在设备抽象的数据结构中增加一个struct fasync_struct的指针
2. 实现设备操作中的fasync函数,其主体就是调用内核的fasync_helper函数。
3. 在需要向用户空间通知的地方(例如scullpipe的write中)调用内核的kill_fasync函数。
4. 在驱动的release方法中调用前面定义的fasync函数, 例如scull_p_fasync(-1, filp, 0);


看一下驱动方面的源码:


    //对应上边的第1步
    struct scull_pipe   

  1.     {  
  2.         ......  
  3.         struct fasync_struct *async_queue;   
  4.         ......  
  5.     };  

 

    //对应上面的第2步
static int scull_p_fasync(int fd, struct file *filp, int mode)   

  1.     {  
  2.         struct scull_pipe *dev = filp->private_data;  
  3.   
  4.         return fasync_helper(fd, filp, mode, &dev->async_queue);  
  5.     }  
    
    //对应上面的第3步,由于新数据是由于进程调用了write而产生的,所以在这里发送SIGIO信号
static ssize_t scull_p_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)  
  1.     {  
  2.         ......  
  3.         ......  
  4.         if (dev->async_queue)   
  5.             kill_fasync(&dev->async_queue, SIGIO, POLL_IN);  
  6.         ......  
  7.         ......  
  8.   
  9.     }  
    
    //对应上面第4步
  1. static int scull_p_release(struct inode *inode, struct file *filp)  
  2.     {  
  3.         ......  
  4.         scull_p_fasync(-1, filp, 0);  
  5.         ......  
  6.     }  

 

 


二、 应用层方面
1. 利用signal或者sigaction设置SIGIO信号的处理函数,关于signal的使用参照http://blog.csdn.net/ypoflyer/article/details/6131334

2. fcntl的F_SETOWN指令设置当前进程为设备文件owner
3. fcntl的F_SETFL指令设置FASYNC标志


看一下应用层方面的源代码,来自asynctest.c文件
   

#include <stdio.h>  
  1. #include <stdlib.h>  
  2. #include <string.h>  
  3. #include <unistd.h>  
  4. #include <signal.h>  
  5. #include <fcntl.h>  
  6.   
  7. int gotdata=0;  
  8. void sighandler(int signo) //这个就是收到SIGIO信号对应的处理函数  
  9. {  
  10.     if (signo==SIGIO)  
  11.         gotdata++;  
  12.     return;  
  13. }  
  14.   
  15. char buffer[4096];  
  16.   
  17. int main(int argc, char **argv)  
  18. {  
  19.     int count;  
  20.     struct sigaction action; //sigaction结构变量action  
  21.   
  22.     memset(&action, 0, sizeof(action)); //清空该变量  
  23.     action.sa_handler = sighandler;  
  24.     action.sa_flags = 0;  
  25.   
  26.     //对应上面的第1步,设置SIGIO的处理函数为sighandle  
  27.     sigaction(SIGIO, &action, NULL); r  
  28.   
  29.     //对应上面的第2步,设置当前进程为设备文件owner。使用getpid获得当前进程的ID  
  30.     fcntl(STDIN_FILENO, F_SETOWN, getpid());  
  31.   
  32.     //对应上面的第3步,设置FASYNC标志,使用的命令是F_SETFL  
  33.     //一旦文件描述符被设置成具有FASYNC属性的状态,  
  34.     //也就是将设备文件切换到异步操作模式。  
  35.     //这时系统就会自动调用驱动程序的fasync方法  
  36.     fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | FASYNC);  
  37.     //到此异步通知机制就已经设置好了  
  38.       
  39.     while(1) {  
  40.         /* this only returns if a signal arrives */  
  41.         sleep(86400); //此处线程开始休眠,该程序一直处于休眠状态,当有标准输入时候,linux操作系统发送SIGIO消息给进程,并将其唤醒  
  42.         if (!gotdata) //唤醒之后还要再检查以下gotdata的状态,如果不是SIGIO唤醒的,则表明没有标准输入,则继续进行while循环  
  43.             continue;  
  44.         count=read(0, buffer, 4096);  
  45.         /* buggy: if avail data is more than 4kbytes... */  
  46.         write(1,buffer,count);  
  47.         gotdata=0;  
  48.     }  
  49. }  

 

 

相关文章推荐

linux 设备驱动异步通知总结

  • 2016年02月18日 15:18
  • 16KB
  • 下载

linux设备驱动开发学习之旅--异步通知

[cpp] view plaincopy /**   * Author:hasen   * 参考 :《linux设备驱动开发详解》   * 简介:android小菜...

07-S3C2440驱动学习(一)嵌入式linux字符设备驱动-按键驱动程序之异步通知机制+原子操作+互斥信号量+阻塞与非阻塞+定时器去抖

一、异步通知机制 从按键的实现方式来说,可以分为以下几种方式 查询方式,极度耗费CPU资源中断方式,平时休眠,按键按下,唤醒休眠poll机制,不需要一直read,根据poll返回值来决定是否rea...

深入浅出 Linux设备驱动异步通知介绍

结合阻塞与非阻塞访问、poll函数可以较好地解决设备的读写,但是如果有了异步通知就更方便了。异步通知的意思是:一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,这一点非常类似于硬...
  • ailinty
  • ailinty
  • 2011年09月01日 14:45
  • 318

Linux的异步通知字符设备驱动

Fasync字符驱动: 1、在我们用户程序下所做的工作: ⑴ 注册信号处理函数。 通过signal 或sigaction()实现。 ⑵ 使进程成为该文件的的属主进程。  通过fcntl 的F_SETO...

Linux设备驱动之异步通知

Linux设备驱动之异步通知的原理及简单代码实现
  • ljmiaw
  • ljmiaw
  • 2017年07月16日 21:02
  • 69

linux字符设备驱动-异步通知

异步通知关键步骤: 1,应用注册信号处理函数,使用signal函数; 2,谁来发:驱动发送通知信号; 3,发给谁:驱动发送通知给特定的应用程序,驱动需要知道应用程序的PID号; 4,怎么发:驱...

linux设备驱动归纳总结(三):7.异步通知fasync

linux设备驱动归纳总结(三):7.异步通知fasync xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...

Linux设备驱动一 (3)异步通知

异步通知,就是让驱动去告诉应用,底层硬件发生了什么事,而不是应用主动地去查询驱动,这对系统的性能有一个很大的提升。    应用层次         1、要用fcntl对此文件进行设置,      ...

Linux字符设备驱动之异步通知

在linux中,异步通知是使用信号来实现的,而在linux,大概有30种信号,比如大家熟悉的ctrl+c的SIGINT信号,进程能够忽略或者捕获除过SIGSTOP和SIGKILL的全部信号,当信号背捕...
  • Lyanzh
  • Lyanzh
  • 2017年08月10日 10:09
  • 176
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Linux 设备驱动学习之 异步通知
举报原因:
原因补充:

(最多只允许输入30个字)