hotspot/src/share/vm/runtime/java.cpp
// Note: before_exit() can be executed only once, if more than one threads
// are trying to shutdown the VM at the same time, only one thread
// can run before_exit() and all other threads must wait.
void before_exit(JavaThread * thread) {
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
#define BEFORE_EXIT_NOT_RUN 0
#define BEFORE_EXIT_RUNNING 1
#define BEFORE_EXIT_DONE 2
{- -------------------------------------------
(1) before_exit() が実行されるのは 1回だけにしたいので,
_before_exit_status という関数内 static 変数を使って排他を行う.
_before_exit_status を BEFORE_EXIT_NOT_RUN から
BEFORE_EXIT_RUNNING に書き換えたスレッドだけが実際の処理を行う.
(ここにたどり着いたその他のスレッドは
_before_exit_status が BEFORE_EXIT_DONE に変わるまで待ってからリターンするだけ)
(なおコメントによると, before_exit() 全体を Mutex で保護するのはダメ, )
---------------------------------------- -}
static jint volatile _before_exit_status = BEFORE_EXIT_NOT_RUN;
// Note: don't use a Mutex to guard the entire before_exit(), as
// JVMTI post_thread_end_event and post_vm_death_event will run native code.
// A CAS or OSMutex would work just fine but then we need to manipulate
// thread state for Safepoint. Here we use Monitor wait() and notify_all()
// for synchronization.
{ MutexLocker ml(BeforeExit_lock);
switch (_before_exit_status) {
case BEFORE_EXIT_NOT_RUN:
_before_exit_status = BEFORE_EXIT_RUNNING;
break;
case BEFORE_EXIT_RUNNING:
while (_before_exit_status == BEFORE_EXIT_RUNNING) {
BeforeExit_lock->wait();
}
assert(_before_exit_status == BEFORE_EXIT_DONE, "invalid state");
return;
case BEFORE_EXIT_DONE:
return;
}
}
{- -------------------------------------------
(1) exit_procs 大域変数に登録されている ExitProc の内容を全て実行する.
(<= とはいえ ExitProc は使用されていないので, 実際には何も実行されないが...)
(See: ExitProc)
---------------------------------------- -}
// The only difference between this and Win32's _onexit procs is that
// this version is invoked before any threads get killed.
ExitProc* current = exit_procs;
while (current != NULL) {
ExitProc* next = current->next();
current->evaluate();
delete current;
current = next;
}
{- -------------------------------------------
(1)
---------------------------------------- -}
// Hang forever on exit if we're reporting an error.
if (ShowMessageBoxOnError && is_error_reported()) {
os::infinite_sleep();
}
{- -------------------------------------------
(1) もし PeriodicTask を使用していた場合は,
WatcherThread::stop() で WatcherThread を終了させる (See: WatcherThread).
---------------------------------------- -}
// Terminate watcher thread - must before disenrolling any periodic task
if (PeriodicTask::num_tasks() > 0)
WatcherThread::stop();
{- -------------------------------------------
(1) FlatProfiler を使用していた場合は, プロファイル情報を出力する.
(See: FlatProfiler)
---------------------------------------- -}
// Print statistics gathered (profiling ...)
if (Arguments::has_profile()) {
FlatProfiler::disengage();
FlatProfiler::print(10);
}
{- -------------------------------------------
(1) StatSampler を停止させる (See: StatSampler).
---------------------------------------- -}
// shut down the StatSampler task
StatSampler::disengage();
StatSampler::destroy();
{- -------------------------------------------
(1) GC アルゴリズムが CMS だった場合は ConcurrentMarkSweepThread を停止させる.
---------------------------------------- -}
#ifndef SERIALGC
// stop CMS threads
if (UseConcMarkSweepGC) {
ConcurrentMarkSweepThread::stop();
}
#endif // SERIALGC
{- -------------------------------------------
(1) (トレース出力)
---------------------------------------- -}
// Print GC/heap related information.
if (PrintGCDetails) {
Universe::print();
AdaptiveSizePolicyOutput(0);
}
{- -------------------------------------------
(1) AllocationProfiler を使用していた場合は, プロファイル情報を出力する.
(See: AllocationProfiler)
---------------------------------------- -}
if (Arguments::has_alloc_profile()) {
HandleMark hm;
// Do one last collection to enumerate all the objects
// allocated since the last one.
Universe::heap()->collect(GCCause::_allocation_profiler);
AllocationProfiler::disengage();
AllocationProfiler::print(0);
}
{- -------------------------------------------
(1) BytecodeHistogram を使用していた場合は, プロファイル情報を出力する.
(See: BytecodeHistogram)
---------------------------------------- -}
if (PrintBytecodeHistogram) {
BytecodeHistogram::print();
}
{- -------------------------------------------
(1) (JVMTI のフック点)
---------------------------------------- -}
if (JvmtiExport::should_post_thread_life()) {
JvmtiExport::post_thread_end(thread);
}
{- -------------------------------------------
(1) (JVMTI のフック点)
---------------------------------------- -}
// Always call even when there are not JVMTI environments yet, since environments
// may be attached late and JVMTI must track phases of VM execution
JvmtiExport::post_vm_death();
{- -------------------------------------------
(1)
---------------------------------------- -}
Threads::shutdown_vm_agents();
{- -------------------------------------------
(1)
---------------------------------------- -}
// Terminate the signal thread
// Note: we don't wait until it actually dies.
os::terminate_signal_thread();
{- -------------------------------------------
(1) (トレース出力)
---------------------------------------- -}
print_statistics();
Universe::heap()->print_tracing_info();
{- -------------------------------------------
(1) 全ての処理が終わったので, _before_exit_status を BEFORE_EXIT_DONE に変更する.
また, 終了を待っているスレッドがいるかもしれないので notify_all() も呼んでおく.
---------------------------------------- -}
{ MutexLocker ml(BeforeExit_lock);
_before_exit_status = BEFORE_EXIT_DONE;
BeforeExit_lock->notify_all();
}
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
#undef BEFORE_EXIT_NOT_RUN
#undef BEFORE_EXIT_RUNNING
#undef BEFORE_EXIT_DONE
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.