zoukankan      html  css  js  c++  java
  • 5、异步通知机制

    异步通知,的确是一种很好处理机制,熟练掌握这种手段,对我们写高质量的应用程序很有帮助。下面说说对它的理解:

    异步通知,就是让驱动去告诉应用,底层硬件发生了什么事,而不是应用主动地去查询驱动,这对系统的性能有一个很大的提升。

    首先,在驱动中

    内核首先定义一个结构体struct fasync_struct,这个结构体用来存放对应设备文件的信息(如fd, filp)并交给内核来管理。一但收到信号,内核就会在这个所谓的异步队列头找到相应的文件(fd),并在filp->owner中找到对应的进程PID,这样就确定了向谁发。不过,此时fd, filp都还不确定,这就需要借助于fasync_helper(fd, filp, mode, &dev->async_queue),将fd,filp和定义的结构体传给内核,这样就完成了fd、filp、结构体三者的衔接。

     int test_fasync (int fd, struct file *filp, int mode) ,在后者中完成对fasync_helper的调用,从而完成对异步队列的填充。

    从这个过程中,也可以看到,哪个进程完成对ops成员fasync成员的调用,就会把fd、filp传给异步队列,kill_fasync发出信号就会到这个进程中,这就是驱动层次的理解。

    其次,就是在应用层次

    首先,要用fcntl对此文件进行设置,

    fcntl(fd, F_SETOWN, getpid());设置接收SIGIO信号的进程组

    Oflags = fcntl(fd, F_GETFL);  得到现在文件的标志位

    fcntl(fd, F_SETFL, Oflags | FASYNC);对当前文件的标志位加上一个FASYNC属性,每当FASYNC标志改变时,驱动程序中的 fasync()函数将得以执行。

    然后就是应用程序得到SIGIO信号后,要绑定新的操作函数

    signal(SIGIO, my_signal_fun);

    这样就完成了异步通信的过程,当驱动发送kill_fasync时就会在应用程序中调用my_signal_fun函数去处理。

    应用程序举例:

    1. //信号处理函数  
    2. void my_signal_fun(int signum)  
    3. {  
    4.     unsigned char key_val;  
    5.     read(fd, &key_val, 1);  
    6.     printf("key_val: 0x%x ", key_val);  
    7. }  
    8.   
    9. int main(int argc, char **argv)  
    10. {  
    11.     unsigned char key_val;  
    12.     int ret;  
    13.     int Oflags;  
    14.   
    15.     //在应用程序中捕捉SIGIO信号(由驱动程序发送)  
    16.     signal(SIGIO, my_signal_fun);  
    17.       
    18.     fd = open("/dev/buttons", O_RDWR);  
    19.     if (fd < 0)  
    20.     {  
    21.         printf("can't open! ");  
    22.     }  
    23.   
    24.     //将当前进程PID设置为fd文件所对应驱动程序将要发送SIGIO,SIGUSR信号进程PID  
    25.     fcntl(fd, F_SETOWN, getpid());  
    26.       
    27.     //获取fd的打开方式  
    28.     Oflags = fcntl(fd, F_GETFL);   
    29.   
    30.     //将fd的打开方式设置为FASYNC --- 即 支持异步通知  
    31.     //该行代码执行会触发 驱动程序中 file_operations->fasync 函数 ------fasync函数调用fasync_helper初始化一个fasync_struct结构体,该结构体描述了将要发送信号的进程PID (fasync_struct->fa_file->f_owner->pid)  
    32.     fcntl(fd, F_SETFL, Oflags | FASYNC);  
    33.   
    34.   
    35.     while (1)  
    36.     {  
    37.         sleep(1000);  
    38.     }  
    39.       
    40.     return 0;  
    41. }  

    驱动程序举例:

    1. static int fifth_drv_fasync (int fd, struct file *filp, int on)  
    2. {  
    3.     printk("driver: fifth_drv_fasync ");  
    4.     //初始化/释放 fasync_struct 结构体 (fasync_struct->fa_file->f_owner->pid)  
    5.     return fasync_helper (fd, filp, on, &button_async);  
    1. static irqreturn_t buttons_irq(int irq, void *dev_id)  
    2. {  
    3.     struct pin_desc * pindesc = (struct pin_desc *)dev_id;  
    4.     unsigned int pinval;  
    5.       
    6.     pinval = s3c2410_gpio_getpin(pindesc->pin);  
    7.   
    8.     if (pinval)  
    9.     {  
    10.         /* 松开 */  
    11.         key_val = 0x80 | pindesc->key_val;  
    12.     }  
    13.     else  
    14.     {  
    15.         /* 按下 */  
    16.         key_val = pindesc->key_val;  
    17.     }  
    18.   
    19.     ev_press = 1;                  /* 表示中断发生了 */  
    20.     wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */  
    21.       
    22.         //发送信号SIGIO信号给fasync_struct 结构体所描述的PID,触发应用程序的SIGIO信号处理函数  
    23.     kill_fasync (&button_async, SIGIO, POLL_IN);  
    24.       
    25.     return IRQ_RETVAL(IRQ_HANDLED);  
    26. }  
  • 相关阅读:
    转载、收藏
    AndroidStudio 问题收集
    android4.4 添加快捷开关(以截屏为例)
    打开USB调试功能
    关于Http通信
    【原创】JMS生产者和消费者【PTP同步接收消息】
    【学习】JMS通信模式
    【原创】Unable to read TLD "META-INF/c.tld" from JAR file 解决方法
    【原创】websphere部署war包报错
    【转载】tom的RUNSTATS测试工具
  • 原文地址:https://www.cnblogs.com/liusiluandzhangkun/p/8544704.html
Copyright © 2011-2022 走看看