这些天,我正在研究内核内部网络代码,尤其是RPS代码。你知道,有很多关于它的功能。但我专注于有关SMP队列处理的一些功能,例如enqueue_to_backlog
和process_backlog
。
我想知道通过使用两个函数 -enqueue_to_backlog
和process_backlog
- 来同步两个内核(或单核(。
在该函数中,一个核心(A(持有另一个核心(B(的spin_lock
,用于将数据包排队进入input_pkt_queue
并调度核心(B(的纳皮。A Core(B(还包含一个spin_lock
,用于将input_pkt_queue
拼接到process_queue
个核心 (B( 并自行去除 napi 时间表。我知道应该保留spin_lock
以防止两个核心在处理队列期间相互访问同一队列。
但我不明白为什么用local_irq_disable
(或local_irq_save
(来称呼spin_lock
。我认为当中断(TH(抢占当前上下文(softirq,BH(时,中断上下文(TH(不会访问核心(B(的队列或rps_lock
。- 当然,可以通过 TH 访问 napi 结构来调度 napi,但它保持禁用 irq 直到排队数据包 -所以我想知道为什么在禁用 irq 的情况下调用spin_lock
。
我认为不可能通过其他BH抢占当前上下文(napi,softirq(,例如tasklet。是真的吗?我想知道local_irq_disable禁用所有内核 irq 还是仅禁用当前内核的 irq?实际上,我读过一本关于内核开发的书,但我认为我对抢占的理解还不够。
会解释为什么 rps 程序将spin_lock
与local_irq_disable
一起使用的原因?
禁用中断会影响当前内核(仅(。因此,禁用后,同一内核上的任何其他代码都无法干扰对数据结构的更新。自旋锁的要点是将"锁定"扩展到其他内核(尽管它是协作的,而不是硬件强制执行的(。
在不禁用中断的情况下在内核中使用旋转锁是危险/不负责任的,因为当发生中断时,当前代码将被挂起,现在您正在阻止其他内核在某些不相关的中断处理程序运行时取得进展(即使原始内核上的另一个用户进程或 tasklet 将无法抢占(。其他内核本身可能处于中断或 BH 上下文中,现在您正在延迟整个系统。自旋锁应该保留很短的时间,以便对共享数据结构进行关键更新。
这也是生成死锁的好方法。考虑上述方案是否在另一个子系统(或可能在同一子系统中的另一个设备,但我会描述前者(中复制。
在这里,内核 A 在子系统 1 中采用自旋锁,而不禁用中断。同时,内核 B 在子系统 2 中也采用自旋锁,而不会禁用中断。现在,如果与子系统 2 相关的中断发生在核心 A 上,并且在执行子系统 2 中断处理程序时,核心 A 需要更新由核心 B 中持有的自旋锁保护的结构,会发生什么情况。但大约在同一时间,子系统 1 中断发生在核心 B 上,需要更新该子系统中的数据结构。现在,两个内核都忙于等待另一个内核持有的旋转锁,并且整个系统被冻结,直到您进行硬重置。