hotspot/src/os/solaris/vm/os_solaris.cpp
void Parker::park(bool isAbsolute, jlong time) {
{- -------------------------------------------
(1) もし _counter の値が 1 であれば (= 既に unpark() が呼ばれていれば),
単に _counter を 0 にするだけでいい.
ここでリターン.
(なお, ここから先が Parker で保護された critical section ということになるので,
OrderAccess::fence() も張っておく)
---------------------------------------- -}
// Optional fast-path check:
// Return immediately if a permit is available.
if (_counter > 0) {
_counter = 0 ;
OrderAccess::fence();
return ;
}
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
// Optional fast-exit: Check interrupt before trying to wait
Thread* thread = Thread::current();
assert(thread->is_Java_thread(), "Must be JavaThread");
JavaThread *jt = (JavaThread *)thread;
{- -------------------------------------------
(1) 処理対象のスレッドに対して java.lang.Thread.interrupt() が呼ばれていた場合は,
待機する必要は無いので, ここでリターン.
(interrupt されたかどうかは後でもチェックしているのでこの処理はなくてもいいが,
ここでチェックに引っかかれば ThreadBlockInVM による状態遷移が必要なくなる, という最適化)
---------------------------------------- -}
if (Thread::is_interrupted(thread, false)) {
return;
}
{- -------------------------------------------
(1) 引数で指定された待ち時間(time)をチェックする. 以下の場合はここでリターン.
* 指定された待ち時間が負値の場合
* 指定された待ち時間が絶対時間であり, その時間が現在時刻よりも古い場合
---------------------------------------- -}
// First, demultiplex/decode time arguments
timespec absTime;
if (time < 0 || (isAbsolute && time == 0) ) { // don't wait at all
return;
}
{- -------------------------------------------
(1) unpackTime() を呼んで, 指定された待ち時間の値(time)を絶対時刻に調整しておく.
---------------------------------------- -}
if (time > 0) {
// Warning: this code might be exposed to the old Solaris time
// round-down bugs. Grep "roundingFix" for details.
unpackTime(&absTime, isAbsolute, time);
}
{- -------------------------------------------
(1) (コメントによると, デッドロックに注意とのこと.
Parker の _mutex を握った状態で Threads_lock でブロックしてはいけない.
Safepoint が開始されている場合には, ThreadBlockInVM のコンストラクタやデストラクタでは
Threads_lock を確保するかもしれない.)
---------------------------------------- -}
// Enter safepoint region
// Beware of deadlocks such as 6317397.
// The per-thread Parker:: _mutex is a classic leaf-lock.
// In particular a thread must never block on the Threads_lock while
// holding the Parker:: mutex. If safepoints are pending both the
// the ThreadBlockInVM() CTOR and DTOR may grab Threads_lock.
{- -------------------------------------------
(1) ThreadBlockInVM で JavaThread の状態を変更しておく.
---------------------------------------- -}
ThreadBlockInVM tbivm(jt);
{- -------------------------------------------
(1) 処理対象のスレッドに対して java.lang.Thread.interrupt() が呼ばれていた場合は, ここでリターンする.
そうでなければ, os::Solaris::mutex_trylock() で _mutex を取得する.
(なお, _mutex のロック処理が unpark() 処理と競合した場合 (= os::Solaris::mutex_trylock() が非ゼロを返した場合) は,
ここでリターンする.)
---------------------------------------- -}
// Don't wait if cannot get lock since interference arises from
// unblocking. Also. check interrupt before trying wait
if (Thread::is_interrupted(thread, false) ||
os::Solaris::mutex_trylock(_mutex) != 0) {
return;
}
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
int status ;
{- -------------------------------------------
(1) もし _counter の値が 1 であれば (= 既に unpark() が呼ばれていれば),
単に _counter を 0 にするだけでいい.
os::Solaris::mutex_unlock() で _mutex を解放した後, ここでリターン.
(なお, ここから先が Parker で保護された critical section ということになるので,
OrderAccess::fence() も張っておく)
---------------------------------------- -}
if (_counter > 0) { // no wait needed
_counter = 0;
status = os::Solaris::mutex_unlock(_mutex);
assert (status == 0, "invariant") ;
OrderAccess::fence();
return;
}
{- -------------------------------------------
(1) (デバッグ用の処理) (#ifdef ASSERT 時にのみ実行)
---------------------------------------- -}
#ifdef ASSERT
// Don't catch signals while blocked; let the running threads have the signals.
// (This allows a debugger to break into the running thread.)
sigset_t oldsigs;
sigset_t* allowdebug_blocked = os::Solaris::allowdebug_blocked_signals();
thr_sigsetmask(SIG_BLOCK, allowdebug_blocked, &oldsigs);
#endif
{- -------------------------------------------
(1) OSThreadWaitState で OSThread の状態を変更した後,
os::Solaris::cond_wait() または os::Solaris::cond_timedwait() を呼んで
誰かが unpark() してくれるまで眠りにつく.
(指定された待ち時間が 0 (= 無制限) であれば os::Solaris::cond_wait(),
そうでなければ os::Solaris::cond_timedwait() を呼び出す.)
(なお, ClearFPUAtPark オプションが指定されている場合は... #TODO)
#TODO JavaThread::set_suspend_equivalent() はどういう意味がある??
---------------------------------------- -}
OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
jt->set_suspend_equivalent();
// cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()
// Do this the hard way by blocking ...
// See http://monaco.sfbay/detail.jsf?cr=5094058.
// TODO-FIXME: for Solaris SPARC set fprs.FEF=0 prior to parking.
// Only for SPARC >= V8PlusA
#if defined(__sparc) && defined(COMPILER2)
if (ClearFPUAtPark) { _mark_fpu_nosave() ; }
#endif
if (time == 0) {
status = os::Solaris::cond_wait (_cond, _mutex) ;
} else {
status = os::Solaris::cond_timedwait (_cond, _mutex, &absTime);
}
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
// Note that an untimed cond_wait() can sometimes return ETIME on older
// versions of the Solaris.
assert_status(status == 0 || status == EINTR ||
status == ETIME || status == ETIMEDOUT,
status, "cond_timedwait");
{- -------------------------------------------
(1) (デバッグ用の処理) (#ifdef ASSERT 時にのみ実行)
---------------------------------------- -}
#ifdef ASSERT
thr_sigsetmask(SIG_SETMASK, &oldsigs, NULL);
#endif
{- -------------------------------------------
(1) _counter の値を 0 に戻し, _mutex を解放する.
(ここまでが _mutex で排他された処理)
---------------------------------------- -}
_counter = 0 ;
status = os::Solaris::mutex_unlock(_mutex);
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
assert_status(status == 0, status, "mutex_unlock") ;
{- -------------------------------------------
(1) 寝ている間に java.lang.Thread.suspend() で suspend 状態にされたかもしれないので,
目が覚めた後に JavaThread::handle_special_suspend_equivalent_condition() でチェックしておく.
もし suspend されていれば, JavaThread::java_suspend_self() でサスペンドが解除されるまで眠りにつく.
---------------------------------------- -}
// If externally suspended while waiting, re-suspend
if (jt->handle_special_suspend_equivalent_condition()) {
jt->java_suspend_self();
}
{- -------------------------------------------
(1) (なお, ここから先が Parker で保護された critical section ということになるので,
OrderAccess::fence() を張っておく)
---------------------------------------- -}
OrderAccess::fence();
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.