hotspot/src/os/solaris/vm/os_solaris.cpp
void os::PlatformEvent::unpark() {
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
int v, AnyWaiters;
{- -------------------------------------------
(1) _Event の値が 0 より大きければ (= つまり 1 であれば), ここでリターンする.
(なお, このプロセッサの store buffer 内の値を見てしまう恐れがあるので,
OrderAccess::fence() を張って確認している)
そうでなければ Atomic::cmpxchg() で _Event の値を 1 増加させておく.
(Atomic::cmpxchg() が失敗した場合は, 成功するまで以上の処理を繰り返す)
(なお, コメントには他の実装方法も幾つか書かれている.
Swap でもいい, とか, CAS でもいい, とか.)
---------------------------------------- -}
// Increment _Event.
// Another acceptable implementation would be to simply swap 1
// into _Event:
// if (Swap (&_Event, 1) < 0) {
// mutex_lock (_mutex) ; AnyWaiters = nParked; mutex_unlock (_mutex) ;
// if (AnyWaiters) cond_signal (_cond) ;
// }
for (;;) {
v = _Event ;
if (v > 0) {
// The LD of _Event could have reordered or be satisfied
// by a read-aside from this processor's write buffer.
// To avoid problems execute a barrier and then
// ratify the value. A degenerate CAS() would also work.
// Viz., CAS (v+0, &_Event, v) == v).
OrderAccess::fence() ;
if (_Event == v) return ;
continue ;
}
if (Atomic::cmpxchg (v+1, &_Event, v) == v) break ;
}
{- -------------------------------------------
(1) 変更前の _Event の値が負値だった場合は
park() で待機しているスレッドがいる(かもしれない)ので,
os::Solaris::cond_signal() で起こしてやる.
(ただし, _nParked フィールドが 0 の場合は起床処理は行わない.
本当に寝ているスレッドがいる場合には _nParked フィールドが 1 以上になっているはずなので.
See: os::PlatformEvent::park()
ついでに, この _nParked フィールドの読み取りは
_mutex で保護された critical section 内で行う)
---------------------------------------- -}
// If the thread associated with the event was parked, wake it.
if (v < 0) {
int status ;
// Wait for the thread assoc with the PlatformEvent to vacate.
status = os::Solaris::mutex_lock(_mutex);
assert_status(status == 0, status, "mutex_lock");
AnyWaiters = _nParked ;
status = os::Solaris::mutex_unlock(_mutex);
assert_status(status == 0, status, "mutex_unlock");
guarantee (AnyWaiters == 0 || AnyWaiters == 1, "invariant") ;
if (AnyWaiters != 0) {
// We intentional signal *after* dropping the lock
// to avoid a common class of futile wakeups.
status = os::Solaris::cond_signal(_cond);
assert_status(status == 0, status, "cond_signal");
}
}
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.