在 Kernel 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,当不涉及抢占,而只是保护被抢占区域的障碍时。
EDIT:分别在 UP 和 non-preempt 中,自旋锁和抢占
禁用/启用点被完全剔除,因为没有
可以达到预期的并发性的常规代码
防止。
但是,虽然没有可以导致调度的常规代码,但我们
做 最终有一些特殊的(字面意思!)代码可以做到这一点,
我们需要确保永远不会进入关键
编译器的区域。
特别是 get_user() 和 put_user() 通常实现为
内联 asm 语句(即使内联 asm 可以调用
指令离线调用),显然会导致页面错误
结果是 IO。如果该内联汇编已安排到
在抢占安全(或自旋锁保护)代码区域的中间,我们
明显输了。
现在,诚然,这非常不太可能真正发生,并且
我们还没有看到与此相关的实际错误示例。但部分
正是因为它很难触发,而由此产生的错误是如此
微妙的,我们应该格外小心才能做到这一点。
因此,请确保即使禁用了抢占,我们也不必这样做
生成任何实际的代码来明确告诉系统我们在
一个禁止抢占的区域,我们至少需要告诉编译器不要
在关键区域周围移动东西。 Source