2012-07-17 12 views
11

İşte bir spin kilitleme uygulamam, ama kritik kodu koruyamadığı görünüyor. Uygulamamda yanlış bir şey mi var?Sıkma kilidimde bir sorun var mı?

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

Eklemem yukarıda. –

+0

Mükemmel; Muhtemelen hata değil, spin_destroy() işleviyle, spin_init() 'tarafından tahsis edilmeyen belleği boşaltmak benim için çok garip görünüyor. (Ayrıca bir 'spin_alloc()' işlevi var mı?) – sarnold

+0

spin_destory fazla olabilir. –

cevap

11

Kodunuz eşittir: Sen kodundan görebilirsiniz

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 */ 
} 

, save_old_value_at_eax hiçbir cpu xchg yaparken gerçek orijinal değerdir. Eski/orijinal değeri xchg yönergesiyle almalı, xchg'u gerçekleştirmeden önce kaydetmelisiniz. ("gerçek eski/orjinal değer değil" anlamına gelir, eğer başka bir CPU kilidi saklarsa bu CPU değeri kaydeder ama bu CPU xchg komutunu gerçekleştirmeden önce, bu CPU yanlış eski değeri alır ve kilit başarılı, böylece iki CPU aynı anda CS'ye girer). Bir okuma-değiştirme-yazma talimatını üç talimata ayırdınız, üç talimatın tümü atomik değildir (kilit önekini xchg'ye taşımanız bile).

Sana kilit önek BÜTÜN üç talimatları kilitlenir, ama aslında kilit önek yalnızca bağlı olduğu tek talimat (bütün talimatlar eklenebilir değil) için kullanılabilecek düşünce tahmin Ve biz değiliz xchg için SMP üzerinde kilit önekine ihtiyacınız var. linux_kernel_src/kemer alıntı/x86 ///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. 
*/ 

Benim önerileri şunlardır:

  1. KENDİNİZİ TEKRAR YAPMAYIN, linux çekirdeğinin döndürme kilit kullanın.
  2. KENDİNİZİ TEKRARLAMAYIN, eğer bir döndürme kilidi uygulamak istiyorsanız, lütfen linux çekirdeğin xchg(), cmpxchg() öğesini kullanın.
  3. Yönergeler hakkında daha fazla bilgi edinin. Linux çekirdeğinin nasıl uygulandığını da öğrenebilirsiniz.
2

Sorun şu ki, kilitleme yönergesi öneki yalnızca aşağıdaki yönergede geçerlidir, bu nedenle değişimin atomik olmadığını unutmayın. Daha fazla bilgi için bu diğer cevaba bakın: What does the "lock" instruction mean in x86 assembly?

Kilit komutunun önekini xchg'ye taşıdığınızda bence işe yarayacaktır.

düzenleme: Ben orijinal cevap aslında yanlış olduğunu düşünüyorum http://locklessinc.com/articles/locks/

Not ayrıca hafıza 386 beri otomatik başvuruda bulunulan kilitli xchg gösterileri googling: Bu kullanışlı (gcc mecliste örnek atom değişim) olabilir. için