2012年9月19日 星期三

Linux request_threaded_irq() 與 request_irq() 差異

一開始看到有 driver 用 request_threaded_irq() 以為是 request_irq() 誤植,Google 查詢後才知道是 Linux kernel 2.6.30 之後新加的 irq handler API

如何確定可以用到 request_threaded_irq() ?

Linux kernel config 需要定義 CONFIG_GENERIC_HARDIQS kernel config 才有支援  threaded irq

原因是在 include/linux/interrupt.h

#ifdef CONFIG_GENERIC_HARDIRQS

函式定義位置在:
    ~linux/kernel/irq/manage.c

1306 int request_threaded_irq(unsigned int irq, irq_handler_t handler,
1307              irq_handler_t thread_fn, unsigned long irqflags,
1308              const char *devname, void *dev_id)

    request_threaded_irq:   kernel thread context ist
    request_irq:    direct function call from hardware IRQ isr

Moving interrupts to threads 介紹 request_threaded_irq() 的由來,從 realtime tree 移植而來,為了減少 kernel 因為要等每一個硬體中斷處理的時間,就另外交給 kernel thread 處理中斷後續處理。

優點:

  1. 減少 kernel 延遲時間
  2. 避免處理中斷時要分辨是在硬體中斷或軟體中斷?
  3. 更容易為 kernel 中斷處理除錯,可能可完全取代 tasklet

   
原本的中斷處理分上半部(硬體中斷處理,必須關閉中斷無法處理新的中斷)跟下半部(軟體中斷處理),因此上半部的硬體中斷處理必須盡可能簡短,讓系統反應速度更快。

request_threaded_irq 是在將上半部的硬體中斷處理更加縮短為,只確定硬體中斷來自我們要處理的裝置,喚醒 kernel thread 執行後續中斷處理。只有將 tasklet 跟 softirq 處理都放到 threaded_irq 的 kernel thread 中,才能發揮最大的系統效能增益。

原本在 reuqest_irq 的 handler 變成快速檢查用的 handler function,

缺點:

對於非處理 irq 中斷的 kernel threads ,需要在原本 task_struct 新增 struct irqaction 多佔 4/8 bytes 記憶體空間,linux kernel 2.6.29 之後(2.6.30)加入 request_threaded_irq

    nested top halves?

jlokier 在回覆 Moving interrupts to threads 補充:跟傳統 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 連結與溝通的麻煩。