[英]Why a "barrier()" is enough for disabling or enabling the preemption?
從 Linux 內核代碼中,我可以看到preempt_enable()
和preempt_disable()
只是barrier()
:
#define preempt_disable() barrier()
#define preempt_enable() barrier()
我無法理解。 為什么僅僅一個barrier()
就足以禁用或啟用搶占?
因為您沒有使用搶占式內核。 但是,用戶空間進程是可搶占的。
檢查內核配置中是否設置了 CONFIG_PREEMPT_VOLUNTARY。
在內核V4.3,為正確界定preempt_enable
是在這里:
#define preempt_enable() \
do { \
barrier(); \
if (unlikely(preempt_count_dec_and_test())) \
__preempt_schedule(); \
} while (0)
同樣對於preempt_disable
在這里:
#define preempt_disable() \
do { \
preempt_count_inc(); \
barrier(); \
} while (0)
preempt_enable
在啟用搶占之前插入優化屏障,而preempt_disable
在搶占計數器遞增后插入屏障。 然而,根據評論,當不涉及搶占而只是保護被搶占區域的障礙時。
編輯:分別在 UP 和非搶占中,自旋鎖和搶占禁用/啟用點被完全排除,因為沒有常規代碼可以達到它們旨在防止的那種並發性。
然而,雖然沒有正規的代碼,可能導致調度,我們最終會遇到一些特殊的(字面!)的代碼,可以做到這一點,而且我們需要確保就都不曾搬進由編譯器的關鍵區域。
特別是 get_user() 和 put_user() 通常是作為內聯 asm 語句實現的(即使內聯 asm 可能會發出 call 指令來調用外線),並且顯然會導致頁面錯誤和 IO 結果. 如果該內聯匯編已被安排到搶占安全(或自旋鎖保護)代碼區域的中間,我們顯然會失敗。
現在,誠然,這是不太可能實際上不會發生,我們還沒有看到與此相關的實際錯誤的例子。 但部分正是因為它很難觸發並且由此產生的錯誤非常微妙,所以我們應該格外小心才能做到這一點。
所以確保即使搶占被禁用,並且我們不必生成任何實際代碼來明確告訴系統我們處於搶占禁用區域,我們至少需要告訴編譯器不要在周圍移動任何東西臨界區。 來源
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.