为什么“屏障()”足以禁用或启用抢占?

时间:2015-11-23 06:31:04

标签: linux linux-kernel barrier preemption preemptive

从Linux内核代码,我可以看到preempt_enable()preempt_disable()除了barrier()之外什么都不是:

#define preempt_disable()       barrier()

#define preempt_enable()        barrier()

我无法理解。为什么只有barrier()足以禁用或启用抢占?

2 个答案:

答案 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?

https://kernel.googlesource.com/pub/scm/linux/kernel/git/stable/linux-stable/+/386afc91144b36b42117b0092893f15bc8798a80%5E!/

以来添加了障碍