Multithreading 关于请求\u线程\u irq行为的澄清

Multithreading 关于请求\u线程\u irq行为的澄清,multithreading,linux-kernel,linux-device-driver,Multithreading,Linux Kernel,Linux Device Driver,我在网上搜索了一下,但对于一些与“请求线程化”功能相关的问题,还没有找到令人信服的答案 问题1: 首先,我在读这篇关于线程IRQ的文章: 有一句话我不清楚: “只有当处理程序 代码通过集成tasklet/softirq来利用它 功能和简化锁定。” 我知道如果我们采用“传统”的上半部分/下半部分方法,我们可能需要自旋锁或禁用本地IRQ来处理共享数据。但是,我不明白的是,线程中断如何通过集成tasklet/softirq功能来简化锁定需求 问题2: 其次,与基于工作队列的下半部分方法相比,请求线程

我在网上搜索了一下,但对于一些与“请求线程化”功能相关的问题,还没有找到令人信服的答案

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

有一句话我不清楚:

“只有当处理程序 代码通过集成tasklet/softirq来利用它 功能和简化锁定。”

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

问题2: 其次,与基于工作队列的下半部分方法相比,请求线程处理方法有什么优势(如果有的话)?在这两种情况下,似乎“工作”被推迟到一个专用线程。那么,有什么区别呢

问题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)
即使中断处理程序的“线程”部分(将rx字节写入循环缓冲区)正忙于处理来自先前唤醒的IRQ,IRQ的“处理程序”部分是否可能由相关IRQ(比如UART以高速率接收字符)连续触发?那么,处理程序是否会试图“唤醒”已经运行的“线程”_fn?在这种情况下,正在运行的irq线程将如何运行

如果有人能帮我理解这一点,我将不胜感激

谢谢, vj

  • 以前,下半部分不是
    任务
    ,仍然是。唯一的区别是中断被禁用。tasklet或softirq允许驱动程序的ISR线程和用户API之间存在不同的互锁(
    ioctl()
    read()
    ,和
    write()
  • 我认为
    工作队列
    几乎相当。但是,tasklet/ksoftirq具有较高的优先级,并由该处理器上所有基于ISR的功能使用。这可能会提供更好的调度机会。此外,驾驶员需要管理的资源更少;所有内容都已内置到内核的ISR处理程序代码中
  • 你必须处理好这件事。通常可以使用缓冲区,也可以像您建议的那样使用
    kfifo
    处理程序应该是贪婪的,在返回
    IRQ\u WAKE\u线程之前从UART获取所有数据
  • 关于第三个问题, 当ThreadeDRQ被激活时,相应的中断线被屏蔽/禁用。当threadedirq运行并完成时,它将在接近结束时启用它。因此,当相应的threadedirq运行时,不会有任何中断触发。

    对于问题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\u RT_PRIO/2
    ,高于常规进程

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

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

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


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

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

    对Qs 3的说明: 正如其他人所说,您的代码必须处理这种情况。 话虽如此,pl注意到使用线程处理程序的一个关键点是,您可以(可能)执行阻塞(休眠)的工作。如果您的“下半部分”工作保证是非阻塞的并且必须是快速的,则pl使用传统风格的“上半部分/bh”处理程序。 我们怎么能做到呢?简单:不要使用request\u-threaded\u-irq(),只需调用request\u-irq()-代码中的注释清楚地说明(wrt第三个参数):

    或者,您可以将IRQF_NO_线程标志传递给request_irq

    (顺便说一句,在3.14.23 k上与cscope进行快速检查
    * @thread_fn: Function called from the irq handler thread
    *          If NULL, no irq thread is created"