6

我已经在网上搜索过,但是对于我遇到的几个相关问题,关于“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

4 回答 4

5

对于问题 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 one ( SCHED_FIFO),并且线程的优先级设置MAX_USER_RT_PRIO/2为高于常规进程。

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

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

最后,设备/外设应具有足够大小的 FIFO,以便高速传输的字符不会被慢 ISR 丢失。ISR 还应设计为在执行时读取尽可能多的字符。

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

于 2014-05-18T02:42:52.790 回答
2

对于第 3 个问题,当一个 threadedirq 被激活时,相应的中断线被屏蔽/禁用。当 threadedirq 运行并完成时,它会在它的末尾启用它。因此,当相应的 threadedirq 运行时,不会有任何中断触发。

于 2013-10-29T05:42:03.590 回答
2
  1. 以前,下半部不是 a task,仍然无法阻挡。唯一的区别是中断被禁用。taskletsoftirq允许在驱动程序的ISR 线程和用户 API(ioctl()read()write())之间进行不同的互锁。
  2. 我认为这work queue几乎是等价的。但是,tasklet/ksoftirq具有高优先级,并被该处理器上所有基于 ISR 的功能使用。这可以提供更好的调度机会。此外,驱动程序管理的更少;一切都已内置到内核的 ISR 处理程序代码中。
  3. 你必须处理这个。通常可以使用乒乓kfifo缓冲区或像您建议的那样。应该是贪婪的handler,并在返回之前从 UART 获取所有数据IRQ_WAKE_THREAD
于 2013-03-20T18:08:48.973 回答
1

将“硬”/“软”处理程序转换为线程处理程序的最初工作是由 Thomas Gleixner 和团队在构建PREEMPT_RT Linux(又名 Linux-as-an-RTOS)项目时完成的(它不是主线的一部分)。要真正让 Linux 作为 RTOS 运行,我们不能容忍中断处理程序中断最关键的 rt (app) 线程的情况;但是我们如何确保应用程序线程甚至覆盖中断?通过使其(中断)线程化、可调度(SCHED_FIFO)并具有低于应用程序线程的优先级(中断线程 rtprio 默认为 50)。因此,rtprio 为 60 的“rt”SCHED_FIFO 应用程序线程即使是中断线程也能够“抢占”(足够接近它可以工作)。那应该回答你的问题。2.

Wrt to Qs 3:正如其他人所说,您的代码必须处理这种情况。话虽如此,请注意使用线程处理程序的关键点是,您可以执行(可能)阻塞(睡眠)的工作。如果您的“下半部分”工作保证是非阻塞的并且必须快速,请使用传统风格的“上半部分/bh”处理程序。我们怎么能做到这一点?简单:不要使用 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。

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

于 2015-03-25T08:10:53.547 回答