kernel version:2.6.32.61
系統有資源處理軟中斷時,會檢視軟中斷向量表,調用對應的handler。
網絡收包時軟中斷處理函數是net_rx_action。是在net_dev_init中初始化的:
net/core/dev.c
5654 static int __init net_dev_init(void)
5655 {
...
5708 open_softirq(NET_TX_SOFTIRQ, net_tx_action);
5709 open_softirq(NET_RX_SOFTIRQ, net_rx_action);
...
5717 }
軟中斷處理函數,主要動作是輪詢poll_list,然後調用poll處理。如果這個裝置所有包都處理完後就将其從poll_list中移除。
這裡分為兩種情況,
1) 裝置驅動支援NAPI
2) 裝置驅動不支援NAPI
對于支援NAPI的驅動,在poll_list中的poll函數是需要裝置自己實作的,裝置擁有自己的隊列,不需要共享CPU隊列,是以不需要關閉中斷。
對于不支援NAPI的驅動,poll函數就是process_backlog,裝置需要共享CPU隊列,而在軟中斷處理時是可以被中斷打斷的,是以對于CPU隊列操作時需要關閉中斷。
以下是net_rx_action的代碼:
net/core/dev.c
2834 static void net_rx_action(struct softirq_action *h)
2835 {
2836 struct list_head *list = &__get_cpu_var(softnet_data).poll_list;
2837 unsigned long time_limit = jiffies + 2;
2838 int budget = netdev_budget;
2839 void *have;
2840
2841 local_irq_disable();
2842
// 周遊poll_list
2843 while (!list_empty(list)) {
2844 struct napi_struct *n;
2845 int work, weight;
2846
2847 /* If softirq window is exhuasted then punt.
2848 * Allow this to run for 2 jiffies since which will allow
2849 * an average latency of 1.5/HZ.
2850 */
// CPU時間用完或者budget用完就要釋放CPU
2851 if (unlikely(budget <= 0 || time_after_eq(jiffies, time_limit)))
2852 goto softnet_break;
2853
2854 local_irq_enable();
2855
2856 /* Even though interrupts have been re-enabled, this
2857 * access is safe because interrupts can only add new
2858 * entries to the tail of this list, and only ->poll()
2859 * calls can remove this head entry from the list.
2860 */
2861 n = list_entry(list->next, struct napi_struct, poll_list);
2862
2863 have = netpoll_poll_lock(n);
2864
2865 weight = n->weight;
2866
2867 /* This NAPI_STATE_SCHED test is for avoiding a race
2868 * with netpoll's poll_napi(). Only the entity which
2869 * obtains the lock and sees NAPI_STATE_SCHED set will
2870 * actually make the ->poll() call. Therefore we avoid
2871 work = 0;
2872 if (test_bit(NAPI_STATE_SCHED, &n->state)) {
// 調用poll函數處理
2873 work = n->poll(n, weight);
2874 trace_napi_poll(n);
2875 }
2876
2877 WARN_ON_ONCE(work > weight);
2878
2879 budget -= work;
2880
2881 local_irq_disable();
2882
2883 /* Drivers must not modify the NAPI state if they
2884 * consume the entire weight. In such cases this code
2885 * still "owns" the NAPI instance and therefore can
2886 * move the instance around on the list at-will.
2887 */
2888 if (unlikely(work == weight)) {
2889 if (unlikely(napi_disable_pending(n))) {
2890 local_irq_enable();
2891 napi_complete(n);
2892 local_irq_disable();
2893 } else
2894 list_move_tail(&n->poll_list, list);
2895 }
2896
2897 netpoll_poll_unlock(have);
2898 }
2899 out:
2900 local_irq_enable();
2901
2902 #ifdef CONFIG_NET_DMA
2903 /*
2904 * There may not be any more sk_buffs coming right now, so push
2905 * any pending DMA copies to hardware
2906 */
2907 dma_issue_pending_all();
2908 #endif
2909
2910 return;
2911
2912 softnet_break:
2913 __get_cpu_var(netdev_rx_stat).time_squeeze++;
2914 __raise_softirq_irqoff(NET_RX_SOFTIRQ);
2915 goto out;
2916 }