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

歡迎訪問 生活随笔!

生活随笔

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

linux

(笔记)Linux内核学习(五)之中断推后处理机制

發布時間:2025/4/16 linux 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 (笔记)Linux内核学习(五)之中断推后处理机制 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一 中斷

?????? 硬件通過中斷與操作系統進行通信,通過對硬件驅動程序處注冊中斷處理程序,快速響應硬件的中斷。

硬件中斷優先級很高,打斷當前正在執行的程序。有兩種情況:

  硬件中斷在中斷處理程序中處理

  硬件中斷延后再進行處理

  這個具體硬件相關,在中斷處理程序中處理,打斷了當前正在執行的程序;所有中斷都將被屏蔽;如果占用時間太長不合適,

造成系統交互性,反應能力都會受到影響。 需要在其中判斷平衡:

?????? 如果一個任務對時間非常敏感,將其放在中斷處理程序中執行;

?????? 如果一個人和和硬件相關,將其放在中斷處理程序中執行;

?????? 如果一個任務要保證不被其他中斷打斷,將其放在中斷處理程序中執行;

?????? 其余情況考慮延后機制中執行——下半部。

二 中斷推后執行機制—— 軟中斷

?????? 軟中斷是在編譯期間靜態分配的,在程序執行前將軟中斷假如到表中。

下面看一下這個過程:

加入軟中斷類型:

?????? Linux3.5.3代碼:

enum {HI_SOFTIRQ=0,TIMER_SOFTIRQ,NET_TX_SOFTIRQ,NET_RX_SOFTIRQ,BLOCK_SOFTIRQ,BLOCK_IOPOLL_SOFTIRQ,TASKLET_SOFTIRQ,SCHED_SOFTIRQ,HRTIMER_SOFTIRQ,RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */NR_SOFTIRQS};

?

?

?

?

//軟中斷表:

static struct?softirq_action?softirq_vec[NR_SOFTIRQS]

//軟中斷結構體

struct softirq_action {void (*action)(struct softirq_action *); };

?

?

注冊軟中斷處理函數:

void open_softirq(int nr, void (*action)(struct softirq_action *)) {//關聯表中對應類型softirq_vec[nr].action = action; }

?

?

?

?

觸發軟中斷:? ? ?

void raise_softirq(unsigned int nr) {unsigned long flags;//停止但保存中斷標志local_irq_save(flags);//將相應軟中斷掛起狀態raise_softirq_irqoff(nr);//恢復中斷local_irq_restore(flags); }

?

?

?

?

執行軟中斷:? ?

void irq_exit(void) { invoke_softirq(); //do_softirq(); }void __do_softirq(void) {struct softirq_action *h;__u32 pending;int max_restart = MAX_SOFTIRQ_RESTART;int cpu;//獲取CPU軟中斷狀態標志位 32位代表最多32個軟中斷pending = local_softirq_pending();restart:/* Reset the pending bitmask before enabling irqs */set_softirq_pending(0);local_irq_enable();h = softirq_vec;do {//被觸發則執行軟中斷處理程序if (pending & 1) {h->action(h);}//下一個軟中斷h++;//下一個軟中斷狀態標志位pending >>= 1;} while (pending);local_irq_disable();pending = local_softirq_pending();if (pending && --max_restart)goto restart;if (pending)wakeup_softirqd();lockdep_softirq_exit();__local_bh_enable(SOFTIRQ_OFFSET); }

?

?

?

軟中斷的基本結構如下圖表示:

??????

    

?

?

三 ?中斷推后執行機制——tasklet

?????? 軟中斷中表中有一種類型是:TASKLET_SOFTIRQ

Tasklet就是利用軟中斷實現中斷推后處理機制。通常使用較多的是tasklet而不是軟中斷。

Tasklet數據結構:???

struct tasklet_struct {//鏈表中下一個taskletstruct tasklet_struct *next;//tasklet狀態unsigned long state;//引用計數器atomic_t count;//tasklet處理函數void (*func)(unsigned long);//處理函數參數unsigned long data;};

?

?

?

state:

enum {TASKLET_STATE_SCHED, /* Tasklet is scheduled for execution */TASKLET_STATE_RUN /* Tasklet is running (SMP only) */ };

?

?

?

count:為0允許激活執行

聲明tasklet:可以動態或者靜態方式

?????? 靜態:

#define DECLARE_TASKLET(name, func, data) \ struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }#define DECLARE_TASKLET_DISABLED(name, func, data) \ struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(1), func, data }

?

?????? 動態:? ??

void tasklet_init(struct tasklet_struct *t,void (*func)(unsigned long), unsigned long data) {t->next = NULL;t->state = 0;atomic_set(&t->count, 0);t->func = func;t->data = data; }

?

?

?

  同時需要編寫tasklet處理函數。

調度tasklet:

? ? ? ?

void tasklet_hi_schedule(struct tasklet_struct *t) {unsigned long flags;local_irq_save(flags);t->next = NULL;*__this_cpu_read(tasklet_vec.tail) = t;__this_cpu_write(tasklet_vec.tail, &(t->next));raise_softirq_irqoff(TASKLET_SOFTIRQ);local_irq_restore(flags); }

?

?

?

執行tasklet處理程序:

?????? 繼續看上面調度tasklet程序執行:

? ? ??

inline void raise_softirq_irqoff(unsigned int nr) {__raise_softirq_irqoff(nr);if (!in_interrupt())wakeup_softirqd(); }//使用ksoftirqd內核線程來處理 static void wakeup_softirqd(void) {/* Interrupts are disabled: no need to stop preemption */struct task_struct *tsk = __this_cpu_read(ksoftirqd);if (tsk && tsk->state != TASK_RUNNING)wake_up_process(tsk); }

?

?

?

Ksoftirqd內核線程:

?????? 軟中斷才被觸發頻率很高,在處理過程中還會重新觸發軟中斷;執行會導致用戶空間進程無法獲得處理時間處于饑餓狀態;

對重新觸發的軟中斷立即處理,會導致占據處理時間過長;不進行立即處理不合適;

對此解決方法:

  l? 只要還有被觸發并等待處理和過程中重新觸發的軟中斷的軟中斷,本次執行就要負責處理;軟中斷立即處理,用戶空間得不到執行時間。

  l? 不處理過程中觸發的軟中斷,放到下一個中斷執行時機時處理。軟中斷得不到立即處理,系統空閑時造成不合理;保證用戶空間得到執行時間。

兩種方式有存在問題,只能在這其中采取這種的方式:

?????? 內核使用線程處理軟中斷,線程優先級較低,可以被搶占;能夠保證軟中斷被處理,也能保證用戶空間程序得到執行時間。

?????? 每個CPU上有存在這樣一個線程:ksoftirqd/0或者ksoftirqd/1……

static __init int spawn_ksoftirqd(void) {void *cpu = (void *)(long)smp_processor_id();int err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);……return 0; }early_initcall(spawn_ksoftirqd); static int __cpuinit cpu_callback(struct notifier_block *nfb,unsigned long action,void *hcpu) {int hotcpu = (unsigned long)hcpu;struct task_struct *p;switch (action) {case CPU_UP_PREPARE:case CPU_UP_PREPARE_FROZEN:p = kthread_create_on_node(run_ksoftirqd,hcpu,cpu_to_node(hotcpu),"ksoftirqd/%d", hotcpu);kthread_bind(p, hotcpu);per_cpu(ksoftirqd, hotcpu) = p;break;…… }

?

?

四 中斷推后執行機制——工作隊列

?????? 工作隊列(work queue)通過內核線程將中斷下半部分程序推后執行到線程中執行,工作隊列可以創建線程來處理相應任務。

?????? 工作隊列創建的線程為工作者線程:worker thread;系統提供默認的線程來處理工作者隊列。

? ? ??  

      

?

工作者線程數據結構:

? ? ? ?

struct workqueue_struct {unsigned int flags; /* W: WQ_* flags */union {struct cpu_workqueue_struct __percpu *pcpu;struct cpu_workqueue_struct *single;unsigned long v;} cpu_wq; /* I: cwq's */struct list_head list; /* W: list of all workqueues */…… }

?

?

?

CPU工作隊列數據結構:

struct cpu_workqueue_struct {
//每個CPU工作隊列信息struct global_cwq *gcwq;
//每個CPU工作隊列struct workqueue_struct *wq; …… };

?

工作數據結構:

struct work_struct {atomic_long_t data;struct list_head entry;work_func_t func;};

?

聲明工作隊列:

?????? 靜態:

#define DECLARE_WORK(n, f) \struct work_struct n = __WORK_INITIALIZER(n, f)

?

?

?

?????? 動態:

#define INIT_WORK(_work, _func) \do { \__INIT_WORK((_work), (_func), 0); \} while (0)??

???????需要編寫工作隊列處理函數:? ? ? ?

typedef void (*work_func_t)(struct work_struct *work);

?

?

?

調度工作隊列:

int schedule_work(struct work_struct *work) {return queue_work(system_wq, work); } int queue_work(struct workqueue_struct *wq, struct work_struct *work) {ret = queue_work_on(get_cpu(), wq, work); }

?

?

?

?????? 喚醒工作者隊列線程處理。

執行工作者隊列處理程序:

? ? ? ?

static int worker_thread(void *__worker) {do {struct work_struct *work =list_first_entry(&gcwq->worklist,struct work_struct, entry);process_one_work(worker, work);} while (keep_working(gcwq));}

?

?

?

可以創建新的工作者隊列和線程來處理。

平衡是個很關鍵的問題!

總結

以上是生活随笔為你收集整理的(笔记)Linux内核学习(五)之中断推后处理机制的全部內容,希望文章能夠幫你解決所遇到的問題。

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