hotspot/src/os/linux/vm/os_linux.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) (変数宣言など)
---------------------------------------- -}
Thread* thread = Thread::current();
assert(thread->is_Java_thread(), "Must be JavaThread");
JavaThread *jt = (JavaThread *)thread;
{- -------------------------------------------
(1) 処理対象のスレッドに対して java.lang.Thread.interrupt() が呼ばれていた場合は,
待機する必要は無いので, ここでリターン.
(interrupt されたかどうかは後でもチェックしているのでこの処理はなくてもいいが,
ここでチェックに引っかかれば ThreadBlockInVM による状態遷移が必要なくなる, という最適化)
---------------------------------------- -}
// Optional optimization -- avoid state transitions if there's an interrupt pending.
// Check interrupt before trying to wait
if (Thread::is_interrupted(thread, false)) {
return;
}
{- -------------------------------------------
(1) 引数で指定された待ち時間(time)をチェックする. 以下の場合はここでリターン.
* 指定された待ち時間が負値の場合
* 指定された待ち時間が絶対時間であり, その時間が現在時刻よりも古い場合
---------------------------------------- -}
// Next, demultiplex/decode time arguments
timespec absTime;
if (time < 0 || (isAbsolute && time == 0) ) { // don't wait at all
return;
}
{- -------------------------------------------
(1) unpackTime() を呼んで, 指定された待ち時間の値(time)を絶対時刻に調整しておく.
---------------------------------------- -}
if (time > 0) {
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() が呼ばれていた場合は, ここでリターンする.
そうでなければ, pthread_mutex_trylock() で _mutex を取得する.
(これ以降の処理は _mutex で排他した状態で行う)
(なお, _mutex のロック処理が unpark() 処理と競合した場合 (= pthread_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) || pthread_mutex_trylock(_mutex) != 0) {
return;
}
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
int status ;
{- -------------------------------------------
(1) もし _counter の値が 1 であれば (= 既に unpark() が呼ばれていれば),
単に _counter を 0 にするだけでいい.
pthread_mutex_unlock() で _mutex を解放した後, ここでリターン.
(なお, ここから先が Parker で保護された critical section ということになるので,
OrderAccess::fence() も張っておく)
---------------------------------------- -}
if (_counter > 0) { // no wait needed
_counter = 0;
status = pthread_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::Linux::allowdebug_blocked_signals();
pthread_sigmask(SIG_BLOCK, allowdebug_blocked, &oldsigs);
#endif
{- -------------------------------------------
(1) OSThreadWaitState で OSThread の状態を変更した後,
pthread_cond_wait() または os::Linux::safe_cond_timedwait() を呼んで
誰かが unpark() してくれるまで眠りにつく.
(指定された待ち時間が 0 (= 無制限) であれば pthread_cond_wait(),
そうでなければ os::Linux::safe_cond_timedwait() を呼び出す.)
(なお, WorkAroundNPTLTimedWaitHang オプションが指定されている場合には,
起きた後で cond_var を新しく作り直す処理も行っている.
See: WorkAroundNPTLTimedWaitHang)
#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()
if (time == 0) {
status = pthread_cond_wait (_cond, _mutex) ;
} else {
status = os::Linux::safe_cond_timedwait (_cond, _mutex, &absTime) ;
if (status != 0 && WorkAroundNPTLTimedWaitHang) {
pthread_cond_destroy (_cond) ;
pthread_cond_init (_cond, NULL);
}
}
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
assert_status(status == 0 || status == EINTR ||
status == ETIME || status == ETIMEDOUT,
status, "cond_timedwait");
{- -------------------------------------------
(1) (デバッグ用の処理) (#ifdef ASSERT 時にのみ実行)
---------------------------------------- -}
#ifdef ASSERT
pthread_sigmask(SIG_SETMASK, &oldsigs, NULL);
#endif
{- -------------------------------------------
(1) _counter の値を 0 に戻し, _mutex を解放する.
(ここまでが _mutex で排他された処理)
---------------------------------------- -}
_counter = 0 ;
status = pthread_mutex_unlock(_mutex) ;
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
assert_status(status == 0, status, "invariant") ;
{- -------------------------------------------
(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.