C 为什么是“a”;屏障();是否足以禁用或启用抢占?

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

从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 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)