hotspot/src/share/vm/runtime/thread.cpp
void Thread::SpinAcquire (volatile int * adr, const char * LockName) {
{- -------------------------------------------
(1) CAS により, 引数で指定されたアドレス(adr)の値を 1 に書き換えてみる
(元々の値は 0 と想定. つまりロックされていない状態と想定).
書き換えが成功したら, ここでリターン.
---------------------------------------- -}
if (Atomic::cmpxchg (1, adr, 0) == 0) {
return ; // normal fast-path return
}
{- -------------------------------------------
(1) (以降はロックされていた場合(競合が起きた場合)の処理)
---------------------------------------- -}
// Slow-path : We've encountered contention -- Spin/Yield/Block strategy.
{- -------------------------------------------
(1) (トレース出力)
---------------------------------------- -}
TEVENT (SpinAcquire - ctx) ;
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
int ctr = 0 ;
int Yields = 0 ;
{- -------------------------------------------
(1) adr の値が 0 になるまで以下の while ループ内で待機し,
0 になったら Atomic::cmpxchg() で 1 への書き換えを試みる.
失敗したらまた while ループに戻る.
以上の流れを, Atomic::cmpxchg() による書き換えが成功するまで続ける.
なお, while ループ内での待機処理では, 以下のように処理を使い分けている.
* マルチプロセッサでない場合 (= os::is_MP() が false の場合)
* ループを始めてから 4回目以内 (= 以下の Yields が 5 未満の場合)
os::NakedYield() で待機する.
* 5 ループ目以降
カレントスレッドの _ParkEvent に対して os::PlatformEvent::park() を呼び出して待機.
* マルチプロセッサの場合 (= os::is_MP() が true の場合)
* ループを始めてから 4095回目以内 (= 以下の ctr が 0xFFF 未満の場合)
SpinPause() で待機する.
* それ以降
マルチプロセッサでない場合と同じ.
---------------------------------------- -}
for (;;) {
while (*adr != 0) {
++ctr ;
if ((ctr & 0xFFF) == 0 || !os::is_MP()) {
if (Yields > 5) {
// Consider using a simple NakedSleep() instead.
// Then SpinAcquire could be called by non-JVM threads
Thread::current()->_ParkEvent->park(1) ;
} else {
os::NakedYield() ;
++Yields ;
}
} else {
SpinPause() ;
}
}
if (Atomic::cmpxchg (1, adr, 0) == 0) return ;
}
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.