Пока я смотрел некоторые версии драйверов от Atmel Software Framework, я столкнулся с несколькими случаями, когда они использовали барьер памяти.Драйвер Atmel и случай использования защитного барьера GCC
определение Барьерный:
#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()
?
Я думаю, что понимаю основные соображения по поводу барьеров программной памяти после чтения this article.
Не могли бы вы объяснить причину использования барьера во втором примере?
Atmel заявляет в любимой статье: «Обратите внимание, что даже изменчивая инструкция asm может перемещаться относительно другого кода, включая инструкции перехода. [...] Аналогично, вы не можете ожидать последовательность волатильных команд asm для остаются совершенно последовательными ». Мне не совсем понятно, при каких обстоятельствах. –
Я согласен, что в первом примере будет иметь смысл второй барьер после назначения SREG. –
Я не уверен в 'twim_idle()'. Он действительно получает доступ к регистрам, но компилятору не разрешается просто реорганизовать логическую последовательность этих двух циклов, или это так? Если это так, нужно было бы постоянно рассматривать эту проблему. Однако, поскольку они использовали барьер(), либо это что-то конкретное в отношении этого кода, либо его просто неуместно и не требуется. –