歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Linux軟中斷

在由內核執行的幾個任務之間有些不是緊急的,在必要情況下他們可以延遲一段時間。一個中斷處理程序的幾個中斷服務例程之間是串行執行的,並且通常在一個中斷的處理程序結束前,不應該再次出現這個中斷。相反,可延遲中斷可以在開中斷的情況下執行。

linux中所謂的可延遲函數,包括軟中斷和tasklet以及通過中作隊列執行的函數(這個以後說),軟中斷的分配是靜態的(即值編譯時定義),而tasklet的分配和初始化可以在運行時進行。

軟中斷

軟中斷所使用的數據結構定義為

  1. static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp;  

其中softirq_action類型為一個函數指針,從這裡也可以看出,軟中斷的個數是有限的有NR_SOFTIRQS個,具體的定義如下:

  1. enum  
  2. {  
  3.     HI_SOFTIRQ=0,  
  4.     TIMER_SOFTIRQ,  
  5.     NET_TX_SOFTIRQ,  
  6.     NET_RX_SOFTIRQ,  
  7.     BLOCK_SOFTIRQ,  
  8.     BLOCK_IOPOLL_SOFTIRQ,  
  9.     TASKLET_SOFTIRQ,  
  10.     SCHED_SOFTIRQ,  
  11.     HRTIMER_SOFTIRQ,  
  12.     RCU_SOFTIRQ,    /* Preferable RCU should always be the last softirq */  
  13.   
  14.     NR_SOFTIRQS  
  15. };  

可以看出,一共10個軟中斷。

  1. struct softirq_action  
  2. {  
  3.     void    (*action)(struct softirq_action *);  
  4. };  

軟中斷的初始化

  1. /*初始化軟中斷*/  
  2. void open_softirq(int nr, void (*action)(struct softirq_action *))  
  3. {  
  4.     softirq_vec[nr].action = action;  
  5. }  

上面函數中,參數nr為softirq_vec[]數組的下標,初始化就是初始化softirq_vec[]數組內容。

初始化了軟中斷後,要執行,接下來要做的是激活軟中斷,運用下面函數

  1. /*激活軟中斷*/  
  2. void raise_softirq(unsigned int nr)  
  3. {  
  4.     unsigned long flags;  
  5.     /*保存eflags寄存器IF標志的狀態值 
  6.     並禁用本地CPU上得中斷*/  
  7.     local_irq_save(flags);  
  8.       
  9.     raise_softirq_irqoff(nr);  
  10.     local_irq_restore(flags);  
  11. }  

具體的激活工作由raise_softirq_irqoff函數實現

  1. /* 
  2.  * This function must run with irqs disabled! 
  3.  */  
  4. inline void raise_softirq_irqoff(unsigned int nr)  
  5. {     
  6.     /*把軟中斷標記為掛起*/  
  7.     __raise_softirq_irqoff(nr);  
  8.   
  9.     /* 
  10.      * If we're in an interrupt or softirq, we're done 
  11.      * (this also catches softirq-disabled code). We will 
  12.      * actually run the softirq once we return from 
  13.      * the irq or softirq. 
  14.      * 
  15.      * Otherwise we wake up ksoftirqd to make sure we 
  16.      * schedule the softirq soon. 
  17.      */  
  18.     if (!in_interrupt())  
  19.         wakeup_softirqd();/*喚醒本地的內核線程*/  
  20. }  

守護線程softirqd就是對軟中斷的處理

  1. static int ksoftirqd(void * __bind_cpu)  
  2. {  
  3.     /*設置進程狀態為可中斷*/  
  4.     set_current_state(TASK_INTERRUPTIBLE);  
  5.   
  6.     while (!kthread_should_stop()) {/*不應該馬上返回*/  
  7.         preempt_disable();  
  8.         /*實現軟中斷中一個關鍵數據結構是每個 
  9.         CPU都有的32位掩碼(描述掛起的軟中斷), 
  10.         他存放在irq_cpustat_t數據結構的__softirq_pending 
  11.         字段中。為了獲取或設置位掩碼的值, 
  12.         內核使用宏local_softirq_pending,他選擇cpu的 
  13.         軟中斷為掩碼*/  
  14.         if (!local_softirq_pending()) {/*位掩碼為0,標示沒有軟中斷*/  
  15.             preempt_enable_no_resched();  
  16.             schedule();  
  17.             preempt_disable();  
  18.         }  
  19.   
  20.         __set_current_state(TASK_RUNNING);  
  21.   
  22.         while (local_softirq_pending()) {  
  23.             /* Preempt disable stops cpu going offline. 
  24.                If already offline, we'll be on wrong CPU: 
  25.                don't process */  
  26.             if (cpu_is_offline((long)__bind_cpu))  
  27.                 goto wait_to_die;  
  28.             do_softirq();/*調用軟中斷處理函數*/  
  29.             preempt_enable_no_resched();  
  30.             cond_resched();  
  31.             preempt_disable();  
  32.             rcu_sched_qs((long)__bind_cpu);  
  33.         }  
  34.         preempt_enable();  
  35.         set_current_state(TASK_INTERRUPTIBLE);  
  36.     }  
  37.     __set_current_state(TASK_RUNNING);  
  38.     return 0;  
  39.   
  40. wait_to_die:  
  41.     preempt_enable();  
  42.     /* Wait for kthread_stop */  
  43.     set_current_state(TASK_INTERRUPTIBLE);  
  44.     while (!kthread_should_stop()) {  
  45.         schedule();  
  46.         set_current_state(TASK_INTERRUPTIBLE);  
  47.     }  
  48.     __set_current_state(TASK_RUNNING);  
  49.     return 0;  
  50. }  
Copyright © Linux教程網 All Rights Reserved