Where Softirq Is Invoked

来源:互联网 发布:怎么取消数据有效性 编辑:程序博客网 时间:2024/06/01 16:42

summary

softirq 真正干活的函数是__do_softirq。 linuxv3.11内核里能够执行__do_softirq,有如下调用, 这里指真正执行softirq的地方,不是触发(设置)softirq标志 !!!

  1. 每个硬中断退出的时。
  2. 当bh使能的时。
  3. 发送回环报文时。

case1 每个硬中断退出的时候。

call trace

123
> irq_exit> > invoke_softirq> > > __do_softirq

irq_exit

1234567891011121314151617181920
350 /*351  * Exit an interrupt context. Process softirqs if needed and possible:352  */353 void irq_exit(void)354 {355 #ifndef __ARCH_IRQ_EXIT_IRQS_DISABLED356         local_irq_disable();357 #else358         WARN_ON_ONCE(!irqs_disabled());359 #endif360361         account_irq_exit_time(current);362         trace_hardirq_exit();363         sub_preempt_count(HARDIRQ_OFFSET);364         if (!in_interrupt() && local_softirq_pending())365                 invoke_softirq();366367         tick_irq_exit();368         rcu_irq_exit();369 }

invoke_softirq

1234567
329 static inline void invoke_softirq(void)330 {331         if (!force_irqthreads)332                 __do_softirq();333         else334                 wakeup_softirqd();335 }

case2 使能bh的时候

call trace

12345
> local_bh_enable> > _local_bh_enable_ip> > > do_softirq> > > > (x86_64特有的)call_softirq> > > > __do_softirq

local_bh_enable

12345
184 void local_bh_enable(void)185 {186         _local_bh_enable_ip(_RET_IP_);187 }188 EXPORT_SYMBOL(local_bh_enable);

_local_bh_enable_ip

NOTE: 使能bh的时候,刚开始抢占还是禁止的。只有软中断处理完了后,抢占才使能的。 顺便说一下,使能bh时,有可能发生进程切换(见preempt_check_resched).

1234567891011121314151617181920212223242526
157 static inline void _local_bh_enable_ip(unsigned long ip)158 {159         WARN_ON_ONCE(in_irq() || irqs_disabled());160 #ifdef CONFIG_TRACE_IRQFLAGS161         local_irq_disable();162 #endif163         /*164          * Are softirqs going to be turned on now:165          */166         if (softirq_count() == SOFTIRQ_DISABLE_OFFSET)167                 trace_softirqs_on(ip);168         /*169          * Keep preemption disabled until we are done with170          * softirq processing:171          */172         sub_preempt_count(SOFTIRQ_DISABLE_OFFSET - 1);173174         if (unlikely(!in_interrupt() && local_softirq_pending()))175                 do_softirq();176177         dec_preempt_count();178 #ifdef CONFIG_TRACE_IRQFLAGS179         local_irq_enable();180 #endif181         preempt_check_resched();182 }

do_softirq根据不同的体系机构有不同的版本。

当对应的硬件体系里没有定义do_softirq时,使用 kernel/softirq.c中通用的do_softirq`.

123456789101112131415161718192021
286 #ifndef __ARCH_HAS_DO_SOFTIRQ287288 asmlinkage void do_softirq(void)289 {290         __u32 pending;291         unsigned long flags;292293         if (in_interrupt())294                 return;295296         local_irq_save(flags);297298         pending = local_softirq_pending();299300         if (pending)301                 __do_softirq();302303         local_irq_restore(flags);304 }305306 #endif

而对于X86_64,有其自己的定义。

12345678910111213141516171819
 92 extern void call_softirq(void); 93 94 asmlinkage void do_softirq(void) 95 { 96         __u32 pending; 97         unsigned long flags; 98 99         if (in_interrupt())100                 return;101102         local_irq_save(flags);103         pending = local_softirq_pending();104         /* Switch to interrupt stack */105         if (pending) {106                 call_softirq();107                 WARN_ON_ONCE(softirq_count());108         }109         local_irq_restore(flags);110 }

其中call_softirq是个用汇编语言写的一个函数定义在 arch/x86/kernel/entry_64.S

netif_rx_ni

这一块的理解不是很透,仅以一个具体的例子来说明。发送回环报文.

发送回环报文

call trace

1234
> dev_loopback_xmit> > netif_rx_ni> > do_softirq> > > __do_softirq

loopback 报文会通过netif_rx函数,被重新放回到 per_cpu变量softnet_data下的队列input_pkt_queue里, 同时激发napi调用,进而激发软中断调用(只是设置标志位,不是真正调用)

另外,注意netif_rx_ni里没有禁止bh调度,而是只是禁止了抢占(preempt_disable).

dev_loopback_xmit
1234567891011
2765 int dev_loopback_xmit(struct sk_buff *skb)2766 {2767         skb_reset_mac_header(skb);2768         __skb_pull(skb, skb_network_offset(skb));2769         skb->pkt_type = PACKET_LOOPBACK;2770         skb->ip_summed = CHECKSUM_UNNECESSARY;2771         WARN_ON(!skb_dst(skb));2772         skb_dst_force(skb);2773         netif_rx_ni(skb);2774         return 0;2775 }
netif_rx_ni
12345678910111213
3267 int netif_rx_ni(struct sk_buff *skb)3268 {3269         int err;32703271         preempt_disable();3272         err = netif_rx(skb);3273         if (local_softirq_pending())3274                 do_softirq();3275         preempt_enable();32763277         return err;3278 }3279 EXPORT_SYMBOL(netif_rx_ni);

 Sep 23rd2013 10:36 am  irqs

http://martinbj2008.github.io/blog/2013/09/23/where-softirq-is-invoked/

0 0
原创粉丝点击