11

これが私のスピンロックの実装ですが、重要なコードを保護できないようです。私の実装に何か問題がありますか?

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);
}
4

1 に答える 1

12

あなたのコードは次のようになります:

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ように、CPU が xchg を実行している間は実際の元の値ではありません。xchg を実行する前に保存するのではなく、 xchg 命令によって古い/元の値を取得する必要があります。(「実際の古い/元の値ではない」とは、この CPU が値を保存した後、この CPU が xchg 命令を実行する前に別の CPU がロックを取得した場合、この CPU は間違った古い値を取得し、ロックが成功したため、2 つの CPU が同時に CS に入ります)。read-modify-write 命令を 3 つの命令に分けました。3 つの命令全体はアトミックではありません (ロック プレフィックスを xchg に移動しても)。

ロック プレフィックスは 3 つの命令全体をロックすると思っていたと思いますが、実際にはロック プレフィックスはそれがアタッチされている唯一の命令にしか使用できません (すべての命令をアタッチできるわけではありません)。xchg の SMP ではロック プレフィックスは必要ありません。 . 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.
 */

私の提案:

  1. 同じことを繰り返さないでください。Linux カーネルのスピン ロックを使用してください。
  2. スピンロックを実装したい場合は、Linux カーネルの xchg()、cmpxchg() を使用してください。
  3. 指示の詳細をご覧ください。また、Linux カーネルがそれをどのように実装しているかを知ることもできます。
于 2012-07-17T03:39:33.077 に答える