澄清request_threaded_irq的行为

时间:2013-03-20 14:48:45

标签: multithreading linux-kernel linux-device-driver

我已经浏览了网页,但是对于“request_threaded_irq”功能,我没有找到有关我的几个相关问题的令人信服的答案。

问题1: 首先,我正在阅读这篇关于线程IRQ的文章:

http://lwn.net/Articles/302043/

这一行我不清楚:

“将中断转换为线程只在处理程序时才有意义  代码通过集成tasklet / softirq来利用它  功能和简化锁定。“

我知道如果我们采用“传统”,上半部/下半部分方法,我们需要自旋锁或禁用本地IRQ来干扰共享数据。但是,我不明白的是,线程中断如何通过集成tasklet / softirq功能来简化锁定需求。

问题2: 其次,request_threaded_handler方法对基于work_queue的下半部方法有什么好处(如果有的话)?在这两种情况下,好像“工作”被推迟到专用线程。那么,有什么区别?

问题3: 最后,在以下原型中:

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)

IRQ的“处理程序”部分是否可能由相关的IRQ连续触发(即UART以高速率接收字符),即使是“thread_fn”(将rx'd字节写入循环缓冲区) )部分中断处理程序正在忙于处理之前唤醒的IRQ?那么,处理程序不会试图“唤醒”已经运行的“thread_fn”吗?在这种情况下,运行irq thread_fn的行为如何?

如果有人能帮我理解,我真的很感激。

谢谢,  VJ

4 个答案:

答案 0 :(得分:2)

  1. 以前,下半部分不是task而是could not block。唯一的区别是中断被禁用。 tasklet softirq 允许驱动程序的 ISR线程与用户API(ioctl(),{{1}之间的不同互锁}和read())。
  2. 我认为write()几乎相同。但是, tasklet / ksoftirq 具有高优先级,并由该处理器上的所有基于ISR的功能使用。这可以提供更好的调度机会。此外,驾驶员管理的次数较少;一切都已经内置到内核的ISR处理程序代码中。
  3. 你必须处理这件事。通常可以使用ping-pong缓冲区或者像您建议的work queuekfifo应该是贪婪的并且在返回handler之前从UART获取所有数据。

答案 1 :(得分:2)

对于第3个问题, 当threadirq被激活时,相应的中断线被屏蔽/禁用。当threadedirq运行并完成时,它将使其朝向它的末端。因此,当相应的threadedirq运行时,不会有任何中断触发。

答案 2 :(得分:2)

对于问题2, 与工作队列不同,创建时的IRQ线程具有更高的优先级。 在kernel/irq/manage.c中,您将看到一些代码,如下所示,用于为线程IRQ创建内核线程:

            static const struct sched_param param = {
                    .sched_priority = MAX_USER_RT_PRIO/2,
            };


            t = kthread_create(irq_thread, new, "irq/%d-%s", irq,
                               new->name);
            if (IS_ERR(t)) {
                    ret = PTR_ERR(t);
                    goto out_mput;
            }

            sched_setscheduler_nocheck(t, SCHED_FIFO, &param);

在这里可以看到,内核线程的调度策略设置为RT(SCHED_FIFO),线程的优先级设置为MAX_USER_RT_PRIO/2,高于常规进程。< / p>

问题3, 您描述的情况也可能在正常中断时发生。通常在内核中,在执行ISR时禁用中断。在执行ISR期间,字符可以继续填充设备的缓冲区,即使中断被禁用,设备也可以并且必须继续断言中断。

设备的工作是确保IRQ线保持有效,直到所有字符都被读取并且ISR完成任何处理。同样重要的是,中断是电平触发的,或者取决于设计是否由中断控制器锁存。

最后,设备/外围设备应具有足够大小的FIFO,以便以较低速率传送的字符不会因速度较慢的ISR而丢失。 ISR还应设计为在执行时尽可能多地读取字符。

一般来说,我所看到的是,控制器将具有一定大小X的FIFO,并且当FIFO被填充X/2时,它将触发将导致ISR的中断尽可能多地获取数据。 ISR尽可能读取,然后清除中断。同时,如果FIFO仍为X/2,则器件会保持中断线有效,导致ISR再次执行。

答案 3 :(得分:0)

转换&#34; hard&#34; /&#34; soft&#34;托马斯·格莱克纳(Thomas Gleixner&amp; Sons)负责处理线程处理程序。团队在构建PREEMPT_RT Linux(又称Linux-as-an-RTOS)项目时(它不是主线的一部分)。 要真正让Linux作为RTOS运行,我们不能容忍中断处理程序中断最关键的rt(app)线程的情况;但是我们怎样才能确保应用程序线程甚至覆盖中断?通过使(中断)线程化,可调度(SCHED_FIFO)并且具有比app线程更低的优先级(中断线程rtprio默认为50)。所以&#34; rt&#34; rtprio为60的SCHED_FIFO app线程将能够抢占&#34;抢占&#34; (足够接近它工作)甚至是一个中断线程。这应该回答你的问题。 2。

Wrt to Qs 3: 正如其他人所说,你的代码必须处理这种情况。 话虽如此,但请注意,使用线程处理程序的关键点是,您可以执行(可能)阻塞(休眠)的工作。如果你的下半部分&#34;工作保证是无阻碍的,必须快,pl使用传统风格&#39; top-half / bh&#39;处理程序。 我们怎么做?简单:不要使用request_threaded_irq()只调用request_irq() - 代码中的注释清楚地说明(wrt 3rd parameter):

* @thread_fn: Function called from the irq handler thread
*          If NULL, no irq thread is created"

或者,您可以将IRQF_NO_THREAD标志传递给request_irq。

(顺便说一句,使用cscope在3.14.23内核源代码树上快速检查显示,request_irq()被调用1502次[给我们非线程中断处理],request_threaded_irq()[ 线程中断]被明确调用204次。