转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=21977330&id=3755609

在linux里,中断处理分为顶半(top half),底半(bottom half),在顶半里处理优先级比较高的事情,要求占用中断时间尽量的短,在处理完成后,就激活底半,有底半处理其余任务。底半的处理方式主要有soft_irq, tasklet, workqueue三种,他们在使用方式和适用情况上各有不同。soft_irq用在对底半执行时间要求比较紧急或者非常重要的场合,主要为一些subsystem用,一般driver基本上用不上。 tasklet和work queue在普通的driver里用的相对较多,主要区别是tasklet是在中断上下文执行,而work queue是在process上下文,因此可以执行可能sleep的操作。

request_threaded_irq()是Linux kernel 2.6.30 之后新加的irq handler API

如何确定可以用到 request_threaded_irq() ? 
Linux kernel config 需要定义CONFIG_GENERIC_HARDIQS 
kernel config 才有支援threaded irq

Moving interrupts to threads 介绍request_threaded_irq() 的由来 
    http://lwn.net/Articles/302043/ 
    从realtime tree 移植而来,为了减少kernel 因为要等待每一个硬件中断处理的时间 
    ,就另外交给kernel thread 处理中断后续工作。 
    优点: 
        1 减少 kernel 延迟时间 
        2 避免处理中断时要分辨是在硬体中断或软体中断? 
        3 更容易为kernel 中断处理除错,可能可完全取代tasklet 
    原本的中断处理分上半部(硬体中断处理,必须关闭中断无法处理新的中断)跟下半部( 
    软体中断处理),因此上半部的硬体中断处理必须尽可能简短,让系统反应速度更快。

request_threaded_irq 是在将上半部的硬件中断处理缩短为只确定硬体中断来 
    自我们要处理的装置,唤醒kernel thread 执行后续中断任务。

缺点: 
    对于非irq 中断的kernel threads ,需要在原本task_struct 新增struct 
    irqaction 多占 4/8 bytes 记忆体空间 
    linux kernel 2.6.29 之后(2.6.30)加入request_threaded_irq

跟传统top/bottom havles 的差异是threaded_irq 受Linux kernel system 
    的 process scheduling 控制,不会因为写错的bottom half 代码造成整个系统 
    延迟的问题。

也可以透过RT/non RT 跟nice 等工具调整各个thread 优先权,丢给使用率较低的 
    cpu 以及受惠于kernel 原本可以对threads 做的各种控制,包括但不限于sleep, 
    lock, allocate 新的记忆体区块。

受惠最大的是shared irq line 的多个中断处理。除了可以加速共享中断造成的延迟 
    ,threaded_irq 也可以降低在同一段程式码处理多个装置中断的复杂度。

threaded irq 在使用性上也比tasklet(接着top half 直接执行,无法sleep) 
    /workqueue(kernel context?) 等需要在top half 增加跟bottom half 连结与沟通 
    的麻烦。

int request_threaded_irq(unsigned int irqirq_handler_t handlerirq_handler_t thread_fn, unsigned long irqflags, const char *devname, void *dev_id)

IRQF_SHARED 共享中断时,dev_id不能为空,因为释放irq时要区分哪个共享中断
irq:中断号
handler:发生中断时首先要执行的硬中断处理函数,这个函数可以通过返回 IRQ_WAKE_THREADED唤醒中断线程,也可
返回IRQ_HANDLE不执行中断线程
thread_fn : 中断线程,类似于中断下半部
后三个参数与request_irq中的一致

关于IRQF_ONESHOT, 直到线程函数执行完毕才会开启该中断

  1. IRQF_ONESHOT:Interrupt is not reenabled after the hardirq handler finished.
  2.     Used by threaded interrupts which need to keep the irq line disabled until
  3. the threaded handler has been run. 这里linus在邮件列表里指明IRQF_ONESHOT 的原因
  4. Making the IRQF_ONESHOT explicit does two things:
  5. - it makes people who read the code *aware* of things
  6. - if/when you have irq conflicts and two drivers want to attach to
  7. the same interrupt, at least you can see directly from the source what
  8. flags they used (and again, not have to even *think* about it).
  9.  
  10. IRQF_ONESHOT IRQF_SHARED 不能同时使用
  11. 当多个设备共享中断时,由于IRQF_ONESHOT会关闭中断线程的中断,而线程一般执行时间会比较长,所以是不允许的
  12. hardirq函数为NULL时,必须声明IRQF_ONESHOT, 表示threadirq线程中关闭该中断,在某些情况下,这个标志会非常有用
  13. 例如:设备是低电平产生中断,而硬中断函数为NULL,如果不使用IRQF_ONESHOT,就会一直产生中断执行NULL函数,中断线程
  14. 得不到执行,声明IRQF_ONESHOT后,会执行完线程才使能该中断  

点击(此处)折叠或打开

  1. /*
  2. * gpio_irqTest.c
  3. * PB27 receive this signal as IRQ and make the LED linking on PB17 turn on or turn off
  4. *
  5. */
  6. #include <linux/types.h>
  7. #include <linux/kernel.h>
  8. #include <linux/module.h>
  9. #include <linux/init.h>
  10. #include <linux/platform_device.h>
  11. #include <linux/cdev.h>
  12. #include <linux/ioctl.h>
  13. #include <linux/fs.h>
  14. #include <linux/gpio.h>
  15. #include <linux/delay.h>
  16. #include <linux/cdev.h>
  17. #include <linux/interrupt.h>
  18. #include <asm/io.h>
  19. #include <asm/io.h>
  20. #include <mach/gpio.h>
  21. #include <mach/hardware.h>
  22. #include <mach/board.h>
  23. #include <mach/gpio.h>
  24. #include <mach/at91_pio.h>
  25. #include <mach/at91_aic.h>
  26. #include <mach/at91_pmc.h>
  27. void led_on()
  28. {
  29. // at91_set_gpio_output(AT91_PIN_PB17,1);
  30. printk("led on\n");
  31. }
  32. void led_off()
  33. {
  34. // at91_set_gpio_output(AT91_PIN_PB17 ,0);
  35. printk("led off.\n");
  36. }
  37. struct light_dev *light_devp;
  38. int light_major = 200;
  39. struct light_dev
  40. {
  41. struct cdev cdev;
  42. unsigned char value;
  43. };
  44. static void io_init(void)
  45. {
  46. at91_set_GPIO_periph(AT91_PIN_PB27, 0);
  47. at91_set_gpio_input(AT91_PIN_PB27, 1);
  48. at91_set_deglitch(AT91_PIN_PB27, 1);
  49. }
  50. struct gpio_irq_desc
  51. {
  52. int pin;
  53. int irq;
  54. unsigned long flags;
  55. char *name;
  56. };
  57. static struct gpio_irq_desc gpio_irq={AT91_PIN_PB27, AT91_PIN_PB27,IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING|IRQF_ONESHOT,"PB27"};
  58. static irqreturn_t gpio_irqhandler(int irq, void *dev_id)
  59. {
  60. printk(KERN_INFO "In hard irq handler.\n");
  61. return IRQ_WAKE_THREAD;
  62. }
  63. static irqreturn_t gpio_threadhandler(int irq, void *dev_id)
  64. {
  65. int rst;
  66. rst = at91_get_gpio_value(gpio_irq.pin);
  67. printk(KERN_INFO "gpio stat: %d\n", rst);
  68. if(rst == 0){
  69. led_on();
  70. }else{
  71. led_off();
  72. }
  73. printk(KERN_INFO "sleep 3000ms\n");
  74. msleep(3000);
  75. printk(KERN_INFO "awake after sleep\n");
  76. return IRQ_HANDLED;
  77. }
  78. int light_open(struct inode *inode,struct file *filp)
  79. {
  80. int err;
  81. struct light_dev *dev;
  82. dev = container_of(inode->i_cdev,struct light_dev,cdev);
  83. filp->private_data = dev;
  84. printk(KERN_DEBUG "%s", __FUNCTION__);
  85. io_init();
  86. // err = request_threaded_irq(gpio_irq.irq,gpio_irqhandler,gpio_threadhandler,gpio_irq.flags,gpio_irq.name,(void*)0);
  87. err = request_threaded_irq(gpio_irq.irq,NULL,gpio_threadhandler,gpio_irq.flags,gpio_irq.name,(void*)0);
  88. if(err)
  89. {
  90. // free_irq(gpio_irq.irq,(void*)0);
  91. printk(KERN_DEBUG "request irq failed.\n");
  92. return -EBUSY;
  93. }
  94. return 0;
  95. }
  96. int light_release(struct inode *inode,struct file *filp)
  97. {
  98. free_irq(gpio_irq.irq,(void*)0);
  99. return 0;
  100. }
  101. int light_ioctl(struct inode *inode,struct file *filp,unsigned int cmd, unsigned long arg)
  102. {
  103. struct light_dev *dev = filp->private_data;
  104. switch(cmd)
  105. {
  106. case 0:
  107. at91_set_gpio_output(AT91_PIN_PB19,0);
  108. break;
  109. case 1:
  110. at91_set_gpio_output(AT91_PIN_PB19,1);
  111. led_off();
  112. break;
  113. default:
  114. return -ENOTTY;
  115. // break;
  116. }
  117. return 0;
  118. }
  119. struct file_operations light_fops =
  120. {
  121. .owner = THIS_MODULE,
  122. .open = light_open,
  123. .release = light_release,
  124. .unlocked_ioctl = light_ioctl,
  125. };
  126. static void light_setup_cdev(struct light_dev *dev,int index)
  127. {
  128. int err,devno = MKDEV(light_major,index);
  129. cdev_init(&dev->cdev,&light_fops);
  130. dev->cdev.owner = THIS_MODULE;
  131. dev->cdev.ops = &light_fops;
  132. err = cdev_add(&dev->cdev,devno,1);
  133. if(err)
  134. {
  135. printk(KERN_NOTICE "Error %d adding LED%d",err,index);
  136. }
  137. }
  138. int __init light_init(void)
  139. {
  140. int result;
  141. dev_t dev = MKDEV(light_major,0);
  142. if(light_major)
  143. {
  144. result = register_chrdev_region(dev,1,"gpio");
  145. }
  146. if(result < 0)
  147. {
  148. printk(KERN_DEBUG "%s: register char dev failed.\n", __FUNCTION__);
  149. return result;
  150. }
  151. light_devp = kmalloc(sizeof(struct light_dev),GFP_KERNEL);
  152. if(!light_devp)
  153. {
  154. result = - ENOMEM;
  155. goto fail_malloc;
  156. }
  157. memset(light_devp,0,sizeof(struct light_dev));
  158. light_setup_cdev(light_devp,0);
  159. printk(KERN_DEBUG "%s done\n", __FUNCTION__);
  160. return 0;
  161. fail_malloc:unregister_chrdev_region(dev,light_devp);
  162. return result;
  163. }
  164. void __exit light_cleanup(void)
  165. {
  166. cdev_del(&light_devp->cdev);
  167. kfree(light_devp);
  168. unregister_chrdev_region(MKDEV(light_major,0),1);
  169. }
  170. module_init(light_init);
  171. module_exit(light_cleanup);
  172. MODULE_AUTHOR("Enzo Fang");
  173. MODULE_LICENSE("Dual BSD/GPL");

结论:
使用
request_threaded_irq(gpio_irq.irq,gpio_irqhandler,gpio_threadhandler,gpio_irq.flags,gpio_irq.name,(void*)0);
hardirq和thread_fn同时出现时,处理thread_fn时该中断是打开的

err = request_threaded_irq(gpio_irq.irq,NULL,gpio_threadhandler,gpio_irq.flags,gpio_irq.name,(void*)0);
但hardirq和thread_fn只有一个存在时,处理thread_fn时,中断是关闭的

linux中断申请之request_threaded_irq 【转】的更多相关文章

  1. linux中断申请之request_threaded_irq

    转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=21977330&id=3755609 在linux里,中断处理分 ...

  2. linux中断申请之request_threaded_irq【转】

    转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=21977330&id=3755609 在linux里,中断处理分 ...

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

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

  4. Linux中断(interrupt)子系统之四:驱动程序接口层 & 中断通用逻辑层【转】

    转自:http://blog.csdn.net/droidphone/article/details/7497787 在本系列文章的第一篇:Linux中断(interrupt)子系统之一:中断系统基本 ...

  5. Linux中断(interrupt)子系统之一:中断系统基本原理【转】

    转自:http://blog.csdn.net/droidphone/article/details/7445825 这个中断系列文章主要针对移动设备中的Linux进行讨论,文中的例子基本都是基于AR ...

  6. Linux中断 - High level irq event handler

    一.前言 当外设触发一次中断后,一个大概的处理过程是: 1.具体CPU architecture相关的模块会进行现场保护,然后调用machine driver对应的中断处理handler 2.mach ...

  7. linux中断线程化分析【转】

    转自:http://blog.csdn.net/qq405180763/article/details/24120895 版权声明:本文为博主原创文章,未经博主允许不得转载. 最近在为3.8版本的Li ...

  8. Linux中断(interrupt)子系统之一:中断系统基本原理

    这个中断系列文章主要针对移动设备中的Linux进行讨论,文中的例子基本都是基于ARM这一体系架构,其他架构的原理其实也差不多,区别只是其中的硬件抽象层.内核版本基于3.3.虽然内核的版本不断地提升,不 ...

  9. Linux中断管理 (1)Linux中断管理机制【转】

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

随机推荐

  1. 每日一问(常用的集合接口和类有哪些【二】)—最常用的集合ArrayList类

    本人在曾经的数年编程生涯中,使用的最多的就是ArrayList类了,原因也非常简单.ArrayList类可以是最直接符合集合这一概念的类了,当然这种说法只是我的个人之见.ArrayList可以说是一个 ...

  2. Luogu4885 灭顶之灾

    显然1的位置确定了整个矩阵,每一段连续的数即是对该位置的限制.化一下式子可以发现是一段区间或一段区间的补集,最后要求的是他们的交.看起来不太好求,于是转为求补集的并,那么排个序就完了. #includ ...

  3. Intelligent Factorial Factorization LightOJ - 1035(水题)

    就是暴力嘛...很水的一个题... 不好意思交都... #include <iostream> #include <cstdio> #include <sstream&g ...

  4. 一些$LCT$的瓜皮题目

    一些瓜皮 放几个比较优(she)秀(pi)的\(LCT\)题. 老惯例,每一题代码因为一些未知原因消失了(如果要的话私我好了,虽然会咕咕咕). 嘴巴\(AC\)真香! [SP16580] QTREE7 ...

  5. 【agc006f】Blackout(神仙题)

    [agc006f]Blackout(神仙题) 翻译 给定一个\(n*n\)的网格图,有些格子是黑色的.如果\((x,y),(y,z)\)都是黑色的,那么\((y,x)\)也会被染黑,求最终黑格子数量. ...

  6. BZOJ2525 [Poi2011]Dynamite 【二分 + 贪心】

    题目链接 BZOJ2525 题解 就是要求所有有炸弹的点到点燃点距离最大值最小 显然二分答案距离\(D\) 然后按深度排序,贪心点燃当前没覆盖的深度最深的点往上第\(D\)层的点 每覆盖一个点要标记其 ...

  7. 基于Java visualvm的可视化监控的使用

    1 Java visualVM可视化监控工具打开方式 ctrl + r 快捷键调出运行窗口,输出 jvisualvm指令,即可打开java visualVM工具.详情如下图: 2 Java Visua ...

  8. vi的一些使用技巧

    1.vi 编辑器中跳到文件的第一行:键盘按下 小写 gg   vi 编辑器跳到文件最后一行:键盘按 shift + g (等于G) 跳转到当前行的第一个字符按0,跳转到当前行的最后一个字符按shift ...

  9. bzoj 2055 80人环游世界

    有源汇上下界最小费用可行流. 将每个国家拆点. 源点向一个新建节点连一条上界为总人数下界为0费用为0的边. 新建节点向每个国家的入点连一条上界为正无穷下界为0费用为0的边. 每个国家的入点向出点连一条 ...

  10. .Net并行编程系列之三:创建带时间限制(Timeout)的异步任务并取得异步任务的结果

    尝试创建基于MVVM三层架构的异步任务: 场景:View层触发ViewModel层的动作请求,ViewModel层异步的从Model层查询数据,当数据返回或者请求超时时正确更新ViewModel层数据 ...