2016-03-03 15 views
5

Dato che il mio compilatore non supporta ancora C++ 11 e std :: atomic, sono costretto a implementarlo manualmente tramite la coppia ldrex-strex.Atomic int64_t su ARM Cortex M3

La mia domanda è: qual è il modo corretto di "atomicamente" leggere-modificare-scrivere int64_t con ldrex e strex?

soluzione semplice come questo non sembra funzionare (uno dei STREXW restituisce 1 per tutto il tempo):

volatile int64_t value; 
int64_t temp; 

do 
{ 
    int32_t low = __LDREXW((uint32_t *)&value); 
    int32_t high = __LDREXW(((uint32_t *)&value)+1); 

    temp = (int64_t)low | ((int64_t)high<<32); 
    temp++;  

} while(__STREXW(temp, (uint32_t *)&value) | __STREXW(temp>>32, ((uint32_t *)&value)+1)); 

non ho trovato nulla circa parecchi LDREX sequenziale o istruzioni STREX indicando varie strade il manuale ma mi è sembrato che fosse permesso.

In caso contrario più thread non sarebbero in grado di modificare due diverse variabili atomiche in alcuni scenari.

+1

è GCC? considerare gli atomici integrati GCC? – user3528438

+0

GCC per ARM ora ha il supporto per std :: atomic. No, non è GCC, è Keil armcc. – Amomum

+0

Vedere: [ARM AN321 - Barriere di memoria Cortex-M] (http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0321a/BIHEADII.html). Atomic è una parola un po 'sovraccaricata. Le cose non possono accadere atomicamente nell'universo. Sono atomici contro qualche set di componenti elettronici; linea principale/interrupt, SMP, dispositivo su un bus, ecc. Qual è esattamente il tuo problema? Devi descriverlo meglio. –

risposta

4

Questo non funzionerà mai, perché non è possibile nidificare esclusive in questo modo. Per quanto riguarda l'implementazione, il monitor esclusivo locale Cortex-M3 non tiene nemmeno traccia di un indirizzo - the exclusive reservation granule is the entire address space - quindi l'ipotesi di tracciare ogni parola separatamente è già valida. Tuttavia, non c'è nemmeno bisogno di prendere in considerazione eventuali dettagli di implementazione, perché l'architettura regole già esplicitamente il back-to-back strex:

If two STREX instructions are executed without an intervening LDREX the second STREX returns a status value of 1. This means that:

  • Every STREX must have a preceding LDREX associated with it in a given thread of execution.
  • It is not necessary for every LDREX to have a subsequent STREX .

Dal Cortex-M3 (e ARMv7-M in generale) doesn' t avere ldrexd come ARMv7-A, dovrai usare un blocco separato per controllare tutti gli accessi alla variabile, o semplicemente disabilitare gli interrupt attorno al read-modify-write. Se possibile, sarebbe davvero meglio riprogettare le cose non avendo bisogno di un tipo atomico a 64 bit, dato che si otterrebbe comunque solo l'atomicità rispetto ad altri thread sullo stesso core - semplicemente non si può fare 64 operazione bit atomica dal punto di vista di un agente esterno come un controller DMA.

+0

Avevo paura di ciò. Quindi, se lo sto facendo adesso, _any_ ldrex resetterà il monitor esclusivo per _every other_ ldrex? – Amomum

+0

Grazie, ora ho capito! – Amomum

+0

@Amomum Dal suo aspetto, v7-M non ha nemmeno la distinzione del monitor locale/globale - si legge come una versione ridotta della macchina dello stato del monitor locale v7-A. Immagino che in pratica l'hardware probabilmente non si preoccupi nemmeno di tenere traccia di un indirizzo e cancella semplicemente lo stato esclusivo su qualsiasi accesso alla memoria. – Notlikethat

1

Vorrei solo vedere come gcc lo fa e utilizzare le stesse sequenze di istruzioni.

gcc 4.8.2 pretese per implementare std::atomic<int64_t> con is_lock_free() restituendo vero, anche con -mcpu=cortex-m3. Sfortunatamente, non funziona davvero. Rende il codice che non si collega o non funziona, perché non c'è implementazione delle funzioni di aiuto che tenta di usare. (Grazie a @Notlikethat per averlo provato.)

Here's the test code I tried. Vedi una vecchia versione di questa risposta se quel collegamento è morto. Lascio questa risposta nel caso in cui l'idea sia utile per chiunque nei casi correlati in cui gcc fa codice.

+0

Ho provato quello che hai suggerito con gcc 5.2.1 per arm e ho avuto l'errore linker: "e: \ gcc-arm-none-eabi-5_2-2015q4-20151219-win32 \ arm-none-eabi \ include \ C++ \ 5.2. 1 \ bits/atomic_base.h: 514: riferimento non definito a '__atomic_fetch_add_8 '" durante la creazione di std :: atomic ; std :: atomic ha funzionato come previsto. Sembra giusto. – Amomum

+0

@Amomum: la tua installazione gcc funziona normalmente quando ha bisogno di funzioni di aiuto da 'libgcc.a'? Questo è un bug gcc o un problema del compilatore installato in modo errato. La divisione a 64 bit probabilmente chiamerà una funzione di aiuto simile. La divisione –

+0

di uint64_t chiama __aeabi_uldivmod come previsto. Non penso che sia stato un bug, forse non c'è davvero modo di implementare uint64_t atomico?È perfettamente normale che alcune architetture non abbiano uint8_t per esempio (se CHAR_BITS è maggiore di 8); quindi non penso che non avere __atomic_fetch_add_8 sia un grosso problema. – Amomum