在面向ARM平台的linux内核实现中,微线程中的延迟工作被添加到percpu vec|vec_hi列表中。
- 现在,当从ISR执行返回时,它会去处理软线程和微线程中的延迟工作。 现在这个延迟的工作可以在中断上下文中被处理,irq被启用,或者有ksoftirq线程可以在进程上下文中处理它。
- 相同的微线程将在同一个CPU上执行,因为ksoftirq线程是全CPU的。
- 我在很多书中看到,例如LDD, Robert Love的书,它声称同一个微线程不能同时在两个核心上执行?
如何?有人能帮我一下吗?如果真是这样,我还错过了什么?
这是真的。虽然微线程可以在任意数量的cpu上调度(即请求微线程执行),但它只会在一个cpu上执行。
我认为这样做的原因是为了简化开发模型:使它更容易实现本质上是中断处理程序,而无需担心由于在多个处理器上同时执行而导致的竞争——同时不禁用其他中断。(游戏邦注:显然,赛车手开发者还需要意识到许多其他的比赛机会,但这些都是最难解决的。)
如果你问的是实现,它实际上很简单。在tasklet_action
中,称为tasklet_trylock
。它使用保证原子函数test_and_set_bit
来设置TASKLET_STATE_RUN
位。这只能在一个处理器上成功。因此,所有其他处理器都被阻止执行微线程,直到该位被清除——这只有在微线程完成后设置它的处理器才会完成。
编辑:
澄清:在任意数量的CPU上调用tasklet_schedule
(在执行之前)会导致微线程只执行一次:在发出调用的第一个 CPU上。同样的机制(test_and_set_bit
)确保如果微线程已经在其他CPU上调度但尚未执行,它将不被添加到后一个CPU上的微线程运行队列(因此根本不会在后一个CPU上执行)。
另一方面,如果它已经开始在第一个CPU上执行,那么TASKLET_STATE_SCHEDULE
位将被清除(因此可能会再次设置),因此对tasklet_schedule
的另一次调用确保该微线程最终将在后面的CPU上重新执行,但直到它在第一个CPU上运行完成之后。
softirqs是下半部中断处理,是基于一个基于索引的函数调用机制,其中函数实现了softirq的功能。
维护一个函数指针数组。当一个函数被注册时,一个有效的函数指针被写入相应的索引中。指数代表软队列个数,0为优先级最高的软队列。一个字被维护为挂起的软请求的掩码。
当前软电平的数目由单词的每个位表示,当软电平升高时,掩码中相应的位被设置。接下来,当内核想要运行挂起的软请求时,它使用掩码字来标识挂起的软请求,并使用数组调用适当的函数调用,该数组的第0个索引映射为掩码字的第0位。
微线程是通过softirqs实现的,数组的索引0和索引5分别包含处理高微线程和普通微线程的函数的指针。微线程是用一个结构体来标识的,这个结构体包含一个函数指针和一个状态标志。
每当创建微线程时,就会创建一个结构,用实现微线程的函数的地址填充函数指针。维护所有这类结构的链接列表。当微线程被调度时,它(内核)在链表的头部添加一个相应的结构,并提高微线程的softirq,即在掩码字中设置适当的位。
接下来,当处理微线程的函数被调用时,它检查链接列表中的所有元素,如果状态标志没有运行,则在结构中调用该函数,这表明它已经在处理器中运行。
因此内核确保没有两个相同的微线程运行在一个以上的处理器。