首頁  >  文章  >  運維  >  Linux驅動中斷下半部的三種方法

Linux驅動中斷下半部的三種方法

嵌入式Linux充电站
嵌入式Linux充电站轉載
2023-07-31 14:57:18965瀏覽

什麼是中斷下半部

當產生中斷時,會進入中斷處理程序。

中斷處理程序必須快速、非同步、簡單的對硬體做出迅速回應並完成那些時間要求很嚴格的操作。

因此,對於那些其他的、對時間要求相對寬鬆的任務,就應該推後到中斷被激活以後再去運行

這樣,整個中斷處理流程就被分成了兩個部分

  • 第一個部分是中斷處理程序(上半部),核心透過對它的非同步執行完成對硬體中斷的即時回應。
  • 中斷處理流程中的另外一部分,下半部(bottom half)

下半部的任務主要是執行與中斷相關的工作,這些工作並沒有被中斷服務程序本身完成

Linux驅動中斷下半部的三種方法

下半部並不需要指明一個確切時間,只要把這些任務推遲一點,讓它們在系統不太繁忙並且中斷恢復後執行就可以了。

上半部與下半部的主要差異

  • 上半部指的是中斷處理程序下半部則指的是一些雖然與中斷有相關性但是可以延後執行的任務。

  • 上半部中斷不能被相同類型的中斷打斷,而下半部依然​​可以被中斷打斷

  • 通常下半部在中斷處理程序一回就會馬上運作。

  • 上半部簡單快速,執行的時候禁止一些或全部中斷。

  • 下半部稍後執行,而且執行期間可以回應所有的中斷。

Linux中,中斷下半部的實作主要有三種:

  • 軟體中斷
  • tasklet
  • #工作佇列

##softirq

#softirq即軟體中斷,程式碼位於kernel/softirq.c檔案中;

每個軟體中斷由

softirq_action結構表示:

Linux驅動中斷下半部的三種方法

softirq.c中定義了一個軟中斷向量陣列softirq_vec

static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp;  
    enum  
    {  
       HI_SOFTIRQ=0, /*用于高优先级的tasklet*/  
       TIMER_SOFTIRQ, /*用于定时器的下半部*/  
       NET_TX_SOFTIRQ, /*用于网络层发包*/  
       NET_RX_SOFTIRQ, /*用于网络层收报*/  
       BLOCK_SOFTIRQ,  
       BLOCK_IOPOLL_SOFTIRQ,  
       TASKLET_SOFTIRQ, /*用于低优先级的tasklet*/  
       SCHED_SOFTIRQ,  
       HRTIMER_SOFTIRQ,  
       RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */  
       NR_SOFTIRQS  
   };

陣列的成員數由

NR_SOFTIRQS決定,是一個列舉常數。

新增一個軟體中斷時,需要在檔案

include/linux/interrupt.h 中加入一個列舉常數。

軟體中斷使用的幾個要點

  • 一个软中断不会抢占另外一个软中断。
  • 惟一可以抢占软中断的是中断处理程序。
  • 其他的软中断可以在其他处理器上同时执行。

相关接口

  • 注册软中断
void open_softirq(int nr, void (*action)(struct softirq_action *))

即注册对应类型的处理函数到全局数组softirq_vec中。

  • 触发软中断
void raise_softirq(unsigned int nr)

实际上即以软中断类型nr作为偏移量会置位irq_stat[cpu_id]的成员变量__softirq_pending.

__softirq_pending字段中的每一个bit,对应着某一个软中断,某个bit被置位,说明有相应的软中断等待处理。

这也是同一类型软中断可以在多个cpu上并行运行的根本原因。

软中断实例

以一个按键驱动的中断处理为例,将按键驱动的中断处理分成上下两部分:

  • 上半部:讀取鍵值,觸發軟中斷
  • 下半部:喚醒程序
Linux驅動中斷下半部的三種方法

軟中斷的註冊,在驅動的入口函數,註冊軟中斷:

Linux驅動中斷下半部的三種方法

新增的列舉常數:

Linux驅動中斷下半部的三種方法

可以看到,使用軟中斷是需要修改內核,增加一個列舉的,有些繁瑣。

所以,通常我們不建議擅自增加軟中斷的數量,如果需要新的軟中斷,盡可能把它們實現為基於軟中斷的tasklet形式。

tasklet

#tasklet是利用軟體中斷實作的一種下半部機制

那是用軟中斷還是tasklet好呢?

選擇到底是用軟體中斷還是tasklet其實很簡單:

  • 通常你应该用tasklet就像我们在前面看到的,软中断资源有限,也麻烦,而且软中断的使用者屈指可数。它只在那些执行频率很高和连续性要求很高的情况下才需要。
  • tasklet却有更广泛的用途。大多数情况下用tasklet效果都不错,而且它们还非常容易使用。
  • 因为tasklet是通过软中断实现的,所以它们本身也是软中断

tasklet使用

tasklet的使用步骤如下:

1、编写tasklet处理函数(下半部

void my_tasklet_fun (unsigned long data)

2、声明tasklet

//静态 
DECLARE_TASKLET(my_tasklet,my_tasklet_fun,data); 
//动态
Struct  tasklet_struct xxx;
tasklet_init(&xxx,tasklet_handler,dev)

3、调度 tasklet

tasklet_schedule(&my_tasklet);

登记my_tasklet, 然后允许系统在合适的时间调度它。

tasklet实例

以按键中断驱动为例:

Linux驅動中斷下半部的三種方法

先使用DECLARE_TASKLET靜態宣告一個tasklet,指定其下半部函數為btn_tasklet_func,在中斷服務函數(上半部)取得按鍵值後,呼叫tasklet_schedule調度。

work queue

#work queue工作佇列,也是中斷下半部的一種。

Work queue將下半部工作延後給一個核心執行緒去執行-work 總是運行於進程上下文.

兩個要點

  • 如果延遲的工作需要睡眠,則使用work queues。否則使用softirqtasklets.
  • #Work queues適用於需要分配大量的內存,以獲得一個信號量,或執行阻塞的I/O的情況.

工作佇列的相關介面函數:

Linux驅動中斷下半部的三種方法

在使用上,工作佇列tasklet是類似的:

Linux驅動中斷下半部的三種方法

#

以上是Linux驅動中斷下半部的三種方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:嵌入式Linux充电站。如有侵權,請聯絡admin@php.cn刪除