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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

[Linux内核]软中断与硬中断

發布時間:2023/11/27 生活经验 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [Linux内核]软中断与硬中断 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉自:http://blog.csdn.net/zhangskd/article/details/21992933

本文主要內容:硬中斷 / 軟中斷的原理和實現

內核版本:2.6.37

Author:zhangskd @ csdn blog

?

概述

?

從本質上來講,中斷是一種電信號,當設備有某種事件發生時,它就會產生中斷,通過總線把電信號發送給中斷控制器。

如果中斷的線是激活的,中斷控制器就把電信號發送給處理器的某個特定引腳。處理器于是立即停止自己正在做的事,

跳到中斷處理程序的入口點,進行中斷處理。

?

(1) 硬中斷

由與系統相連的外設(比如網卡、硬盤)自動產生的。主要是用來通知操作系統系統外設狀態的變化。比如當網卡收到數據包

的時候,就會發出一個中斷。我們通常所說的中斷指的是硬中斷(hardirq)。

?

(2) 軟中斷

為了滿足實時系統的要求,中斷處理應該是越快越好。linux為了實現這個特點,當中斷發生的時候,硬中斷處理那些短時間

就可以完成的工作,而將那些處理事件比較長的工作,放到中斷之后來完成,也就是軟中斷(softirq)來完成。

?

(3) 中斷嵌套

Linux下硬中斷是可以嵌套的,但是沒有優先級的概念,也就是說任何一個新的中斷都可以打斷正在執行的中斷,但同種中斷

除外。軟中斷不能嵌套,但相同類型的軟中斷可以在不同CPU上并行執行。

?

(4) 軟中斷指令

int是軟中斷指令。

中斷向量表是中斷號和中斷處理函數地址的對應表。

int n - 觸發軟中斷n。相應的中斷處理函數的地址為:中斷向量表地址 + 4 * n。

?

(5)硬中斷和軟中斷的區別

軟中斷是執行中斷指令產生的,而硬中斷是由外設引發的。

硬中斷的中斷號是由中斷控制器提供的,軟中斷的中斷號由指令直接指出,無需使用中斷控制器。

硬中斷是可屏蔽的,軟中斷不可屏蔽。

硬中斷處理程序要確保它能快速地完成任務,這樣程序執行時才不會等待較長時間,稱為上半部。

軟中斷處理硬中斷未完成的工作,是一種推后執行的機制,屬于下半部。?

?

開關

?

(1) 硬中斷的開關

簡單禁止和激活當前處理器上的本地中斷:

local_irq_disable();

local_irq_enable();

保存本地中斷系統狀態下的禁止和激活:

unsigned long flags;

local_irq_save(flags);

local_irq_restore(flags);

?

(2) 軟中斷的開關

禁止下半部,如softirq、tasklet和workqueue等:

local_bh_disable();

local_bh_enable();

需要注意的是,禁止下半部時仍然可以被硬中斷搶占。

?

(3) 判斷中斷狀態

#define in_interrupt() (irq_count())?// 是否處于中斷狀態(硬中斷或軟中斷)

#define in_irq()?(hardirq_count()) // 是否處于硬中斷

#define in_softirq() (softirq_count()) // 是否處于軟中斷

?

硬中斷

?

(1) 注冊中斷處理函數

注冊中斷處理函數:

 1 /** 
 2  * irq: 要分配的中斷號 
 3  * handler: 要注冊的中斷處理函數 
 4  * flags: 標志(一般為0) 
 5  * name: 設備名(dev->name) 
 6  * dev: 設備(struct net_device *dev),作為中斷處理函數的參數 
 7  * 成功返回0 
 8  */  
 9   
10 int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,   
11     const char *name, void *dev);  

?

中斷處理函數本身:

 1 typedef irqreturn_t (*irq_handler_t) (int, void *);  
 2   
 3 /** 
 4  * enum irqreturn 
 5  * @IRQ_NONE: interrupt was not from this device 
 6  * @IRQ_HANDLED: interrupt was handled by this device 
 7  * @IRQ_WAKE_THREAD: handler requests to wake the handler thread 
 8  */  
 9 enum irqreturn {  
10     IRQ_NONE,  
11     IRQ_HANDLED,  
12     IRQ_WAKE_THREAD,  
13 };  
14 typedef enum irqreturn irqreturn_t;  
15 #define IRQ_RETVAL(x) ((x) != IRQ_NONE)  

(2) 注銷中斷處理函數

 1 /** 
 2  * free_irq - free an interrupt allocated with request_irq 
 3  * @irq: Interrupt line to free 
 4  * @dev_id: Device identity to free 
 5  * 
 6  * Remove an interrupt handler. The handler is removed and if the 
 7  * interrupt line is no longer in use by any driver it is disabled. 
 8  * On a shared IRQ the caller must ensure the interrupt is disabled 
 9  * on the card it drives before calling this function. The function does 
10  * not return until any executing interrupts for this IRQ have completed. 
11  * This function must not be called from interrupt context. 
12  */  
13   
14 void free_irq(unsigned int irq, void *dev_id);  

?

軟中斷

?

(1) 定義

軟中斷是一組靜態定義的下半部接口,可以在所有處理器上同時執行,即使兩個類型相同也可以。

但一個軟中斷不會搶占另一個軟中斷,唯一可以搶占軟中斷的是硬中斷。?

軟中斷由softirq_action結構體表示:

1 struct softirq_action {  
2     void (*action) (struct softirq_action *); /* 軟中斷的處理函數 */  
3 };  ?

目前已注冊的軟中斷有10種,定義為一個全局數組:

 1 static struct softirq_action softirq_vec[NR_SOFTIRQS];  
 2   
 3 enum {  
 4     HI_SOFTIRQ = 0, /* 優先級高的tasklets */  
 5     TIMER_SOFTIRQ, /* 定時器的下半部 */  
 6     NET_TX_SOFTIRQ, /* 發送網絡數據包 */  
 7     NET_RX_SOFTIRQ, /* 接收網絡數據包 */  
 8     BLOCK_SOFTIRQ, /* BLOCK裝置 */  
 9     BLOCK_IOPOLL_SOFTIRQ,  
10     TASKLET_SOFTIRQ, /* 正常優先級的tasklets */  
11     SCHED_SOFTIRQ, /* 調度程序 */  
12     HRTIMER_SOFTIRQ, /* 高分辨率定時器 */  
13     RCU_SOFTIRQ, /* RCU鎖定 */  
14     NR_SOFTIRQS /* 10 */  
15 };  

?

(2) 注冊軟中斷處理函數

1 /** 
2  * @nr: 軟中斷的索引號 
3  * @action: 軟中斷的處理函數 
4  */  
5   
6 void open_softirq(int nr, void (*action) (struct softirq_action *))  
7 {  
8     softirq_vec[nr].action = action;  
9 }  ?

例如:

open_softirq(NET_TX_SOFTIRQ, net_tx_action);

open_softirq(NET_RX_SOFTIRQ, net_rx_action);

?

(3) 觸發軟中斷?

調用raise_softirq()來觸發軟中斷。

 1 void raise_softirq(unsigned int nr)  
 2 {  
 3     unsigned long flags;  
 4     local_irq_save(flags);  
 5     raise_softirq_irqoff(nr);  
 6     local_irq_restore(flags);  
 7 }  
 8   
 9 /* This function must run with irqs disabled */  
10 inline void rasie_softirq_irqsoff(unsigned int nr)  
11 {  
12     __raise_softirq_irqoff(nr);  
13   
14     /* If we're in an interrupt or softirq, we're done 
15      * (this also catches softirq-disabled code). We will 
16      * actually run the softirq once we return from the irq 
17      * or softirq. 
18      * Otherwise we wake up ksoftirqd to make sure we 
19      * schedule the softirq soon. 
20      */  
21     if (! in_interrupt()) /* 如果不處于硬中斷或軟中斷 */  
22         wakeup_softirqd(void); /* 喚醒ksoftirqd/n進程 */  
23 }  

Percpu變量irq_cpustat_t中的__softirq_pending是等待處理的軟中斷的位圖,通過設置此變量

即可告訴內核該執行哪些軟中斷。

 1 static inline void __rasie_softirq_irqoff(unsigned int nr)  
 2 {  
 3     trace_softirq_raise(nr);  
 4     or_softirq_pending(1UL << nr);  
 5 }  
 6   
 7 typedef struct {  
 8     unsigned int __softirq_pending;  
 9     unsigned int __nmi_count; /* arch dependent */  
10 } irq_cpustat_t;  
11   
12 irq_cpustat_t irq_stat[];  
13 #define __IRQ_STAT(cpu, member) (irq_stat[cpu].member)  
14 #define or_softirq_pending(x) percpu_or(irq_stat.__softirq_pending, (x))  
15 #define local_softirq_pending() percpu_read(irq_stat.__softirq_pending)  ?

喚醒ksoftirqd內核線程處理軟中斷。

1 static void wakeup_softirqd(void)  
2 {  
3     /* Interrupts are disabled: no need to stop preemption */  
4     struct task_struct *tsk = __get_cpu_var(ksoftirqd);  
5   
6     if (tsk && tsk->state != TASK_RUNNING)  
7         wake_up_process(tsk);  
8 }  

在下列地方,待處理的軟中斷會被檢查和執行:

1. 從一個硬件中斷代碼處返回時

2. 在ksoftirqd內核線程中

3. 在那些顯示檢查和執行待處理的軟中斷的代碼中,如網絡子系統中

?

而不管是用什么方法喚起,軟中斷都要在do_softirq()中執行。如果有待處理的軟中斷,

do_softirq()會循環遍歷每一個,調用它們的相應的處理程序。

在中斷處理程序中觸發軟中斷是最常見的形式。中斷處理程序執行硬件設備的相關操作,

然后觸發相應的軟中斷,最后退出。內核在執行完中斷處理程序以后,馬上就會調用

do_softirq(),于是軟中斷開始執行中斷處理程序完成剩余的任務。

下面來看下do_softirq()的具體實現。

 1 asmlinkage void do_softirq(void)  
 2 {  
 3     __u32 pending;  
 4     unsigned long flags;  
 5   
 6     /* 如果當前已處于硬中斷或軟中斷中,直接返回 */  
 7     if (in_interrupt())   
 8         return;  
 9   
10     local_irq_save(flags);  
11     pending = local_softirq_pending();  
12     if (pending) /* 如果有激活的軟中斷 */  
13         __do_softirq(); /* 處理函數 */  
14     local_irq_restore(flags);  
15 }  

?

 1 /* We restart softirq processing MAX_SOFTIRQ_RESTART times, 
 2  * and we fall back to softirqd after that. 
 3  * This number has been established via experimentation. 
 4  * The two things to balance is latency against fairness - we want 
 5  * to handle softirqs as soon as possible, but they should not be 
 6  * able to lock up the box. 
 7  */  
 8 asmlinkage void __do_softirq(void)  
 9 {  
10     struct softirq_action *h;  
11     __u32 pending;  
12     /* 本函數能重復觸發執行的次數,防止占用過多的cpu時間 */  
13     int max_restart = MAX_SOFTIRQ_RESTART;  
14     int cpu;  
15   
16     pending = local_softirq_pending(); /* 激活的軟中斷位圖 */  
17     account_system_vtime(current);  
18     /* 本地禁止當前的軟中斷 */  
19     __local_bh_disable((unsigned long)__builtin_return_address(0), SOFTIRQ_OFFSET);  
20     lockdep_softirq_enter(); /* current->softirq_context++ */  
21     cpu = smp_processor_id(); /* 當前cpu編號 */  
22   
23 restart:  
24     /* Reset the pending bitmask before enabling irqs */  
25     set_softirq_pending(0); /* 重置位圖 */  
26     local_irq_enable();  
27     h = softirq_vec;  
28     do {  
29         if (pending & 1) {  
30             unsigned int vec_nr = h - softirq_vec; /* 軟中斷索引 */  
31             int prev_count = preempt_count();  
32             kstat_incr_softirqs_this_cpu(vec_nr);  
33   
34             trace_softirq_entry(vec_nr);  
35             h->action(h); /* 調用軟中斷的處理函數 */  
36             trace_softirq_exit(vec_nr);  
37   
38             if (unlikely(prev_count != preempt_count())) {  
39                 printk(KERN_ERR "huh, entered softirq %u %s %p" "with preempt_count %08x,"  
40                     "exited with %08x?\n", vec_nr, softirq_to_name[vec_nr], h->action, prev_count,  
41                     preempt_count());  
42             }  
43             rcu_bh_qs(cpu);  
44         }  
45         h++;  
46         pending >>= 1;  
47     } while(pending);  
48   
49     local_irq_disable();  
50     pending = local_softirq_pending();  
51     if (pending & --max_restart) /* 重復觸發 */  
52         goto restart;  
53   
54     /* 如果重復觸發了10次了,接下來喚醒ksoftirqd/n內核線程來處理 */  
55     if (pending)  
56         wakeup_softirqd();   
57   
58     lockdep_softirq_exit();  
59     account_system_vtime(current);  
60     __local_bh_enable(SOFTIRQ_OFFSET);  
61 }  ?

(4) ksoftirqd內核線程

內核不會立即處理重新觸發的軟中斷。

當大量軟中斷出現的時候,內核會喚醒一組內核線程來處理。

這些線程的優先級最低(nice值為19),這能避免它們跟其它重要的任務搶奪資源。

但它們最終肯定會被執行,所以這個折中的方案能夠保證在軟中斷很多時用戶程序不會

因為得不到處理時間而處于饑餓狀態,同時也保證過量的軟中斷最終會得到處理。

?

每個處理器都有一個這樣的線程,名字為ksoftirqd/n,n為處理器的編號。

 1 static int run_ksoftirqd(void *__bind_cpu)  
 2 {  
 3     set_current_state(TASK_INTERRUPTIBLE);  
 4     current->flags |= PF_KSOFTIRQD; /* I am ksoftirqd */  
 5   
 6     while(! kthread_should_stop()) {  
 7         preempt_disable();  
 8   
 9         if (! local_softirq_pending()) { /* 如果沒有要處理的軟中斷 */  
10             preempt_enable_no_resched();  
11             schedule();  
12             preempt_disable():  
13         }  
14   
15         __set_current_state(TASK_RUNNING);  
16   
17         while(local_softirq_pending()) {  
18             /* Preempt disable stops cpu going offline. 
19              * If already offline, we'll be on wrong CPU: don't process. 
20              */  
21              if (cpu_is_offline(long)__bind_cpu))/* 被要求釋放cpu */  
22                  goto wait_to_die;  
23   
24             do_softirq(); /* 軟中斷的統一處理函數 */  
25   
26             preempt_enable_no_resched();  
27             cond_resched();  
28             preempt_disable();  
29             rcu_note_context_switch((long)__bind_cpu);  
30         }  
31   
32         preempt_enable();  
33         set_current_state(TASK_INTERRUPTIBLE);  
34     }  
35   
36     __set_current_state(TASK_RUNNING);  
37     return 0;  
38   
39 wait_to_die:  
40     preempt_enable();  
41     /* Wait for kthread_stop */  
42     set_current_state(TASK_INTERRUPTIBLE);  
43     while(! kthread_should_stop()) {  
44         schedule();  
45         set_current_state(TASK_INTERRUPTIBLE);  
46     }  
47   
48     __set_current_state(TASK_RUNNING);  
49     return 0;  
50 }  

?

轉載于:https://www.cnblogs.com/aaronLinux/p/6341590.html

總結

以上是生活随笔為你收集整理的[Linux内核]软中断与硬中断的全部內容,希望文章能夠幫你解決所遇到的問題。

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