从Linux内核代码,我可以看到preempt_enable()
和preempt_disable()
除了barrier()
之外什么都不是:
#define preempt_disable() barrier()
#define preempt_enable() barrier()
我无法理解。为什么只有barrier()
足以禁用或启用抢占?
答案 0 :(得分:0)
在内核v4.3中,preempt_enable
的正确定义为here:
#define preempt_enable() \
do { \
barrier(); \
if (unlikely(preempt_count_dec_and_test())) \
__preempt_schedule(); \
} while (0)
并且preempt_disable
类似here:
#define preempt_disable() \
do { \
preempt_count_inc(); \
barrier(); \
} while (0)
preempt_enable
在启用抢占之前插入优化屏障,并且在抢占计数器递增后preempt_disable
插入屏障。然而,根据comment,当没有先发制人但只是保护被抢占地区的障碍时。
编辑:分别在UP和非抢占中,自旋锁和抢占 禁用/启用点完全被删除,因为没有 常规代码,可以达到它们所要达到的那种并发性 防止。
但是,虽然没有可以导致调度的常规代码,但我们 做最终会有一些特殊的(字面意思!)代码可以这样做, 而且我们需要确保永远不会陷入批评 区域由编译器。
特别是,get_user()和put_user()通常实现为 内联asm语句(即使内联asm可以随后进行调用 指令调用外线),显然会导致页面错误 和IO因此。如果内联asm已被安排到 在抢占安全(或自旋锁保护)代码区域的中间,我们 显然输了。
现在,诚然,这非常实际上不太可能发生,并且 我们没有看到与此相关的实际错误的示例。但部分原因 完全是因为它很难触发,结果就是这样 微妙的,我们应该格外小心地做到这一点。
因此,即使禁用抢占,我们也不必这样做 生成任何实际的代码以明确告诉系统我们所在的 一个抢占禁用区域,我们至少需要告诉编译器 在关键区域周围移动东西。 Source
答案 1 :(得分:0)
因为您没有使用可抢占的内核。 用户空间进程是可以抢占的。
检查内核配置中是否设置了CONFIG_PREEMPT_VOLUNTARY。
请参阅 What is preemption / What is a preemtible kernel? What is it good for?
以来添加了障碍