hotspot/src/os/linux/vm/os_linux.cpp
void os::PlatformEvent::park() { // AKA "down()"
{- -------------------------------------------
(1) (コメントによると
os::PlatformEvent::park() を呼び出していいのは
この os::PlatformEvent オブジェクトに関連付いているスレッドだけ.
それを確かめる為の assert を入れたい, とのこと)
---------------------------------------- -}
// Invariant: Only the thread associated with the Event/PlatformEvent
// may call park().
// TODO: assert that _Assoc != NULL or _Assoc == Self
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
int v ;
{- -------------------------------------------
(1) Atomic::cmpxchg() で _Event フィールドの値を 1デクリメントする.
(Atomic::cmpxchg() は失敗することもあるが, 成功するまで繰り返す)
---------------------------------------- -}
for (;;) {
v = _Event ;
if (Atomic::cmpxchg (v-1, &_Event, v) == v) break ;
}
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
guarantee (v >= 0, "invariant") ;
{- -------------------------------------------
(1) もし変更前の _Event フィールドの値が 0 だった場合は,
pthread_cond_wait() を呼んで
誰かが unpark() してくれるまで眠りにつく.
(なお, 以下の処理は _mutex で排他された critical section 内で行う)
(間違って起きてしまうこともあるので,
目が覚めた後で _Event フィールドもチェックしている.
_Event フィールドが負値のままであれば,
0 以上の値になるまで pthread_cond_wait() を呼び続ける.)
(なお, 眠っているスレッドがいることを unpark() する側に伝えるために,
眠りにつく前に _nParked フィールドの値をインクリメントし,
unpark() されたら _nParked フィールドの値を戻している.)
(unpark() されて待機が解けたら, _Event フィールドの値は 0 にしている.
なお, この _Event フィールドのクリア処理は critical section 内で行っているが,
これは pthread_mutex_unlock() の後ろに回すとメモリバリアを置く必要があるから, との理由らしい.)
---------------------------------------- -}
if (v == 0) {
// Do this the hard way by blocking ...
int status = pthread_mutex_lock(_mutex);
assert_status(status == 0, status, "mutex_lock");
guarantee (_nParked == 0, "invariant") ;
++ _nParked ;
while (_Event < 0) {
status = pthread_cond_wait(_cond, _mutex);
// for some reason, under 2.7 lwp_cond_wait() may return ETIME ...
// Treat this the same as if the wait was interrupted
if (status == ETIME) { status = EINTR; }
assert_status(status == 0 || status == EINTR, status, "cond_wait");
}
-- _nParked ;
// In theory we could move the ST of 0 into _Event past the unlock(),
// but then we'd need a MEMBAR after the ST.
_Event = 0 ;
status = pthread_mutex_unlock(_mutex);
assert_status(status == 0, status, "mutex_unlock");
}
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
guarantee (_Event >= 0, "invariant") ;
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.