linux中断线程化分析【转】
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
linux中断线程化分析【转】
版权声明:本⽂为博主原创⽂章,未经博主允许不得转载。
最近在为3.8版本的内核打RT_PREEMPT补丁,并且优化系统实时性,这篇⽂章主要对RTlinux中中断线程化部分进⾏分析。我们知道在RT_PREEMPT补丁中之所以要将中断
线程化就是因为硬中断的实时性太⾼,会影响实时进程的实时性,所以需要将中断处理程序线程化并设置优先级,使中断处理线程的优先级⽐实时进程优先级低,从⽽提⾼系统
实时性。
⽹上看到⼀些⽹友说在2.6.25.8版本的内核,引⼊了中断线程化,具体是不是2.6.25.8版本开始引⼊中断线程化我没有去求证,因为版本⽐较⽼了改动很多,但据我的查证从
2.6.30开始内核引⼊request_threaded_irq函数,从这个版本开始可以通过在申请中断时为request_irq设置不同的参数决定是否线程化该中断。⽽在2.6.39版内核__setup_irq引⼊
irq_setup_forced_threading函数,开始可以通过# define
force_irqthreads(true)强制使中断线程化,那么从这个版本开始想实现中断线程化就已经变得很简单了,让force_irqthreads为真即可,所以在3.8版本的实时补丁中,正是这⼀段代码实现了中断的线程化:[plain]
1. #ifdef CONFIG_IRQ_FORCED_THREADING
2. -extern bool force_irqthreads;
3. +# ifndef CONFIG_PREEMPT_RT_BASE
4. + extern bool force_irqthreads;
5. +# else
6. +# define force_irqthreads (true)
7. +# endif
8. #else
9. -#define force_irqthreads (0)
10. +#define force_irqthreads (false)
11. #endif
下⾯我们开始正式介绍中断线程化是怎么实现的。
Linux内核常见申请中断的函数request_irq,在内核源码include/linux/interrupt.h头⽂件中可以看到request_irq仅包含return request_threaded_irq(irq, handler, NULL, flags, name,
dev);调⽤,request_threaded_irq函数在源码⽬录kernel/irq/manage.c⽂件中,下⾯通过分析manage.c中各个相关函数解读中断线程化的实现过程。
根据request_irq的调⽤,⾸先分析request_threaded_irq
[plain]
1. int request_threaded_irq(unsigned int irq, irq_handler_t handler,
2. irq_handler_t thread_fn, unsigned long irqflags,
3. const char *devname, void *dev_id)
4. {
5. struct irqaction *action;
6. struct irq_desc *desc;
7. int retval;
8.
9. /*
10. * Sanity-check: shared interrupts must pass in a real dev-ID,
11. * otherwise we'll have trouble later trying to figure out
12. * which interrupt is which (messes up the interrupt freeing
13. * logic etc).
14. */
15. if ((irqflags & IRQF_SHARED) && !dev_id) //共享中断必须有唯⼀确定的设备号,不然中断处理函数找不到发出中断请求的设备,注释写的很清楚
16. return -EINVAL;
17.
18. desc = irq_to_desc(irq);
19. if (!desc)
20. return -EINVAL;
21.
22. if (!irq_settings_can_request(desc) ||
23. WARN_ON(irq_settings_is_per_cpu_devid(desc)))
24. return -EINVAL;
25.
26. if (!handler) { //handler和thread_fn都没有指针传⼊肯定是出错了,有thread_fn⽆handler则将irq_default_primary_handler给handler
27. if (!thread_fn)
28. return -EINVAL;
29. handler = irq_default_primary_handler;
30. }
31.
32. action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
33. if (!action)
34. return -ENOMEM;
35.
36. action->handler = handler;
37. action->thread_fn = thread_fn;
38. action->flags = irqflags;
39. action->name = devname;
40. action->dev_id = dev_id;
41.
42. chip_bus_lock(desc);
43. retval = __setup_irq(irq, desc, action); //在__setup_irq中确定是否线程化并完成中断处理函数绑定
44. chip_bus_sync_unlock(desc);
45.
46. if (retval)
47. kfree(action);
48.
49. #ifdef CONFIG_DEBUG_SHIRQ_FIXME
50. if (!retval && (irqflags & IRQF_SHARED)) {
51. /*
52. * It's a shared IRQ -- the driver ought to be prepared for it
53. * to happen immediately, so let's make sure....
54. * We disable the irq to make sure that a 'real' IRQ doesn't
55. * run in parallel with our fake.
56. */
57. unsigned long flags;
58.
59. disable_irq(irq);
60. local_irq_save(flags);
61.
62. handler(irq, dev_id);
63.
64. local_irq_restore(flags);