Während ich mir einige Treiberimplementierungen aus dem Atmel Software Framework ansah, stieß ich auf mehrere Fälle, in denen sie eine Speicherbarriere verwendeten.Atmel-Treiber und GCC-Speicherbarriere Anwendungsfall
Barrier Definition:
#define barrier() asm volatile("" ::: "memory")
Beispiel 1 (Interrupt-Hilfsfunktionen):
static inline void cpu_irq_restore(irqflags_t flags)
{
barrier();
SREG = flags;
}
Diese Barriere macht Sinn für mich. Da cpu_irq_restore
implizit inlined wird, verhindert es, dass die kritische SREG-Zuweisung (von einer Ausführungsreihenfolge aus gesehen) von der tatsächlichen Funktionsaufrufposition neu geordnet wird.
Als Nebenbemerkung: SREG
wird als ein Spezialfunktionsregister definiert ist definiert als:
#define _SFR_MEM8(mem_addr) (*(volatile uint8_t *)(mem_addr))
Beispiel 2 (von AVR TWI Treiber):
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;
}
Diese zweite Anwendungsfall jedoch ist mir nicht klar. Auf welche Weise könnte der Compiler diesen Code optimieren, so dass er ohne die bricht?
Ich glaube, ich verstehe die grundlegenden Überlegungen hinter Software-Speicherbarrieren nach dem Lesen this article.
Könnte jemand bitte die Gründe für die Verwendung der Barriere im zweiten Beispiel erklären?
Atmel Staaten in der Artikel gemocht: "Beachten Sie, dass auch eine flüchtige ASM-Anweisung relativ zu anderen Code, einschließlich über springen Anweisungen bewegt werden kann. [...] Ebenso können Sie nicht erwarten eine Folge von flüchtigen ASM Anweisungen zu bleib perfekt konsekutiv. " Unter welchen Umständen ist mir nicht ganz klar. –
Ich stimme zu, dass im ersten Beispiel eine zweite Barriere nach der SREG-Zuweisung sinnvoll wäre. –
Ich bin mir nicht sicher über die 'twim_idle()'. Es greift tatsächlich auf Register zu, aber der Compiler darf nicht nur die logische Reihenfolge dieser beiden while-Schleifen reorganisieren, oder? Wenn das der Fall ist, müsste man diese Art von Problem die ganze Zeit berücksichtigen. Da sie jedoch barrier() verwendet haben, ist entweder etwas an diesem Code spezifisch oder es ist einfach fehl am Platz und nicht erforderlich. –