spinlock.c void release(struct spinlock *lk)

トップページ
jupiteroak.hatenablog.com


spinlock.c
https://github.com/mit-pdos/xv6-public/blob/master/spinlock.c#L46

void release(struct spinlock *lk)
{
  if(!holding(lk))
    panic("release");

  lk->pcs[0] = 0;
  lk->cpu = 0;

  // Tell the C compiler and the processor to not move loads or stores
  // past this point, to ensure that all the stores in the critical
  // section are visible to other cores before the lock is released.
  // Both the C compiler and the hardware may re-order loads and
  // stores; __sync_synchronize() tells them both not to.
  __sync_synchronize();

  // Release the lock, equivalent to lk->locked = 0.
  // This code can't use a C assignment, since it might
  // not be atomic. A real OS would use C atomics here.
  asm volatile("movl $0, %0" : "+m" (lk->locked) : );

  popcli();
}

release関数は、排他制御の対象となる共有資源に関連しているロックを解放します。

引数 struct spinlock *lk
解放対象となるロックのアドレスです。


処理の内容

ロックを既に解放していないことを確認する

if(!holding(lk))
   panic("release");

holding関数を呼び出して、現在この処理を実行しているプロセッサ(スレッド)が引数で渡されたロックlkを保持しているかどうかを確認します。
!holding(lk)が真となる場合→holding関数の戻り値が0の場合→ロックを保持していない場合は、panic関数を呼び出してメッセージを出力します。
!holding(lk)が偽となる場合→holding関数の戻り値が1の場合→ロックを保持している場合は、if文内の処理に入らず次の処理へ進みます。

リターンアドレスを記録している配列pcsの先頭要素を0で初期化する

lk->pcs[0] = 0;

ロックを保持しているプロセッサ(スレッド)への参照をなくす

lk->cpu = 0;

ロックを解放するので、現在この処理を実行しているプロセッサ(スレッド)への参照をなくすために、cpuメンバを0で初期化します。

メモリバリアを作成する

__sync_synchronize();

__sync_synchronizeは、この関数が定義された箇所を超えてコンパイラの最適化やプロセッサのアウトオブオーダーによる命令の並び替えが起こらないようにするために、メモリバリアを作成します。

ロックを解放する

asm volatile("movl $0, %0"
              : "+m" (lk->locked)
              :
              );

ロックlkのlockedメンバの値を0にします。

ハードウェア割り込みを有効化する

popcli();

pushcliで行った処理を復元し、ハードウェア割り込みを有効化します。