linux驱动程序中的异步编程

linux驱动程序中的异步编程

A
前面介绍的等待队列和轮询编程提供了较好的解决设备访问的机制,但是这些机制都
是由应用程序发起的,都需要应用程序主动访问设备。更完美的方式是由驱动程序主
动通知应用程序,也就是说,当驱动程序满足某些条件后,会主动通知应用程序处理
,这些处理方式有些像面向对象编程的事件,而在linux内核使用的事件是接下来要介
绍的信号。

#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);  
    data[len]=0;  
    printf("input available:%s\n",data);  
}  
  


main()  
{  
    int oflags;  
    
    signal(SIGIO,input_handler);   //捕获SIGIO信号
    //通过F_SETOWN将标准输入设备文件(驱动)STDIN_FILENO--的拥有者设置为
   //当前进程,这样从设备驱动STDIN_FILENO发出的信号才能被当前进程所接到。
    fcntl(STDIN_FILENO,F_SETOWN,getpid());  
    oflags=fcntl(STDIN_FILENO,F_GETFL); 
   // 通过F_SETFL使设备文件支持FASYNC,也就是异步通知模式。
    fcntl(STDIN_FILENO,F_SETFL,oflags|FASYNC);  
  
    while(1);  
}  


B
设备驱动中异步通知编程比较简单,主要用到一项数据结构和两个函数。
数据结构是 fasync_struct 结构体,
两个函数分别如下。 
处理 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; /*cdev 结构体*/   
        ...   
      struct fasync_struct *async_queue; /* 异步结构体指针 */   
 };   
在设备驱动的 fasync() 函数中,只需要简单地将该函数的 3 个参数以及
fasync_struct 结构体指针的指针作为第 4 个参数传入 fasync_helper()函数即

可。代码清单给出了支持异步通知的设备驱动程序 fasync()函数的模板。

//处理应用程序的F_SETFL命令的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);   
 }   
static  struct file_operations dev_fops=
{
.owner=...
.read=....
.write=...
.fasync=xxx_fasync;
}
在设备资源可以获得时,应该调用 kill_fasync()释放 SIGIO 信号,可读时第 3 
个参数设置为 POLL_IN,可写时第 3 个参数设置为 POLL_OUT。下面代码为释放信号
的范例。
static ssize_t xxx_write(struct file *filp, const char _ _user *buf, size_t count,loff_t *f_pos}
       {   
   struct xxx_dev *dev = filp->private_data;   
   ...   
   
  if (dev->async_queue)   
     kill_fasync(&dev->async_queue, SIGIO, POLL_IN);   /* 产生异步读信号 */   
   ...   
 }   

最后,在文件关闭时,即在设备驱动的 release()函数中,应调用设备驱动的 
fasync()函数将文件从异步通知的列表中删除。下面代码清单给出了支持异步通知的
设备驱动release()函数的模板。
static int xxx_release(struct inode *inode, struct file *filp)   
  {   
    struct xxx_dev *dev = filp->private_data;   
   /* 将文件从异步通知列表中删除 */   
   xxx_fasync(-1, filp, 0);   

   ...   
    return 0;   

  }   


应用程序:

打开两个终端,一个运行应用程序,另外一个执行 echo   "hello" >/dev/设备名  ,

执行完这条指令后,驱动调用write函数,驱动程序中的write函数中会调用

kill_fasync(&dev->async_queue, SIGIO, POLL_IN);   /* 产生异步读信号 */ ,

这样应用程序马上捕捉到SIGIO,此时应用程序进入处理接受信号函数。





郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。