技術

[xv6 #40] Chapter 3 – Locking – Memory ordering

テキストの48〜49ページ

本文

この章では、プロセッサが、プログラムの中で現れる順番で一連の命令を開始し完了すると仮定する。
しかしながら多くのプロセッサは、より高いパフォーマンスを達成するために命令を順番通りには実行しない。(アウトオブオーダー実行)
ある命令が、その完了までに多くのサイクルを要する場合、他の命令とオーバーラップして実行しプロセッサのストールを避るために、プロセッサはその命令を早めに発行したいはずである。
例えば、プロセッサは直列に並んでいる命令Aと命令Bがお互いに依存してない事に気づき、命令Aを完了するときに命令Bも完了させるために、命令Aの前に命令Bを開始する。
しかしながら同時実行は、命令の並び替えによってソフトウェアに影響を与え、間違った振る舞いを発生させるかもしれない。

例えば、release関数がxchg命令を使わずにlk->lockedに0を割り当てる場合、何が起きるのか心配しなければならないだろう。
x86プロセッサは、世代によって保証するメモリの順序性に違いがあるため、この問題に対する答えは不明瞭である。
lk->locked=0がpopcli関数の後に並び替え可能だった場合、ロックが解放される前に他のスレッドで割り込みが有効になる可能性があるので、acquireは壊れるかもしれない。
(ここ特に訳に自信なし。原文: If lk->locked=0, were allowed to be re-ordered say after popcli, than acquire might break, because to another thread interrupts would be enabled before a lock is released.)
メモリの順序性に関する不明瞭なプロセッサの特性に頼るのを避けるため、xv6は、プロセッサが並び替えしない事を保証しなければならないxchg命令を使って、リスクを犯さないようにしている。

spinlock.cのrelease関数

// Release the lock.
void
release(struct spinlock *lk)
{
  if(!holding(lk))
    panic("release");

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

  // The xchg serializes, so that reads before release are 
  // not reordered after it.  The 1996 PentiumPro manual (Volume 3,
  // 7.2) says reads can be carried out speculatively and in
  // any order, which implies we need to serialize here.
  // But the 2007 Intel 64 Architecture Memory Ordering White
  // Paper says that Intel 64 and IA-32 will not move a load
  // after a store. So lock->locked = 0 would work here.
  // The xchg being asm volatile ensures gcc emits it after
  // the above assignments (and after the critical section).
  xchg(&lk->locked, 0);

  popcli();
}

感想

ロック機構は小さな穴さえ無いよう慎重に作られていますが、CPUのアウトオブオーダー実行の機能の差異によってロック機構の作り方次第では穴が出来ちゃうよ、という話ですかね。

release関数内の長いコメントにもより具体的に似たような事が書いてありますね。

コメントを残す

メールアドレスが公開されることはありません。



※画像をクリックして別の画像を表示