Domanda

Dato che, sulla corteccia del braccio M3, posso:

  • Leggi atomicamente un solo bit
  • Imposta atomicamente un solo bit
  • Atomicamente cancellare un singolo bit

Come posso combinarli per un set di operazioni in stile mutex:

try lock
take lock
release lock

Sembra che try_lock o take_lock richiederebbe due operazioni che non sarebbero atomiche.

Ho bisogno di più controllo per raggiungere questo obiettivo? Disabilitare gli interrupt globali lo farebbero, ma sembra che ci dovrebbe essere un approccio più chirurgico.

È stato utile?

Soluzione

Tuo rwl_TryLock() Non restituisce necessariamente un errore se il blocco è già trattenuto quando viene chiamato (il compilatore dovrebbe dare almeno un avviso su un percorso del codice che non ha valore di reso). Prova quanto segue:

int rwl_TryLock(volatile uint32_t *lock, int who){

    Var_SetBit_BB((uint32_t)lock, who);
    if(*lock == (1<<who)){ // check that we have exclusive access
        // got the lock!
        return 1;
    } 

    // do not have the lock
    Var_ResetBit_BB((uint32_t)lock, who); // clear the lock flag
    return 0;
}

Si noti che quanto sopra non funzionerà per rivendicare in modo ricorsivo lo stesso blocco (cioè, se l'attività specificata da who == 1 Ha già il blocco e cerca di rivendicarlo di nuovo, il codice sopra non funzionerà correttamente), ma era vero anche per il tuo originale.

Inoltre, gli interrupt possono essere disabilitati/abilitati sulla Cortex M3 abbastanza rapidamente (è un semplice aggiornamento per un registro NVIC). Sei sicuro che il tuo sistema non possa vivere con altri cicli di latenza di interruzione per mantenere il codice per la gestione delle strutture dei dati di blocco semplice (il che generalmente significa più facile da risolvere)?

Altri suggerimenti

Bit banding non funzionerà per questa situazione. È solo un modo davvero ordinato di impostare i bit nei file di registro dei dispositivi e nella tua memoria. Utilizza le istruzioni esclusive e memorizza esclusive per implementare il tuo semaforo/mutex. Ecco un documento di esempio che è possibile utilizzare che implementa un semaforo usando queste istruzioni e descrive in dettaglio come funziona.

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0439b/chddigac.html

Detto questo, puoi ridurre l'impronta di memoria dei tuoi mutex usando la fascia di bit ...

Alcuni per informazioni dopo alcune ricerche:

"Arm Cortex-M3 Bit-Banding MicroController's MicroController Core offre un altro modo per implementare i semafori. L'accesso a scrivere alle variabili nella regione alias Bit-Band provoca un accesso atomico a lettura-modifica-scrive a una posizione di memoria nella regione della banda bit in Livello del bus di sistema. Come si traduce in semafori? Una variabile nella regione della banda bit potrebbe fungere da contenitore per i semafori. Ogni cliente "possiede" un po 'in quel contenitore. Ogni volta che un cliente deve rivendicare il semaforo, imposta il proprio Bit scrivendo un 1 nella posizione corrispondente nella regione alias Bit-Band. Leggerebbe quindi il contenitore (regione della banda bit) e verificherebbe che non sono fissati altri bit, il che significa che il cliente ha recitato in modo contrario il semaforo. Nel caso Sono impostati altri bit, il cliente dovrebbe cancellare di nuovo il proprio bit e riprovare (forse dopo aver aspettato). "(fonte)

Ecco la mia interpretazione grezza (non testata):

/*
 * Frees a lock.
 *
 * @note lock must point to a fully aligned 32 bit integer.
 * (atomically set to 0)
 *
 * @returns 1 if successfull
 */
int rwl_FreeLock(volatile uint32_t *lock){
    *lock = 0;
    return 1; // always successful
}

/*
 * Attempts to acquire a lock
 * @param who is the client taking the lock
 * @lock pointer to the mutex (uint32_t value in memory)
 * @note lock must point to a fully aligned 32 bit integer.
 * (atomically set to 1 only if set to 0)
 */
int rwl_TryLock(volatile uint32_t *lock, int who){
    // initial check of lock
    if(*lock == 0){
        Var_SetBit_BB((uint32_t)lock, who);
        if(*lock == (1<<who)){ // check that we still have exclusive access
            // got the lock!
            return 1;
        } else {
                    // do not have the lock
            Var_ResetBit_BB((uint32_t)lock, who); // clear the lock flag
            return 0;
        }
    }
}

VAR_SET_BB / VAR_RESET_BB: SET / CONTRO un bit usando la fascia di bit. (atomico)

Comunque, non funziona!!!

Non ho mai usato il banding bit sul braccio; La mia inclinazione invece sarebbe quella di utilizzare il carico-esclusivo/store-condizionata per tutte queste operazioni. Utilizzare un ciclo per caricare il vecchio valore, calcolare il nuovo valore e utilizzare un negozio condizionale per scriverlo. Loop fino a quando il negozio condizionale non riesce (che probabilmente sarà la seconda volta, se non è il primo).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top