linux中断申请之request_threaded_irq 【转】
转自: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 irq, irq_handler_t handler, irq_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, 直到线程函数执行完毕才会开启该中断
- IRQF_ONESHOT:Interrupt is not reenabled after the hardirq handler finished.
- Used by threaded interrupts which need to keep the irq line disabled until
- the threaded handler has been run. 这里linus在邮件列表里指明IRQF_ONESHOT 的原因
- Making the IRQF_ONESHOT explicit does two things:
- - it makes people who read the code *aware* of things
- - if/when you have irq conflicts and two drivers want to attach to
- the same interrupt, at least you can see directly from the source what
- flags they used (and again, not have to even *think* about it).
- IRQF_ONESHOT 与 IRQF_SHARED 不能同时使用
- 当多个设备共享中断时,由于IRQF_ONESHOT会关闭中断线程的中断,而线程一般执行时间会比较长,所以是不允许的
- 当hardirq函数为NULL时,必须声明IRQF_ONESHOT, 表示threadirq线程中关闭该中断,在某些情况下,这个标志会非常有用
- 例如:设备是低电平产生中断,而硬中断函数为NULL,如果不使用IRQF_ONESHOT,就会一直产生中断执行NULL函数,中断线程
- 得不到执行,声明IRQF_ONESHOT后,会执行完线程才使能该中断
点击(此处)折叠或打开
- /*
- * gpio_irqTest.c
- * PB27 receive this signal as IRQ and make the LED linking on PB17 turn on or turn off
- *
- */
- #include <linux/types.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/platform_device.h>
- #include <linux/cdev.h>
- #include <linux/ioctl.h>
- #include <linux/fs.h>
- #include <linux/gpio.h>
- #include <linux/delay.h>
- #include <linux/cdev.h>
- #include <linux/interrupt.h>
- #include <asm/io.h>
- #include <asm/io.h>
- #include <mach/gpio.h>
- #include <mach/hardware.h>
- #include <mach/board.h>
- #include <mach/gpio.h>
- #include <mach/at91_pio.h>
- #include <mach/at91_aic.h>
- #include <mach/at91_pmc.h>
- void led_on()
- {
- // at91_set_gpio_output(AT91_PIN_PB17,1);
- printk("led on\n");
- }
- void led_off()
- {
- // at91_set_gpio_output(AT91_PIN_PB17 ,0);
- printk("led off.\n");
- }
- struct light_dev *light_devp;
- int light_major = 200;
- struct light_dev
- {
- struct cdev cdev;
- unsigned char value;
- };
- static void io_init(void)
- {
- at91_set_GPIO_periph(AT91_PIN_PB27, 0);
- at91_set_gpio_input(AT91_PIN_PB27, 1);
- at91_set_deglitch(AT91_PIN_PB27, 1);
- }
- struct gpio_irq_desc
- {
- int pin;
- int irq;
- unsigned long flags;
- char *name;
- };
- static struct gpio_irq_desc gpio_irq={AT91_PIN_PB27, AT91_PIN_PB27,IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING|IRQF_ONESHOT,"PB27"};
- static irqreturn_t gpio_irqhandler(int irq, void *dev_id)
- {
- printk(KERN_INFO "In hard irq handler.\n");
- return IRQ_WAKE_THREAD;
- }
- static irqreturn_t gpio_threadhandler(int irq, void *dev_id)
- {
- int rst;
- rst = at91_get_gpio_value(gpio_irq.pin);
- printk(KERN_INFO "gpio stat: %d\n", rst);
- if(rst == 0){
- led_on();
- }else{
- led_off();
- }
- printk(KERN_INFO "sleep 3000ms\n");
- msleep(3000);
- printk(KERN_INFO "awake after sleep\n");
- return IRQ_HANDLED;
- }
- int light_open(struct inode *inode,struct file *filp)
- {
- int err;
- struct light_dev *dev;
- dev = container_of(inode->i_cdev,struct light_dev,cdev);
- filp->private_data = dev;
- printk(KERN_DEBUG "%s", __FUNCTION__);
- io_init();
- // err = request_threaded_irq(gpio_irq.irq,gpio_irqhandler,gpio_threadhandler,gpio_irq.flags,gpio_irq.name,(void*)0);
- err = request_threaded_irq(gpio_irq.irq,NULL,gpio_threadhandler,gpio_irq.flags,gpio_irq.name,(void*)0);
- if(err)
- {
- // free_irq(gpio_irq.irq,(void*)0);
- printk(KERN_DEBUG "request irq failed.\n");
- return -EBUSY;
- }
- return 0;
- }
- int light_release(struct inode *inode,struct file *filp)
- {
- free_irq(gpio_irq.irq,(void*)0);
- return 0;
- }
- int light_ioctl(struct inode *inode,struct file *filp,unsigned int cmd, unsigned long arg)
- {
- struct light_dev *dev = filp->private_data;
- switch(cmd)
- {
- case 0:
- at91_set_gpio_output(AT91_PIN_PB19,0);
- break;
- case 1:
- at91_set_gpio_output(AT91_PIN_PB19,1);
- led_off();
- break;
- default:
- return -ENOTTY;
- // break;
- }
- return 0;
- }
- struct file_operations light_fops =
- {
- .owner = THIS_MODULE,
- .open = light_open,
- .release = light_release,
- .unlocked_ioctl = light_ioctl,
- };
- static void light_setup_cdev(struct light_dev *dev,int index)
- {
- int err,devno = MKDEV(light_major,index);
- cdev_init(&dev->cdev,&light_fops);
- dev->cdev.owner = THIS_MODULE;
- dev->cdev.ops = &light_fops;
- err = cdev_add(&dev->cdev,devno,1);
- if(err)
- {
- printk(KERN_NOTICE "Error %d adding LED%d",err,index);
- }
- }
- int __init light_init(void)
- {
- int result;
- dev_t dev = MKDEV(light_major,0);
- if(light_major)
- {
- result = register_chrdev_region(dev,1,"gpio");
- }
- if(result < 0)
- {
- printk(KERN_DEBUG "%s: register char dev failed.\n", __FUNCTION__);
- return result;
- }
- light_devp = kmalloc(sizeof(struct light_dev),GFP_KERNEL);
- if(!light_devp)
- {
- result = - ENOMEM;
- goto fail_malloc;
- }
- memset(light_devp,0,sizeof(struct light_dev));
- light_setup_cdev(light_devp,0);
- printk(KERN_DEBUG "%s done\n", __FUNCTION__);
- return 0;
- fail_malloc:unregister_chrdev_region(dev,light_devp);
- return result;
- }
- void __exit light_cleanup(void)
- {
- cdev_del(&light_devp->cdev);
- kfree(light_devp);
- unregister_chrdev_region(MKDEV(light_major,0),1);
- }
- module_init(light_init);
- module_exit(light_cleanup);
- MODULE_AUTHOR("Enzo Fang");
- 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 【转】的更多相关文章
- linux中断申请之request_threaded_irq
转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=21977330&id=3755609 在linux里,中断处理分 ...
- linux中断申请之request_threaded_irq【转】
转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=21977330&id=3755609 在linux里,中断处理分 ...
- Linux中断管理 (1)Linux中断管理机制
目录: <Linux中断管理> <Linux中断管理 (1)Linux中断管理机制> <Linux中断管理 (2)软中断和tasklet> <Linux中断管 ...
- Linux中断(interrupt)子系统之四:驱动程序接口层 & 中断通用逻辑层【转】
转自:http://blog.csdn.net/droidphone/article/details/7497787 在本系列文章的第一篇:Linux中断(interrupt)子系统之一:中断系统基本 ...
- Linux中断(interrupt)子系统之一:中断系统基本原理【转】
转自:http://blog.csdn.net/droidphone/article/details/7445825 这个中断系列文章主要针对移动设备中的Linux进行讨论,文中的例子基本都是基于AR ...
- Linux中断 - High level irq event handler
一.前言 当外设触发一次中断后,一个大概的处理过程是: 1.具体CPU architecture相关的模块会进行现场保护,然后调用machine driver对应的中断处理handler 2.mach ...
- linux中断线程化分析【转】
转自:http://blog.csdn.net/qq405180763/article/details/24120895 版权声明:本文为博主原创文章,未经博主允许不得转载. 最近在为3.8版本的Li ...
- Linux中断(interrupt)子系统之一:中断系统基本原理
这个中断系列文章主要针对移动设备中的Linux进行讨论,文中的例子基本都是基于ARM这一体系架构,其他架构的原理其实也差不多,区别只是其中的硬件抽象层.内核版本基于3.3.虽然内核的版本不断地提升,不 ...
- Linux中断管理 (1)Linux中断管理机制【转】
转自:https://www.cnblogs.com/arnoldlu/p/8659981.html 目录: <Linux中断管理> <Linux中断管理 (1)Linux中断管理机 ...
随机推荐
- 每日一问(常用的集合接口和类有哪些【二】)—最常用的集合ArrayList类
本人在曾经的数年编程生涯中,使用的最多的就是ArrayList类了,原因也非常简单.ArrayList类可以是最直接符合集合这一概念的类了,当然这种说法只是我的个人之见.ArrayList可以说是一个 ...
- Luogu4885 灭顶之灾
显然1的位置确定了整个矩阵,每一段连续的数即是对该位置的限制.化一下式子可以发现是一段区间或一段区间的补集,最后要求的是他们的交.看起来不太好求,于是转为求补集的并,那么排个序就完了. #includ ...
- Intelligent Factorial Factorization LightOJ - 1035(水题)
就是暴力嘛...很水的一个题... 不好意思交都... #include <iostream> #include <cstdio> #include <sstream&g ...
- 一些$LCT$的瓜皮题目
一些瓜皮 放几个比较优(she)秀(pi)的\(LCT\)题. 老惯例,每一题代码因为一些未知原因消失了(如果要的话私我好了,虽然会咕咕咕). 嘴巴\(AC\)真香! [SP16580] QTREE7 ...
- 【agc006f】Blackout(神仙题)
[agc006f]Blackout(神仙题) 翻译 给定一个\(n*n\)的网格图,有些格子是黑色的.如果\((x,y),(y,z)\)都是黑色的,那么\((y,x)\)也会被染黑,求最终黑格子数量. ...
- BZOJ2525 [Poi2011]Dynamite 【二分 + 贪心】
题目链接 BZOJ2525 题解 就是要求所有有炸弹的点到点燃点距离最大值最小 显然二分答案距离\(D\) 然后按深度排序,贪心点燃当前没覆盖的深度最深的点往上第\(D\)层的点 每覆盖一个点要标记其 ...
- 基于Java visualvm的可视化监控的使用
1 Java visualVM可视化监控工具打开方式 ctrl + r 快捷键调出运行窗口,输出 jvisualvm指令,即可打开java visualVM工具.详情如下图: 2 Java Visua ...
- vi的一些使用技巧
1.vi 编辑器中跳到文件的第一行:键盘按下 小写 gg vi 编辑器跳到文件最后一行:键盘按 shift + g (等于G) 跳转到当前行的第一个字符按0,跳转到当前行的最后一个字符按shift ...
- bzoj 2055 80人环游世界
有源汇上下界最小费用可行流. 将每个国家拆点. 源点向一个新建节点连一条上界为总人数下界为0费用为0的边. 新建节点向每个国家的入点连一条上界为正无穷下界为0费用为0的边. 每个国家的入点向出点连一条 ...
- .Net并行编程系列之三:创建带时间限制(Timeout)的异步任务并取得异步任务的结果
尝试创建基于MVVM三层架构的异步任务: 场景:View层触发ViewModel层的动作请求,ViewModel层异步的从Model层查询数据,当数据返回或者请求超时时正确更新ViewModel层数据 ...