2012-07-17 13 views
11

Ecco la mia implementazione di uno spin lock, ma sembra che non possa proteggere il codice critico. C'è qualcosa di sbagliato nella mia implementazione?C'è qualcosa che non va con il mio spin lock?

static __inline__ int xchg_asm(int* lock, int val) 
{ 
    int ret; 
    __asm__ __volatile__(
    LOCK "movl (%1),%%eax; 
    xchg (%1),%2; 
    movl %%eax, %0" :"=m" (ret) :"d"(lock), "c"(val) 
); 
    return ret; 
} 
void spin_init(spinlock_t* sl) 
{ 
    sl->val = 0; 
} 
void spin_lock(spinlock_t* sl) 
{ 
    int ret; 
    do { 
    ret = xchg_asm(&(sl->val), 1); 
    } while (ret==0); 
} 

void spin_unlock(spinlock_t* sl) 
{ 
    xchg_asm(&(sl->val), 0); 
} 
+0

la mia aggiunta è sopra. –

+0

Eccellente; probabilmente non è l'errore, ma mi sembra molto strano per la funzione 'spin_destroy()' per liberare memoria non allocata da 'spin_init()'. (Esiste anche una funzione 'spin_alloc()'?) – sarnold

+0

spin_destory è in eccesso forse. –

risposta

11

il codice è uguale a:

static __inline__ int xchg_asm(int* lock, int val) { 
    int save_old_value_at_eax; 

    save_old_value_at_eax = *lock;  /* with a wrong lock prefix */ 
    xchg *lock with val and discard the original value of *lock. 
    return save_old_value_at_eax;   /* but it not the real original value of *lock */ 
} 

Si può vedere dal codice, save_old_value_at_eax c'è il vero valore originale mentre la CPU esegue xchg. Si dovrebbe ottenere il valore vecchio/originale con l'istruzione xchg, non salvandolo prima di eseguire xchg. ("non è il vero valore vecchio/originale" significa, se un'altra CPU prende il blocco dopo che questa CPU ha salvato il valore ma prima che questa CPU esegua l'istruzione xchg, questa CPU avrà il vecchio valore sbagliato, e pensa che abbia preso il blocco riuscito, quindi, due CPU entrano nel CS contemporaneamente). Hai separato un'istruzione read-modify-write in tre istruzioni, le tre istruzioni complete non sono atomiche (anche se sposti il ​​prefisso di blocco a xchg).

immagino si pensava il prefisso di blocco bloccherà l'INTERA tre istruzioni, ma in realtà il prefisso serratura può essere utilizzato solo per la sola istruzione di cui è attaccato (non tutte le istruzioni possono essere attaccati) E noi non serve il prefisso di blocco su SMP per xchg. Citazione di linux_kernel_src/arch/x86 // include/asm/cmpxchg.h

/* 
* Note: no "lock" prefix even on SMP: xchg always implies lock anyway. 
* Since this is generally used to protect other memory information, we 
* use "asm volatile" and "memory" clobbers to prevent gcc from moving 
* information around. 
*/ 

I miei suggerimenti:

  1. do not repeat yourself, si prega di utilizzare il blocco rotazione del kernel di Linux.
  2. NON RIPETERE TE STESSO, utilizzare xchg(), cmpxchg() del kernel Linux se si desidera implementare un blocco di selezione.
  3. Ulteriori informazioni sulle istruzioni. puoi anche scoprire come il kernel Linux lo implementa.
2

Credo che il problema è che il prefisso di istruzioni di blocco si applica solo alle seguenti istruzioni, quindi il tuo scambio non è atomico. Vedere questa altra risposta su SO per ulteriori dettagli: What does the "lock" instruction mean in x86 assembly?

Penso che se si sposta il prefisso di istruzione di blocco per xchg, funzionerà.

edit: Questo potrebbe essere utile (ad esempio lo scambio atomica in assemblea gcc): http://locklessinc.com/articles/locks/

Nota che penso che la mia risposta originale è effettivamente sbagliato, googling inoltre spettacoli che XCHG è bloccato se la memoria si fa riferimento automaticamente dal 386.

Problemi correlati