C 为什么是“a”;屏障();是否足以禁用或启用抢占?
从Linux内核代码中,我可以看到C 为什么是“a”;屏障();是否足以禁用或启用抢占?,c,linux,linux-kernel,barrier,preemption,C,Linux,Linux Kernel,Barrier,Preemption,从Linux内核代码中,我可以看到preempt\u enable()和preempt\u disable()只是barrier(): #define preempt_disable() barrier() #define preempt_enable() barrier() 我不明白。为什么仅仅一个barrier()就足以禁用或启用抢占?在内核v4.3中,对抢占启用的正确定义是: 类似地,对于preempt\u disable是: preempt\u enable
preempt\u enable()
和preempt\u disable()
只是barrier()
:
#define preempt_disable() barrier()
#define preempt_enable() barrier()
我不明白。为什么仅仅一个
barrier()
就足以禁用或启用抢占?在内核v4.3中,对抢占启用的正确定义是:
类似地,对于preempt\u disable
是:
preempt\u enable
在启用抢占前插入优化屏障,preempt\u disable
在抢占计数器递增后插入屏障。然而,根据,当不涉及优先购买权,而只是保护优先购买区域的障碍时
编辑:在UP和non-preempt中,分别使用自旋锁和抢占
禁用/启用点被完全删除,因为没有
常规代码可能会达到其预期的并发性
防范
然而,虽然没有常规代码可以导致调度,但我们
最终一定会有一些特殊的(字面上的!)代码可以做到这一点,
我们需要确保永远不会进入关键阶段
由编译器指定的区域
具体来说,get_user()和put_user()通常实现为
内联asm语句(即使内联asm可能会调用
指令),并可能明显导致页面错误
结果是IO。如果已将该内联asm计划到
在抢占安全(或自旋锁保护)代码区域的中间,我们
显然是输了
现在,诚然,这是不可能真正发生的,而且
我们还没有看到与此相关的实际bug示例。但部分
正是因为它很难被触发,而导致的错误是如此的严重
微妙的是,我们应该格外小心,以使这一点正确
因此,请确保即使禁用了抢占,我们也不必这样做
生成任何实际代码,以显式地告诉系统我们处于
一个禁止抢占的区域,我们至少需要告诉编译器不要
在关键区域移动东西 因为您没有使用可抢占内核。
不过,用户空间进程是可抢占的
检查内核配置中是否设置了CONFIG_PREEMPT_
看
由于的实现需要启用CONFIG\u PREEMPT\u COUNT
,(\define PREEMPT\u disable()barrier()
)是禁用CONFIG\u PREEMPT\u COUNT
时的版本。要添加到上述描述中,内核可以以两种方式编译,即抢占模式和非抢占模式。(我不想谈论一直存在的用户空间抢占)。Kconfig[source](),控制抢占的启用/禁用。当我们启用配置抢占时,配置抢占计数会自动启用(请参阅kconfig.PREEMPT)。当PREEMPT被禁用时,调用方将被barrier()替换,barrier()只用于刷新对DRAM的写入。
#define preempt_enable() \
do { \
barrier(); \
if (unlikely(preempt_count_dec_and_test())) \
__preempt_schedule(); \
} while (0)
#define preempt_disable() \
do { \
preempt_count_inc(); \
barrier(); \
} while (0)