歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Linux軟中斷

Linux軟中斷

日期:2017/3/1 10:25:18   编辑: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. NR_SOFTIRQS
  14. };

可以看出,一共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. raise_softirq_irqoff(nr);
  9. local_irq_restore(flags);
  10. }

具體的激活工作由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. * If we're in an interrupt or softirq, we're done
  10. * (this also catches softirq-disabled code). We will
  11. * actually run the softirq once we return from
  12. * the irq or softirq.
  13. *
  14. * Otherwise we wake up ksoftirqd to make sure we
  15. * schedule the softirq soon.
  16. */
  17. if (!in_interrupt())
  18. wakeup_softirqd();/*喚醒本地的內核線程*/
  19. }

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

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