为什么同一个 TASKLET 不能同时在两个内核上执行?

why same TASKLET can't execute on two core simultaneously?

在ARM平台的linux内核实现中,tasklet中的延迟工作被添加到percpu vec|vec_hi列表中。

  1. 现在从 ISR 执行返回时,它会处理 softirq 和 tasklet 中的延迟工作。
  2. 现在可以在启用 IRQ 的中断上下文中处理这个延迟的工作,或者有 ksoftirq 线程可以在进程上下文中处理它。
  3. 相同的 tasklet 将在相同的 CPU 上执行,因为 ksoftirq 线程是 percpu。
  4. 我在很多书中都看到过这一点,例如LDD,Robert Love的书,说同一个tasklet不能同时在两个核上执行?

怎么样?有人可以帮我解决这个问题吗...如果是这样,我错过了什么?

这是真的。虽然可以在任意数量的 CPU 上安排 tasklet(即请求 tasklet 执行),但它只会在一个上执行。

我认为这样做的原因是为了简化开发模型:使本质上是中断处理程序的实现变得更容易,而无需担心由于在多个处理器上同时执行而导致的竞争——同时不禁用其他处理器中断。 (显然,驱动程序开发人员还需要注意许多其他的比赛机会,但这些都是最难解决的。)

如果你问的是实现,其实很简单。在tasklet_action中,调用了tasklet_trylock。它使用保证原子函数 test_and_set_bit 来设置 TASKLET_STATE_RUN 位。这只能在一个处理器上成功。因此,在该位被清除之前,所有其他处理器都无法执行该 tasklet——这仅由在 tasklet 完成后设置它的处理器完成。

编辑:
澄清:在任意数量的 CPU 上调用 tasklet_schedule(在执行之前)会导致 tasklet 恰好执行一次:在 first CPU那个打了电话。同样的机制(test_and_set_bit)确保如果tasklet已经被其他CPU调度但是还没有被执行,它会被添加到tasklets-to-运行 在后面的 CPU 队列中(因此根本不会在后面的 CPU 上执行)。

另一方面,如果它已经开始执行第一个 CPU,TASKLET_STATE_SCHEDULE 位将被清除(因此可能会再次设置),因此另一个调用tasklet_schedule 确保 tasklet 最终将在稍后的 CPU 上重新执行,但直到它在第一个 CPU.运行 完成后才会执行。

softirqs 是 bottom half 中断处理,基于基于索引的函数调用机制,其中函数实现 softirq 的功能。

维护了一个函数指针数组。当一个软中断被注册时,一个有效的函数指针被写入适当的索引。该指数代表 softirq 的编号,0 是最高优先级的 softirq。保留一个字作为挂起软中断的掩码。

当前 9 个软中断的数量由一个字的每一位表示,当 sofirq 被提升时,掩码中的适当位是 set.Next 当内核想要 运行 它使用的挂起的软中断用于标识未决软中断的掩码字,并使用数组调用适当的函数调用,其第 0 个索引与掩码字的第 0 位映射。

小任务是通过软中断实现的,数组的索引 0 和索引 5 包含指向分别处理高级和普通小任务的函数的指针。 Tasklet 用一个结构来标识,该结构在其他成员中包含一个函数指针和一个状态标志。

每当创建 tasklet 时,都会创建一个结构,用实现 tasklet 的函数的地址填充函数指针。维护了所有此类结构的 link 列表。 当 tasklet 被调度时,它(内核)将相应的结构添加到 link 列表的头部并引发 tasklet 的 softirq,即在掩码字中设置适当的位。

接下来,当调用处理微线程的函数时,它会检查 link 列表的所有元素,并在状态标志不是 运行ning 的情况下调用结构中的函数,这表明它已经 运行在处理器中。

因此内核确保不会有 2 个相同的小线程 运行在一个以上的处理器中运行。