2015-11-23 24 views
2

Из кода ядра Linux, я могу видеть preempt_enable() и preempt_disable() нет ничего, кроме всего barrier():Почему достаточно «барьера()» для отключения или включения превенции?

#define preempt_disable()  barrier() 

#define preempt_enable()  barrier() 

Я не могу этого понять. Почему просто для barrier() достаточно для отключения или включения предохранения?

ответ

0

В Kernel v4.3, право определение preempt_enablehere является:

#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 и не-PREEMPT соответственно, спин-блокировка и упреждение отключить/включить пункты затушили полностью, потому что нет регулярного кода, который никогда не может попасть в таком параллелизме они предназначены для защищать от.

Однако, в то время как нет регулярного кода, который может вызвать планирование, мы сделать в конечный итоге, некоторый исключительный (буквально!) Код, который может сделать так, и что нам нужно, чтобы убедиться, что не когда-нибудь перемещаемыми в критическую область компилятором.

В частности, get_user() и put_user(), как правило, реализуются в виде заявления инлайн ассемблера (даже если встроенный ASM может затем сделать вызов инструкции для вызова вне линии), и, очевидно, могут вызвать страницу ошибка и IO в результате. Если этот встроенный asm был запланирован на в середине защищенной от вторсырья (или защищенной от спин-блокировки) области кода, мы, очевидно, проиграем .

Теперь, по общему признанию, это очень вряд ли когда-либо произойдет, и мы не видели примеров фактических ошибок, связанных с этим. Но частично именно потому, что его так сложно вызвать, и получившаяся ошибка настолько утончена, что мы должны быть осторожны, чтобы получить это право.

Поэтому убедитесь, что даже когда упреждение отключен, и мы не должны генерировать любые фактические код явно указать системе, что мы находимся в упреждение-инвалидов области, мы должны, по крайней мере сказать компилятор не для перемещения предметов вокруг критической области. Source

+0

[preempt_disable] (http://lxr.free-electrons.com/source/include/linux/preempt.h#L163) 'ы для реализации требуется 'CONFIG_PREEMPT_COUNT', [This] (http://lxr.free-electrons.com/source/include/linux/preempt.h#L236) (' #define preempt_disable() барьер() ') - это когда 'CONFIG_PREEMPT_COUNT' выключен. –

+0

Чтобы добавить к вышеприведенному описанию, ядро ​​может быть скомпилировано двумя способами, а именно с упреждающим режимом и не превентивным режимом. (Я не берусь о приостановке пользовательского пространства, которое всегда существует). Kconfig [источник] (http://lxr.free-electrons.com/source/kernel/Kconfig.preempt), который контролирует включение/выключение preemption. Когда мы включаем CONFIG_PREEMPT, автоматически включается CONFIG_PREEMPT_COUNT (см. Kconfig.preempt). Когда PREEMPT отключен, вызовы заменяются барьером(), который только для сброса записи в DRAM. – Nithin