hotspot/src/os/linux/vm/os_linux.cpp
int os::sleep(Thread* thread, jlong millis, bool interruptible) {
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
assert(thread == Thread::current(), "thread consistency check");
{- -------------------------------------------
(1) os::PlatformEvent::reset() を呼んで,
処理対象のスレッドの _SleepEvent フィールド (ParkEvent オブジェクト) をリセットしておく.
(ついでに, OrderAccess::fence() でメモリバリアも張っておく.
以降の park() 操作での load/store がこの初期化操作の store を追い抜くのは禁止.)
---------------------------------------- -}
ParkEvent * const slp = thread->_SleepEvent ;
slp->reset() ;
OrderAccess::fence() ;
{- -------------------------------------------
(1) (以下の処理は, java.lang.Thread.interrupt() による割り込みを
許すかどうか(= 引数の interruptible が true か否か)に応じて, 2通りに分岐)
---------------------------------------- -}
{- -------------------------------------------
(1) (以下が, java.lang.Thread.interrupt() による割り込みを許す場合の処理)
ThreadBlockInVM 及び OSThreadWaitState で JavaThread/OSThread の状態を変更した後,
_SleepEvent フィールドに対して os::PlatformEvent::park() を呼ぶことで眠りにつく.
(予定より早く起きることもあり得るので, 目が覚める度に javaTimeNanos() で時間を確認し,
ちゃんと指定時間分だけ経過するまで os::PlatformEvent::park() の呼び出しを繰り返す.)
(なお, 寝ている間に java.lang.Thread.suspend() で suspend 状態にされているかもしれないので,
目が覚める度に JavaThread::check_and_wait_while_suspended() でチェックを行っている.
もし suspend されていれば, この中で resume されるまで待機する
(See: java.lang.Thread.suspend()))
(また, 寝ている間に java.lang.Thread.interrupt() で割り込まれたのかもしれないので,
毎回 os::is_interrupted() でチェックを行っている.
もし割り込まれていれば, その時点でリターンする (OS_INTRPT をリターン).
(See: java.lang.Thread.interrupt()))
#TODO JavaThread::set_suspend_equivalent() はどういう意味がある??
---------------------------------------- -}
if (interruptible) {
jlong prevtime = javaTimeNanos();
for (;;) {
if (os::is_interrupted(thread, true)) {
return OS_INTRPT;
}
jlong newtime = javaTimeNanos();
if (newtime - prevtime < 0) {
// time moving backwards, should only happen if no monotonic clock
// not a guarantee() because JVM should not abort on kernel/glibc bugs
assert(!Linux::supports_monotonic_clock(), "time moving backwards");
} else {
millis -= (newtime - prevtime) / NANOSECS_PER_MILLISECS;
}
if(millis <= 0) {
return OS_OK;
}
prevtime = newtime;
{
assert(thread->is_Java_thread(), "sanity check");
JavaThread *jt = (JavaThread *) thread;
ThreadBlockInVM tbivm(jt);
OSThreadWaitState osts(jt->osthread(), false /* not Object.wait() */);
jt->set_suspend_equivalent();
// cleared by handle_special_suspend_equivalent_condition() or
// java_suspend_self() via check_and_wait_while_suspended()
slp->park(millis);
// were we externally suspended while we were waiting?
jt->check_and_wait_while_suspended();
}
}
{- -------------------------------------------
(1) (以下が, java.lang.Thread.interrupt() による割り込みを許さない場合の処理)
OSThreadWaitState で OSThread の状態を変更した後,
_SleepEvent フィールドに対して os::PlatformEvent::park() を呼ぶことで眠りにつく.
(予定より早く起きることもあり得るので, 目が覚める度に javaTimeNanos() で時間を確認し,
ちゃんと指定時間分だけ経過するまで os::PlatformEvent::park() の呼び出しを繰り返す.)
---------------------------------------- -}
} else {
OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
jlong prevtime = javaTimeNanos();
for (;;) {
// It'd be nice to avoid the back-to-back javaTimeNanos() calls on
// the 1st iteration ...
jlong newtime = javaTimeNanos();
if (newtime - prevtime < 0) {
// time moving backwards, should only happen if no monotonic clock
// not a guarantee() because JVM should not abort on kernel/glibc bugs
assert(!Linux::supports_monotonic_clock(), "time moving backwards");
} else {
millis -= (newtime - prevtime) / NANOSECS_PER_MILLISECS;
}
if(millis <= 0) break ;
prevtime = newtime;
slp->park(millis);
}
return OS_OK ;
}
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.