日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux Kernel中断下半部分实现的三种方式

發布時間:2025/3/21 linux 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux Kernel中断下半部分实现的三种方式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

👉👉👉 個人博客筆記導讀目錄(全部) 👈👈👈
.
說明:
在默認情況下,本文講述的都是ARMV8-aarch64架構,linux kernel 5.14

目錄

        • 1、軟中斷
        • 2、tasklet
        • 3、工作隊列
        • 總結

目前有三種中斷的三種機制:

  • 軟中斷
  • tasklet
  • 工作隊列

1、軟中斷

軟中斷是一組靜態定義的下半部接口,有 32 個,可以在所有處理器上同時執行,類型相同也可以;在編譯時靜態注冊。
軟中斷的相關函數:

  • 注冊軟中斷 open_softirq
  • 觸發軟中斷 raise_softirq
  • 執行軟中斷 do_softirq

Linux Kernel中定義的軟中斷:

(linux/include/linux/interrupt.h)enum {HI_SOFTIRQ=0,TIMER_SOFTIRQ,NET_TX_SOFTIRQ,NET_RX_SOFTIRQ,BLOCK_SOFTIRQ,IRQ_POLL_SOFTIRQ,TASKLET_SOFTIRQ,SCHED_SOFTIRQ,HRTIMER_SOFTIRQ,RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */NR_SOFTIRQS };

軟中斷執行函數如下:

(linux/kernel/softirq.c)asmlinkage __visible void do_softirq(void){__u32 pending;unsigned long flags;if (in_interrupt())return;local_irq_save(flags);pending = local_softirq_pending();if (pending && !ksoftirqd_running(pending))do_softirq_own_stack();local_irq_restore(flags);}

代碼一上來就判斷是否在中斷處理中,如果在立刻退出函數。這說明如果有其他軟中斷觸發,則立即返回。所以,軟中斷不能被另外一個軟中斷搶占!唯一可以搶占軟中斷的是中斷處理程序,所以軟中斷允許響應中斷。雖然不能在本處理器上搶占,但是其他的軟中斷甚至同類型可以再其他處理器上同時執行。由于這點,所以對臨界區需要加鎖保護。

軟中斷給對時間要求最嚴格的下半部使用。目前只有網絡,內核定時器和 tasklet 建立在軟中斷上。

2、tasklet

Tasklet是建立在軟中斷之上的下半部機制,tasklet和軟中斷很類似,但是tasklet的接口更簡單,也不需要嚴格的鎖機制。因為tasklet是使用軟中斷來實現的,所以tasklet本身就是軟中斷。

tasklet使用兩種軟中斷來實現:HI_SOFTIRQ和TASKLET_SOFTIRQ。兩者的唯一區別在于優先級,前者優先級更高,總是先于后者執行。

tasklet使用tasklet_struct結構來表示,每個結構體表示一個唯一的tasklet,定義在<linux/interrupt.h>中

(linux/include/linux/interrupt.h)struct tasklet_struct {struct tasklet_struct *next;unsigned long state;atomic_t count;bool use_callback;union {void (*func)(unsigned long data);void (*callback)(struct tasklet_struct *t);};unsigned long data; };

Tasklet的使用:

(1)、聲明一個新的tasklet

struct tasklet_struct my_tasklet = { NULL, 0, ATOMIC_INIT(0), my_tasklet_handler, dev };

或者

tasklet_init(t, tasklet_handler, dev); /* dynamically as opposed to statically */

(2)、tasklet的處理程序

void tasklet_handler(unsigned long data)

注意:和軟中斷類似,tasklet不能睡眠(阻塞),因為軟中斷是運行在中斷上下文中的,而tasklet是使用軟中斷來實現的。

(3)、tasklet的調度
使用tasklet_schedule()進行調度(類似軟中斷的觸發),傳入參數為指向tasklet_struct的指針。tasklet被調度后,內核會在合適的時機執行該taskelt。(詳見前面的tasklet調度的實現)。如果一個tasklet在執行前被調度了多次,還是只會執行一次(tasklet鏈表中不會有重復的tasklet)。如果一個tasklet在運行中被調度了(比如被另一個處理器上執行的代碼調度了),那么這個tasklet會被重新調度并在下次內核處理tasklet的時候再次執行。

3、工作隊列

工作隊列是和軟中斷或者tasklet不同的一種下半部機制。工作隊列將工作推遲,交給內核線程執行(所以工作隊列總是運行在進程上下文中)。工作隊列的這種實現可以很好的利用進程上下文的優勢,最重要的就是可以睡眠也可以被調度(搶占)。與之相反的是,軟中斷和tasklet是不能睡眠和被調度的。

可以自己創建工作隊列,但是大部分驅動都會使用系統提供的缺省的工作隊列類型events,該類型的工作隊列的內核線程名字為 events/n,n為處理器編號,每個處理器對應一個內核線程。如果下半部的工作是處理器密集型并且對性能敏感的,可以考慮創建自己的內核線程。比如XFS文件系統就自己創建了兩種內核線程。

工作隊列的使用:–(缺省工作隊列events)

(1)、創建工作(Creaing Work)

DECLARE_WORK(name, void (*func)(void *), void *data); //靜態 INIT_WORK(struct work_struct *work, void (*func)(void *), void *data); //動態

(2)、定義工作隊列處理函數

void work_handler(void *data)

(3)、對工作(work)進行調度

內核提供了兩個函數對使用缺省工作隊列events的工作進行調度

schedule_work(&work); schedule_delayed_work(&work, delay);
  • schedule_work()會立刻對工作(work)進行調度,一旦其所在的處理器上的events內核線程被喚醒,該工作就會被執行。
  • schedule_delayed_work()會延后一定數量的(由dealy指定)的timer tick后再進行調度。

創建自己的內核線程工作隊列

(1)、創建內核線程工作隊列
如果需要利用單獨的內核線程的(不用events的內核線程)的性能優勢,可以通過函數struct workqueue_struct *create_workqueue(const char *name)創建一個新的工作隊列,參數是工作隊列的名字。比如缺省的events工作隊列的創建:

struct workqueue_struct *keventd_wq; keventd_wq = create_workqueue(“events”);

這個函數會創建所有的內核線程(每個處理器一個),并且做些準備好讓這些內核線程可以處理工作

(2)、工作隊列調度

int queue_work(struct workqueue_struct *wq, struct work_struct *work) int queue_delayed_work(struct workqueue_struct *wq,struct work_struct *work,unsigned long delay)

總結

下半部上下文說明
軟中斷中斷上下文不能睡眠、不能被搶占
tasklet中斷上下文不能睡眠、不能搶占、同類型tasklet不能并行
工作隊列進程上下文可以睡眠、可以被搶占

總結

以上是生活随笔為你收集整理的Linux Kernel中断下半部分实现的三种方式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。