[英]Atmel driver and GCC memory barrier use case
在查看Atmel軟件框架中的一些驅動程序實現時,我遇到了幾種使用內存屏障的情況。
屏障定義:
#define barrier() asm volatile("" ::: "memory")
示例1 (中斷幫助器函數):
static inline void cpu_irq_restore(irqflags_t flags)
{
barrier();
SREG = flags;
}
這個障礙對我來說很有意義。 由於cpu_irq_restore
隱式內聯,因此可以防止從實際函數調用位置對關鍵的SREG分配(從執行順序角度而言)重新排序。
附帶說明: SREG
被定義為特殊功能寄存器,定義為:
#define _SFR_MEM8(mem_addr) (*(volatile uint8_t *)(mem_addr))
示例2 (來自AVR TWI驅動程序):
static inline status_code_t twim_release(void)
{
/* First wait for the driver event handler to indicate something
* other than a transfer in-progress, then test the bus interface
* for an Idle bus state.
*/
while (OPERATION_IN_PROGRESS == transfer.status);
while (! twim_idle(transfer.bus)) { barrier(); }
status_code_t const status = transfer.status;
transfer.locked = false;
return status;
}
但是,第二個用例對我來說還不清楚。 編譯器可以通過哪種方式優化該代碼,從而在沒有barrier()
情況下中斷代碼?
閱讀完本文后,我想我理解了軟件內存障礙背后的基本原因。
在第二個示例中使用障礙的背后原因是什么?
twim_idle
函數可能會執行類似讀取與TWI相關的特殊功能寄存器的值並檢查其中某些位的操作。 沒有障礙,危險是編譯器可能會優化該寄存器的讀取並將其移至第二個循環之前。 因此,第二個循環將如下所示:
bool idle = twim_idle(transfer.bus);
while (!idle);
這種優化可以使循環更快,並且對讀取普通變量有效,但是在這種情況下顯然會引起問題。 在循環中放置障礙應防止發生優化。
實際上,您不需要內存障礙,因為所有特殊功能寄存器都已使用volatile
關鍵字進行了限定,因此編譯器將不會嘗試緩存對其的訪問。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.