Linux 设备驱动中的 I/O模型(二)—— 异步通知和异步I/O

 阻塞和非阻塞访问、poll() 函数提供了较多地解决设备访问的机制,但是如果有了异步通知整套机制就更加完善了。

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

    阻塞I/O意味着移植等待设备可访问后再访问,非阻塞I/O中使用poll()意味着查询设备是否可访问,而异步通知则意味着设备通知自身可访问,实现了异步I/O。由此可见,这种方式I/O可以互为补充。


1、异步通知的概念和作用

影响:阻塞–应用程序无需轮询设备是否可以访问

           非阻塞–中断进行通知

即:由驱动发起,主动通知应用程序


2、linux异步通知编程

2.1 linux信号

作用:linux系统中,异步通知使用信号来实现

函数原型为:

void (*signal(int signum,void (*handler))(int)))(int)

原型比较难理解可以分解为

typedef void(*sighandler_t)(int);sighandler_t signal(int signum,sighandler_t handler);

第一个参数是指定信号的值,第二个参数是指定针对前面信号的处理函数


2.2 信号的处理函数(在应用程序端捕获信号)

signal()函数

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. //启动信号机制  
  2.    
  3. void sigterm_handler(int sigo)  
  4. {  
  5.     char data[MAX_LEN];  
  6.     int len;  
  7.     len = read(STDIN_FILENO,&data,MAX_LEN);  
  8.     data[len] = 0;  
  9.     printf("Input available:%s\n",data);  
  10.     exit(0);  
  11.  }  
  12.    
  13. int main(void)  
  14. {  
  15.    
  16.     int oflags;  
  17.   
  18.     //启动信号驱动机制  
  19.     signal(SIGIO,sigterm_handler);  
  20.     fcntl(STDIN_FILENO,F_SETOWN,getpid());  
  21.     oflags = fcntl(STDIN_FILENO,F_GETFL);  
  22.     fctcl(STDIN_FILENO,F_SETFL,oflags | FASYNC);  
  23.       
  24.     //建立一个死循环,防止程序结束       
  25.     whlie(1);  
  26.    
  27.     return 0;  
  28. }  

2.3 信号的释放 (在设备驱动端释放信号)

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

(1)、支持F_SETOWN命令,能在这个控制命令处理中设置filp->f_owner为对应的进程ID。不过此项工作已由内核完成,设备驱动无须处理。
(2)、支持F_SETFL命令处理,每当FASYNC标志改变时,驱动函数中的fasync()函数得以执行。因此,驱动中应该实现fasync()函数
(3)、在设备资源中可获得,调用kill_fasync()函数激发相应的信号

     

     设备驱动中异步通知编程比较简单,主要用到一项数据结构和两个函数。这个数据结构是fasync_struct 结构体,两个函数分别是:

a -- 处理FASYNC标志变更

int fasync_helper(int fd,struct file *filp,int mode,struct fasync_struct **fa);

b -- 释放信号用的函数

void kill_fasync(struct fasync_struct **fa,int sig,int band);

和其他结构体指针放到设备结构体中,模板如下

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. struct xxx_dev{  
  2.     struct cdev cdev;  
  3.     ...  
  4.     struct fasync_struct *async_queue;  
  5.     //异步结构体指针  
  6. };  

      在设备驱动中的fasync()函数中,只需简单地将该函数的3个参数以及fasync_struct结构体指针的指针作为第四个参数传入fasync_helper()函数就可以了,模板如下

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. static int xxx_fasync(int fd,struct file *filp, int mode)  
  2. {  
  3.     struct xxx_dev *dev = filp->private_data;  
  4.     return fasync_helper(fd, filp, mode, &dev->async_queue);  
  5. }  
     在设备资源可获得时应该调用kill_fasync()函数释放SIGIO信号,可读时第三个参数为POLL_IN,可写时第三个参数为POLL_OUT,模板如下
[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. static ssize_t xxx_write(struct file *filp,const char __user *buf,size_t count,loff_t *ppos)  
  2. {  
  3.     struct xxx_dev *dev = filp->private_data;  
  4.     ...  
  5.        
  6.     if(dev->async_queue)  
  7.    
  8.     kill_fasync(&dev->async_queue,GIGIO,POLL_IN);  
  9.     ...  
  10. }  

    最后在文件关闭时,要将文件从异步通知列表中删除
[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. int xxx_release(struct inode *inode,struct file *filp)  
  2. {  
  3.     xxx_fasync(-1,filp,0);  
  4.    
  5.     ...  
  6.     return 0;  
  7.    
  8. }  

3、下面是个实例:

hello.c

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. #include <linux/module.h>  
  2. #include <linux/fs.h>  
  3. #include <linux/cdev.h>  
  4. #include <linux/device.h>  
  5. #include <asm/uaccess.h>  
  6. #include <linux/fcntl.h>  
  7.   
  8. static int major = 250;  
  9. static int minor=0;  
  10. static dev_t devno;  
  11. static struct class *cls;  
  12. static struct device *test_device;  
  13.   
  14. static char temp[64]={0};  
  15. static struct fasync_struct *fasync;  
  16.   
  17. static int hello_open (struct inode *inode, struct file *filep)  
  18. {  
  19.     return 0;  
  20. }  
  21. static int hello_release(struct inode *inode, struct file *filep)  
  22. {  
  23.     return 0;  
  24. }  
  25.   
  26. static ssize_t hello_read(struct file *filep, char __user *buf, size_t len, loff_t *pos)  
  27. {  
  28.     if(len>64)  
  29.     {  
  30.         len =64;  
  31.     }  
  32.     if(copy_to_user(buf,temp,len))  
  33.     {  
  34.         return -EFAULT;  
  35.     }     
  36.     return len;  
  37. }  
  38. static ssize_t hello_write(struct file *filep, const char __user *buf, size_t len, loff_t *pos)  
  39. {  
  40.     if(len>64)  
  41.     {  
  42.         len = 64;  
  43.     }  
  44.   
  45.     if(copy_from_user(temp,buf,len))  
  46.     {  
  47.         return -EFAULT;  
  48.     }  
  49.     printk("write %s\n",temp);  
  50.   
  51.     kill_fasync(&fasync, SIGIO, POLL_IN);  
  52.     return len;  
  53. }  
  54.   
  55. static int hello_fasync (int fd, struct file * file, int on)  
  56. {  
  57.     return fasync_helper(fd, file, on, &fasync);  
  58.   
  59. }  
  60. static struct file_operations hello_ops=  
  61. {  
  62.     .open = hello_open,  
  63.     .release = hello_release,  
  64.     .read =hello_read,  
  65.     .write=hello_write,  
  66. };  
  67. static int hello_init(void)  
  68. {  
  69.     int ret;      
  70.     devno = MKDEV(major,minor);  
  71.     ret = register_chrdev(major,"hello",&hello_ops);  
  72.   
  73.     cls = class_create(THIS_MODULE, "myclass");  
  74.     if(IS_ERR(cls))  
  75.     {  
  76.         unregister_chrdev(major,"hello");  
  77.         return -EBUSY;  
  78.     }  
  79.     test_device = device_create(cls,NULL,devno,NULL,"hello");//mknod /dev/hello  
  80.     if(IS_ERR(test_device))  
  81.     {  
  82.         class_destroy(cls);  
  83.         unregister_chrdev(major,"hello");  
  84.         return -EBUSY;  
  85.     }     
  86.     return 0;  
  87. }  
  88. static void hello_exit(void)  
  89. {  
  90.     device_destroy(cls,devno);  
  91.     class_destroy(cls);   
  92.     unregister_chrdev(major,"hello");  
  93.     printk("hello_exit \n");  
  94. }  
  95. MODULE_LICENSE("GPL");  
  96. module_init(hello_init);  
  97. module_exit(hello_exit);  

test.c

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. #include <sys/types.h>  
  2. #include <sys/stat.h>  
  3. #include <fcntl.h>  
  4. #include <stdio.h>  
  5. #include <signal.h>  
  6.   
  7. static int fd,len;  
  8. static char buf[64]={0};  
  9.   
  10. void func(int signo)  
  11. {  
  12.     printf("signo %d \n",signo);  
  13.     read(fd,buf,64);  
  14.     printf("buf=%s \n",buf);      
  15. }  
  16.   
  17. main()  
  18. {  
  19.   
  20.     int flage,i=0;  
  21.   
  22.     fd = open("/dev/hello",O_RDWR);  
  23.     if(fd<0)  
  24.     {  
  25.         perror("open fail \n");  
  26.         return ;  
  27.     }  
  28.   
  29.   
  30.     fcntl(fd,F_SETOWN,getpid());  
  31.     flage = fcntl(fd,F_GETFL);  
  32.     fcntl(fd,F_SETFL,flage|FASYNC);  
  33.   
  34.     signal(SIGIO,func);  
  35.   
  36.     while(1)  
  37.     {  
  38.   
  39.         sleep(1);  
  40.         printf("%d\n",i++);  
  41.     }  
  42.   
  43.     close(fd);  
  44. }  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/402218.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

判断链表是否有环

链表有环的情况一般是链表的尾指向前面的节点而不是null&#xff0c;如head->node1->node2->node3->node4->tail->node2&#xff0c;该链表存在环。判断环是否存在可以借助两个指针&#xff0c;一个指针每次迭代只移动一步&#xff0c;第二个指针每次迭代移动…

Linux 设备驱动中的 I/O模型(一)—— 阻塞和非阻塞I/O

在前面学习网络编程时&#xff0c;曾经学过I/O模型 Linux 系统应用编程——网络编程&#xff08;I/O模型&#xff09;&#xff0c;下面学习一下I/O模型在设备驱动中的应用。 回顾一下在Unix/Linux下共有五种I/O模型&#xff0c;分别是&#xff1a; a -- 阻塞I/O b -- 非阻塞I/O…

Python 爬虫进阶六之多进程的用法

python 中的多线程其实并不是真正的多线程&#xff0c;并不能做到充分利用多核 CPU 资源。 如果想要充分利用&#xff0c;在 python 中大部分情况需要使用多进程&#xff0c;那么这个包就叫做 multiprocessing。 借助它&#xff0c;可以轻松完成从单进程到并发执行的转换。mult…

Linux 设备驱动的并发控制

Linux 设备驱动中必须要解决的一个问题是多个进程对共享的资源的并发访问&#xff0c;并发的访问会导致竞态&#xff0c;即使是经验丰富的驱动工程师也常常设计出包含并发问题bug 的驱动程序。 一、基础概念 1、Linux 并发相关基础概念 a -- 并发&#xff08;concurrency&#…

第三章:多坐标系

第一节&#xff1a;为什么要有多坐标系 当我们使用一个坐标系来描绘整个场景的时候&#xff0c;场景中的任意点都可以用该坐标系描述&#xff0c;此时如果有一只羊一遍摇动着耳朵&#xff0c;一边走&#xff0c;这个时候如果进行坐标的转换会发现异常的麻烦&#xff0c;此时如果…

Linux 设备驱动开发 —— 设备树在platform设备驱动中的使用

关与设备树的概念&#xff0c;我们在Exynos4412 内核移植&#xff08;六&#xff09;—— 设备树解析 里面已经学习过&#xff0c;下面看一下设备树在设备驱动开发中起到的作用 Device Tree是一种描述硬件的数据结构&#xff0c;设备树源(Device Tree Source)文件&#xff08;以…

Android 网络通信框架Volley简介(Google IO 2013)

1. 什么是Volley 在这之前&#xff0c;我们在程序中需要和网络通信的时候&#xff0c;大体使用的东西莫过于AsyncTaskLoader&#xff0c;HttpURLConnection&#xff0c;AsyncTask&#xff0c;HTTPClient&#xff08;Apache&#xff09;等&#xff0c;今年的Google I/O 2013上&…

Linux 设备驱动开发 —— platform设备驱动应用实例解析

前面我们已经学习了platform设备的理论知识Linux 设备驱动开发 —— platform 设备驱动 &#xff0c;下面将通过一个实例来深入我们的学习。 一、platform 驱动的工作过程 platform模型驱动编程&#xff0c;需要实现platform_device(设备)与platform_driver&#xff08;驱动&am…

Python爬虫入门四urllib库的高级用法

1.设置headers 有些网站不会同意程序直接用上面的方式进行访问&#xff0c;如果识别有问题&#xff0c;那么站点根本不会响应&#xff0c;所以为了完全模拟浏览器的工作&#xff0c;我们需要设置一些 Headers 的属性。 首先&#xff0c;打开我们的浏览器&#xff0c;调试浏览器…

进程上下文、中断上下文及原子上下文

谈论进程上下文 、中断上下文 、 原子上下文之前&#xff0c;有必要讨论下两个概念&#xff1a; a -- 上下文 上下文是从英文context翻译过来&#xff0c;指的是一种环境。相对于进程而言&#xff0c;就是进程执行时的环境&#xff1b; 具体来说就是各个变量和数据&#xff0c;…

Linux 文件系统与设备文件系统 (二)—— sysfs 文件系统与Linux设备模型

提到 sysfs 文件系统 &#xff0c;必须先需要了解的是Linux设备模型&#xff0c;什么是Linux设备模型呢&#xff1f; 一、Linux 设备模型 1、设备模型概述 从2.6版本开始&#xff0c;Linux开发团队便为内核建立起一个统一的设备模型。在以前的内核中没有独立的数据结构用来让内…

Python爬虫入门七正则表达式

已经搞定了怎样获取页面的内容&#xff0c;不过还差一步&#xff0c;这么多杂乱的代码夹杂文字我们怎样把它提取出来整理呢&#xff1f;下面就开始介绍一个十分强大的工具&#xff0c;正则表达式 1.了解正则表达式 正则表达式是用来匹配字符串非常强大的工具&#xff0c;在其…

Linux 文件系统与设备文件系统 (一)—— udev 设备文件系统

一、什么是Linux设备文件系统 首先我们不看定义&#xff0c;定义总是太抽象很难理解&#xff0c;我们先看现象。当我们往开发板上移植了一个新的文件系统之后&#xff08;假如各种设备驱动也移植好了&#xff09;&#xff0c;启动开发板&#xff0c;我们用串口工具进入开发板&a…

情人节,教大家使用css画出一朵玫瑰花。

情人节到了&#xff0c;给大家来一朵高端的玫瑰花。 在网上看到的一个canvas实现的玫瑰花&#xff0c;效果很好&#xff0c;但是代码被压缩过&#xff0c;也没有注释&#xff0c;看的云里雾里的。 今天我教大脚用CSS来实现一朵玫瑰花。 先看效果 首先我们画出一个花瓣 1、画出一…

Linux 字符设备驱动开发基础(六)—— VFS 虚拟文件系统解析

一、VFS 虚拟文件系统基础概念 Linux 允许众多不同的文件系统共存&#xff0c;并支持跨文件系统的文件操作&#xff0c;这是因为有虚拟文件系统的存在。虚拟文件系统&#xff0c;即VFS&#xff08;Virtual File System&#xff09;是 Linux 内核中的一个软件抽象层。它通过一些…

vim使用—实现程序的自动补齐(C语言)

使用过Source Insight的人一定对它的自动补全功能印象深刻&#xff0c;在很多的集成开发环境中&#xff0c;也都支持自动补全。vim做为一个出色的编辑器&#xff0c;这样的功能当然少不了。至于如何实现程序自动补全&#xff0c;网上教程很多。这里&#xff0c;我将自己配置过程…

[C#]Attribute特性(3)——AttributeUsage特性和特性标识符

相关文章 [C#]Attribute特性 [C#]Attribute特性(2)——方法的特性及特性参数 AttributeUsage特性 除了可以定制自己的特性来注释常用的C#类型外&#xff0c;您可以用AttributeUsage特性来定义您想怎样使用这些特性。AttributeUsage特性采用如下的调用惯例&#xff1a; 1 [Attri…

Linux 命令 ——less命令

less 工具也是对文件或其它输出进行分页显示的工具&#xff0c;应该说是linux正统查看文件内容的工具&#xff0c;功能极其强大。less 的用法比起 more 更加的有弹性。在 more 的时候&#xff0c;我们并没有办法向前面翻&#xff0c; 只能往后面看&#xff0c;但若使用了 less …

android闹钟实现原理

闹钟的原理可用下面我自己画的一幅图来概括&#xff1a;&#xff08;不对的地方&#xff0c;尽管吐槽&#xff09; 我们来看看新建闹钟到闹钟响铃的步骤&#xff1a; 1、新建一个闹钟&#xff1a; ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22…

将openstack的Token认证信息存储在memcache中

公司线上的openstack环境运行了5个多月的时间&#xff0c;keystone库的token表已经增长到了31GB&#xff0c;这个数据量还是很大的&#xff0c;对于以后的数据库备份很不方便。每次管理openstack的时候&#xff0c;都会产生一个新的token验证&#xff0c;而历史token信息其实都…