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 }