一、中断嵌套
   当系统正在执行某中断处理函数时,又产生了一个新的中断,这就叫做中断嵌套。当中断为慢速中断时,新的中断会取代当前中断,即当前中断没有执行完就结束
了;当中断为快速中断时,新的终端就不会产生。这两种情况都是我们不愿意看到的情况,所以就有了今天的题目——中断分层。

二、中断分层
  中断分层是将中断处理函数分为上下两个部分。上半部是与硬件相关的,下半部是与硬件无关的。与硬件无关的内容我们就可以将它分离出中断处理函数,交给内核在系统空闲的时候处理,这样就缩短了中断处理的时间,从而减小了中断丢失的几率。
  分层方式:
    1、软中断
    2、tasklet
    3、工作队列
三、工作队列处理方式
  将中断下半部分的工作挂载到工作队列中去,在内核空闲的时候将工作调用。Linux内核使用struct    workqueue_struct来描述一个工作队列,用struct    work_struct来描述一个工作项。

  1. struct workqueue_struct {
  2. unsigned int flags; /* I: WQ_* flags */
  3. union {
  4. struct cpu_workqueue_struct __percpu *pcpu;
  5. struct cpu_workqueue_struct *single;
  6. unsigned long v;
  7. } cpu_wq; /* I: cwq's */
  8. struct list_head list; /* W: list of all workqueues */
  9.  
  10. struct mutex flush_mutex; /* protects wq flushing */
  11. int work_color; /* F: current work color */
  12. int flush_color; /* F: current flush color */
  13. atomic_t nr_cwqs_to_flush; /* flush in progress */
  14. struct wq_flusher *first_flusher; /* F: first flusher */
  15. struct list_head flusher_queue; /* F: flush waiters */
  16. struct list_head flusher_overflow; /* F: flush overflow list */
  17.  
  18. mayday_mask_t mayday_mask; /* cpus requesting rescue */
  19. struct worker *rescuer; /* I: rescue worker */
  20.  
  21. int saved_max_active; /* W: saved cwq max_active */
  22. const char *name; /* I: workqueue name */
  23. };

  

  1. struct work_struct {
  2. atomic_long_t data;
  3. struct list_head entry;
  4. work_func_t func;
  5. };

  1、创建工作队列
  create_workqueue(name)
  参数:name为const char *类型,创建工作队列的名字
  返回值:struct    workqueue_struct*型指针
  2、创建工作
  INIT_WORK(_work, _func)
  参数:

    work:创建好工作项变量的地址
    func:工作项中的成员func的名字
  无返回值
  3、提交工作
  即将工作项挂载到工作队列中去。
  int    queue_work(struct workqueue_struct *wq, struct work_struct *work)
  参数:

    wq:工作队列变量的地址
    work:工作项变量的地址

  

  其实Linux内核已创建好了一个默认的工作队列供用户使用,keventd_wq,这样我们就不用再去进行创建工作队列的工作。提交工作项到默认工作队列的函数为
  int    schedule_work(struct work_struct *work)
  参数:要提交工作项的地址

工作队列应用代码:

  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3.  
  4. struct work_struct *work1,*work2;
  5.  
  6. void work1_func()
  7. {
  8. printk("this is work1\n");
  9. }
  10.  
  11. void work2_func()
  12. {
  13. printk("this is work2\n");
  14. }
  15.  
  16. int que_init()
  17. {
  18. /*创建工作*/
  19. work1 = kmalloc(sizeof(struct work_struct),GFP_KERNEL);
  20.  
  21. INIT_WORK(work1, work1_func);
  22.  
  23. /*挂载工作到工作队列*/
  24. schedule_work(work1);
  25.  
  26. /*创建工作*/
  27. work2 = kmalloc(sizeof(struct work_struct),GFP_KERNEL);
  28.  
  29. INIT_WORK(work2, work2_func);
  30.  
  31. /*挂载工作到工作队列*/
  32. schedule_work(work2);
  33.  
  34. return ;
  35. }
  36.  
  37. void que_exit()
  38. {
  39.  
  40. }
  41.  
  42. MODULE_LICENSE("GPL");
  43. module_init(que_init);
  44. module_exit(que_exit);

将中断分层应用到键盘中断驱动程序中:

  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/fs.h>
  4. #include <linux/miscdevice.h>
  5. #include <linux/interrupt.h>
  6. #include <linux/io.h>
  7.  
  8. #define GPGCON 0x56000060
  9.  
  10. /*定义工作队列*/
  11. struct work_struct *work1;
  12.  
  13. void work1_func()
  14. {
  15. printk("press key down\n");
  16. }
  17. int que_init()
  18. {
  19. /*创建工作*/
  20. work1 = kmalloc(sizeof(struct work_struct),GFP_KERNEL);
  21.  
  22. INIT_WORK(work1, work1_func);
  23. }
  24.  
  25. /*中断处理函数*/
  26. irqreturn_t key_int(int irq, void *dev_id)
  27. {
  28. /*1、检测设备是否产生中断*/
  29.  
  30. /*2、清除中断产生标志*/
  31.  
  32. /*3、提交下半部分工作*/
  33. schedule_work(work1);
  34.  
  35. return ;
  36. }
  37.  
  38. void key_hw_init()
  39. {
  40. unsigned int data;
  41. unsigned int *gpio_config;
  42.  
  43. gpio_config = ioremap(GPGCON,);
  44. data = readw(gpio_config);
  45. data &= (()|(<<)|(<<)|(<<)|(<<)|(<<));//~(0b11);
  46. data |= (|(<<)|(<<)|(<<)|(<<)|(<<));//0b10;
  47. writew(data,gpio_config);
  48. }
  49.  
  50. int key_open(struct inode *node, struct file *filp)
  51. {
  52. return ;
  53. }
  54.  
  55. struct file_operations key_fops =
  56. {
  57. .open = key_open,
  58. //.unlocked_ioctl = key_ioctl,
  59. };
  60.  
  61. struct miscdevice key_miscdev =
  62. {
  63. .minor = ,
  64. .name = "key",
  65. .fops = &key_fops,
  66. };
  67.  
  68. static int key_init()
  69. {
  70. /*注册设备*/
  71. misc_register(&key_miscdev);
  72.  
  73. /*硬件初始化*/
  74. key_hw_init();
  75.  
  76. /*注册中断*/
  77. request_irq(IRQ_EINT8,key_int,IRQF_TRIGGER_FALLING ,"key", );
  78. request_irq(IRQ_EINT11,key_int,IRQF_TRIGGER_FALLING ,"key", );
  79. request_irq(IRQ_EINT13,key_int,IRQF_TRIGGER_FALLING ,"key", );
  80. request_irq(IRQ_EINT14,key_int,IRQF_TRIGGER_FALLING ,"key", );
  81. request_irq(IRQ_EINT15,key_int,IRQF_TRIGGER_FALLING ,"key", );
  82. request_irq(IRQ_EINT19,key_int,IRQF_TRIGGER_FALLING ,"key", );
  83.  
  84. que_init();
  85. printk("key.ko is ready\n");
  86. return ;
  87. }
  88.  
  89. static void key_exit()
  90. {
  91. /*注销设备*/
  92. misc_deregister(&key_miscdev);
  93. /*注销中断*/
  94. free_irq(IRQ_EINT8, );
  95. }
  96.  
  97. MODULE_LICENSE("GPL");
  98. module_init(key_init);
  99. module_exit(key_exit);

实现功能:

  当按下一个按键,在串口中打印出对应的信息。

此代码适用mini2440开发板,不同型号开发板IO口和中断号不同。如果有疑问或建议,欢迎指出。

Linux中断分层技术的更多相关文章

  1. Linux中断分层--软中断和tasklet

    1. Linux中断分层 (1)上半部:当中断发生时,它进行相应的硬件读写,并“登记”该中断.通常由中断处理程序充当上半部.(一般情况下,上半部不可被打断) (2)下半部:在系统空闲的时候,对上半部“ ...

  2. Linux中断分层--工作队列

    1. 工作队列是一种将任务推后执行的方式,它把推后的任务交由一个内核线程去执行.这样中断的下半部会在进程上下文执行,他允许重新调度甚至睡眠.每个被推后的任务叫做“工作”,由这些工作组成的队列称为工作队 ...

  3. Linux设备驱动之中断支持及中断分层

    快速中断:在开启快速中断时,其他中断不会打断快速中断. 多个中断共享一个中断号. 中断行为受到限制: 1.不能使用可能引起阻塞的函数 2.不能使用可能引起调度的函数 中断注册:request_irq( ...

  4. Linux中断管理 (1)Linux中断管理机制

    目录: <Linux中断管理> <Linux中断管理 (1)Linux中断管理机制> <Linux中断管理 (2)软中断和tasklet> <Linux中断管 ...

  5. Linux中断管理 (3)workqueue工作队列

    目录: <Linux中断管理> <Linux中断管理 (1)Linux中断管理机制> <Linux中断管理 (2)软中断和tasklet> <Linux中断管 ...

  6. Linux kprobe调试技术使用

    kprobe调试技术是为了便于跟踪内核函数执行状态所设计的一种轻量级内核调试技术. 利用kprobe技术,可以在内核绝大多数函数中动态插入探测点,收集调试状态所需信息而基本不影响原有执行流程. kpr ...

  7. Linux中断概述

    中断和异常 1.1中断的由来及实质 Linux内核要管理计算机上的硬件设备,首先要和他们通信.而处理器的速度跟外围硬件设备的速度往往不在一个数量级上,因此,如果内核采取让处理器向硬件发出一个请求,然后 ...

  8. Linux内核调试技术——jprobe使用与实现

    前一篇博文介绍了kprobes的原理与kprobe的使用与实现方式,本文介绍kprobes中的另外一种探測技术jprobe.它基于kprobe实现,不能在函数的任何位置插入探測点,仅仅能在函数的入口处 ...

  9. Linux中断管理 (3)workqueue工作队列【转】

    转自:https://www.cnblogs.com/arnoldlu/p/8659988.html 目录: <Linux中断管理> <Linux中断管理 (1)Linux中断管理机 ...

随机推荐

  1. SKPhysicsJointSpring类

    继承自 NSObject 符合 NSCoding(SKPhysicsJoint)NSObject(NSObject) 框架  /System/Library/Frameworks/SpriteKit. ...

  2. Com编程入门——什么是COM,如何使用COM

    本文的目的是为刚刚接触COM的程序员提供编程指南,并帮助他们理解COM的基本概念.内容包括COM规范简介,重要的COM术语以及如何重用现有的COM组件.本文不包括如何编写自己的COM对象和接口. CO ...

  3. Ubuntu安装分区设置

    我的Ubuntu 安装分区 /boot   200M /          2000M /home  6000M swap    1000M /boot分区,它包含了操作系统的内核和在启动系统过程中所 ...

  4. git查看某个文件的修改历史

    <转自 http://www.cnblogs.com/flyme/archive/2011/11/28/2265899.html> 有时候在比对代码时,看到某些改动,但不清楚这个改动的作者 ...

  5. 读书笔记--用Python写网络爬虫01--网络爬虫简介

    Wiki - Web crawler 百度百科 - 网络爬虫 1.1 网络爬虫何时使用 用于快速自动地获取网络信息,避免重复性的手工操作. 1.2 网络爬虫是否合法 网络爬虫目前人处于早期的蛮荒阶段, ...

  6. fastUtils学习

    比传统java集合工具类速度更快 google的guava也新增了java容器新的功能,功能更加强大,参考文档:http://www.ibm.com/developerworks/cn/java/j- ...

  7. 如何在CentOS 7上修改主机名

    如何在CentOS 7上修改主机名 在CentOS中,有三种定义的主机名:静态的(static),瞬态的(transient),和灵活的(pretty).“静态”主机名也称为内核主机名,是系统在启动时 ...

  8. Visual Studio 2013如何破解(密钥激活)

    其实有个方法最简单,就是点击“帮助”,选择注册产品,点击打开页面右下边的“使用秘钥注册产品”,输入上述秘钥即可.   在输入密钥界面,输入密钥“BWG7X-J98B3-W34RT-33B3R-JVYW ...

  9. JavaScript 客户端JavaScript之 脚本化文档

    客户端JavaScript的存在把静态HTML转变为交互式的Web应用程序,脚本化Web页面的内容正是JavaScript存在的理由.   一个文档对象模型或者说DOM就是一个API,它定义了如何访问 ...

  10. preventDefault() 方法 取消掉与事件关联的默认动作

    前几天写的 响应键盘的图片切换 中, 键盘总是让浏览器滚动,为了取消掉默认的事件,使用了 preventDefault() 方法 定义和用法 preventDefault() 方法取消事件的默认动作. ...