spin_lock_bh

本文探讨了Linux内核中的软中断(SoftIRQ)和Tasklet机制,对比了早期Bottom Half(BH)机制的局限性,并详细解释了软中断如何解决多CPU环境下BH机制存在的问题。此外,还介绍了Tasklet作为简化版本的软中断机制的特点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 一个软中断不会抢占另外一个软中断,softirq执行时preempt_count大于零,所以从中断返回到软中断的时候,不会调度

 

用lock_bh(),是因为这些netfilter hooks可以从系统调用的context到达,
比如socket的send_msg()是可以到达LOCAL_OUT/POST_ROUTING的,
这样,也就是说,在这些情况下操作conntrack链表的时候,是进程上下文,而不是软中断上下文,
因此,是需要关闭bh的。

ip_conntrack_in()比较特殊,它是注册在PRE_ROUTING上的,
按道理说,它只能从软中断到达,因此只需要spin_lock()就可以了,
之所以也使用spin_lock_bh(),
可能是为了维护一致性(这里多一次lock_bh无所谓),
也可能是因为会有些特殊的虚拟设备,可以从其他的上下文到达PRE_ROUTING。

Linux内核为将中断服务分为两部分提供了方便,并设立了相应的机制。在以前的内核中,这个机制就叫bottom half(简称bh),但在2.4版中有了新的发展和推广,叫做软中断(softirq)机制。

1.Bh机制

以前内核中的Bh机制设置了一个函数指针数组bh_base[],它把所有的后半部分都组织起来,其大小为32,数组中的每一项就是一个后半部分,即一个bh 函数。同时,又设置了两个32位无符号整数bh_active和bh_mask,每个无符号整数中的一位对应着bh_base[]中的一个元素,如图3.9所示:

 在2.4以前的内核中,每次执行完do_IRQ()中的中断服务例程以后,以及每次系统调用结束之前,就在一个叫do_bottom_half()的函数中执行相应的bh函数。

在do_bottom_half()中对bh函数的执行是在关中断的情况下进行的,也就是说对bh的执行进行了严格的“串行化”,这种方式简化了bh的设计,这是因为,对单CPU来说,bh 函数的执行可以不嵌套;而对于多CPU来说,在同一时间内最多只允许一个CPU执行bh函数。

这种简化了的设计在一定程度上保证了从单CPU到多CPU SMP结构的平稳过渡,但随着时间的推移,就会发现这样的处理对于SMP的性能有不利的影响。因为,当系统中有很多个bh函数需要执行时,bh函数的“串行化”却只能使一个CPU执行一个bh函数,其它CPU即使空闲,也不能执行其它的bh函数。由此可以看出,bh函数的串行化是针对所有CPU的,根本发挥不出多CPU的优势。

那么,在新内核的设计中,是改进bh机制还是抛弃bh机制,建立一种新的机制?2.4选择了一种折中的办法,继续保留bh机制,另外增加一种或几种机制,并把它们纳入一个统一的框架中,这就是2.4内核中的软中断(softirq)机制。

2.软中断机制

软中断机制也是推迟内核函数的执行,然而,与bh函数严格地串行执行相比,软中断却在任何时候都不需要串行化。同一个软中断的两个实例完全有可能在两个CPU上同时运行。当然,在这种情况下,软中断必须是可重入的。软中断给网络部分带来的好处尤为突出,因为2.4内核中用两个软中断代替原来的一个NET_BH函数,这就使得在多处理机系统上软中断的执行更为高效。

3.Tasklet机制

另一个类似于bh的机制叫做tasklet。Tasklet建立在软中断之上,但与软中断的区别是,同一个tasklet只能运行在一个CPU上,而不同的tasklet可以同时运行在不同的CPU上。在这种情况下,tasklet就不需要是可重入的,因此,编写tasklet比编写一个软中断要容易。

     Bh机制在2.4中依然存在,但不是作为一个单独的机制存在,而是建立在tasklet之上。因此,在2.4版中,设备驱动程序的开发者必须更新他们原来的驱动程序,用tasklet代替bh。

 

 

int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq) { struct ath10k *ar = hw->priv; struct ath10k_htt *htt = &ar->htt; struct ath10k_txq *artxq = (void *)txq->drv_priv; struct ieee80211_vif *vif = txq->vif; struct ieee80211_sta *sta = txq->sta; enum ath10k_hw_txrx_mode txmode; enum ath10k_mac_tx_path txpath; struct sk_buff *skb; struct ieee80211_hdr *hdr; size_t skb_len; bool is_mgmt, is_presp; int ret; u16 airtime; spin_lock_bh(&ar->htt.tx_lock); ret = ath10k_htt_tx_inc_pending(htt); spin_unlock_bh(&ar->htt.tx_lock); if (ret) return ret; skb = ieee80211_tx_dequeue_ni(hw, txq); if (!skb) { spin_lock_bh(&ar->htt.tx_lock); ath10k_htt_tx_dec_pending(htt); spin_unlock_bh(&ar->htt.tx_lock); return -ENOENT; } airtime = ath10k_mac_update_airtime(ar, txq, skb); ath10k_mac_tx_h_fill_cb(ar, vif, txq, sta, skb, airtime); skb_len = skb->len; txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb); txpath = ath10k_mac_tx_h_get_txpath(ar, skb, txmode); is_mgmt = (txpath == ATH10K_MAC_TX_HTT_MGMT); if (is_mgmt) { hdr = (struct ieee80211_hdr *)skb->data; is_presp = ieee80211_is_probe_resp(hdr->frame_control); spin_lock_bh(&ar->htt.tx_lock); ret = ath10k_htt_tx_mgmt_inc_pending(htt, is_mgmt, is_presp); if (ret) { ath10k_htt_tx_dec_pending(htt); spin_unlock_bh(&ar->htt.tx_lock); return ret; } spin_unlock_bh(&ar->htt.tx_lock); } ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb, false); if (unlikely(ret)) { ath10k_warn(ar, "failed to push frame: %d\n", ret); spin_lock_bh(&ar->htt.tx_lock); ath10k_htt_tx_dec_pending(htt); if (is_mgmt) ath10k_htt_tx_mgmt_dec_pending(htt); spin_unlock_bh(&ar->htt.tx_lock); return ret; } spin_lock_bh(&ar->htt.tx_lock); artxq->num_fw_queued++; spin_unlock_bh(&ar->htt.tx_lock); return skb_len; }这个函数在做什么
04-09
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值