linux驱动程序中的异步编程

来源:互联网 发布:windows xp字体大小 编辑:程序博客网 时间:2024/06/06 01:40
linux驱动程序中的异步编程 


前面介绍的等待队列和轮询编程提供了较好的解决设备访问的机制,但是这些机制都 
是由应用程序发起的,都需要应用程序主动访问设备。更完美的方式是由驱动程序主 
动通知应用程序,也就是说,当驱动程序满足某些条件后,会主动通知应用程序处理 
,这些处理方式有些像面向对象编程的事件,而在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);   
}   



设备驱动中异步通知编程比较简单,主要用到一项数据结构和两个函数。 
数据结构是 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,此时应用程序进入处理接受信号函数。

0 0
原创粉丝点击