2012-07-17 23 views
11

Aquí está mi implementación de un bloqueo de giro, pero parece que no puede proteger el código crítico. ¿Hay algún problema con mi implementación?¿Hay algún problema con mi bloqueo de giro?

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

mi adición está arriba. –

+0

Excelente; probablemente no sea el error, pero me parece muy extraño que la función 'spin_destroy()' libere la memoria que no fue asignada por 'spin_init()'. (¿Hay una función 'spin_alloc()' también?) – sarnold

+0

spin_destory es quizás exceso. –

Respuesta

11

Su código es igual 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 */ 
} 

Se puede ver en el código, save_old_value_at_eax no es el valor original real, mientras que la CPU realice xchg. Debe obtener el valor antiguo/original mediante la instrucción xchg, no guardándolo antes de realizar xchg. ("no es el verdadero valor original/antiguo" significa, si otra CPU toma el bloqueo después de que esta CPU guarda el valor, pero antes de que esta CPU realice la instrucción xchg, esta CPU obtendrá el valor antiguo incorrecto, y cree que tomó el bloqueo exitoso, por lo tanto, dos CPU ingresan a la CS al mismo tiempo). Has separado una instrucción de lectura-modificación-escritura en tres instrucciones, las tres instrucciones completas no son atómicas (incluso si mueves el prefijo de bloqueo a xchg).

supongo que pensó el prefijo de bloqueo bloqueará el TODA tres instrucciones, pero en realidad prefijo de bloqueo sólo puede ser utilizado para la única instrucción que se adjunta (no todas las instrucciones se pueden unir) y nosotros no necesita el prefijo de bloqueo en SMP para xchg. Presupuesto de 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. 
*/ 

Mis sugerencias:

  1. No te repitas, por favor utilice el bloqueo de giro del núcleo de Linux.
  2. NO SE REPITA, utilice xchg(), cmpxchg() del kernel de Linux si desea implementar un bloqueo de giro.
  3. Más información sobre instrucciones. También puede averiguar cómo lo implementa el kernel de Linux.
2

Creo que el problema es que el prefijo de instrucción de bloqueo solo se aplica a las siguientes instrucciones, por lo que su intercambio no es atómico. Vea esta otra respuesta en SO para más detalles: What does the "lock" instruction mean in x86 assembly?

Creo que si mueve el prefijo de instrucción de bloqueo al xchg, funcionará.

edición: Esto podría ser útil (ejemplo de cambio atómica en el montaje gcc): http://locklessinc.com/articles/locks/

Tenga en cuenta que creo que mi respuesta original es realmente mal, buscando en Google muestra además que xchg se bloquea si la memoria se hace referencia de forma automática desde 386.

Cuestiones relacionadas