8260019: Move some Thread subtypes out of thread.hpp
Reviewed-by: dholmes, coleenp
This commit is contained in:
parent
08f7454fa9
commit
c5bb109272
@ -31,6 +31,7 @@
|
||||
#include "code/debugInfoRec.hpp"
|
||||
#include "code/dependencies.hpp"
|
||||
#include "code/exceptionHandlerTable.hpp"
|
||||
#include "compiler/compilerThread.hpp"
|
||||
#include "compiler/oopMap.hpp"
|
||||
#include "oops/methodData.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -57,6 +57,7 @@ class nmethod;
|
||||
class OopRecorder;
|
||||
class xmlStream;
|
||||
class CompileLog;
|
||||
class CompileTask;
|
||||
class DepChange;
|
||||
class KlassDepChange;
|
||||
class CallSiteDepChange;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -78,6 +78,7 @@ NOT_PRODUCT(cflags(IGVPrintLevel, intx, PrintIdealGraphLevel, IGVPrintLeve
|
||||
#define compilerdirectives_c2_flags(cflags)
|
||||
#endif
|
||||
|
||||
class AbstractCompiler;
|
||||
class CompilerDirectives;
|
||||
class DirectiveSet;
|
||||
|
||||
|
95
src/hotspot/share/compiler/compilerThread.cpp
Normal file
95
src/hotspot/share/compiler/compilerThread.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "compiler/compileBroker.hpp"
|
||||
#include "compiler/compileTask.hpp"
|
||||
#include "compiler/compilerThread.hpp"
|
||||
#include "runtime/sweeper.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
|
||||
// Create a CompilerThread
|
||||
CompilerThread::CompilerThread(CompileQueue* queue,
|
||||
CompilerCounters* counters)
|
||||
: JavaThread(&CompilerThread::thread_entry) {
|
||||
_env = NULL;
|
||||
_log = NULL;
|
||||
_task = NULL;
|
||||
_queue = queue;
|
||||
_counters = counters;
|
||||
_buffer_blob = NULL;
|
||||
_compiler = NULL;
|
||||
|
||||
// Compiler uses resource area for compilation, let's bias it to mtCompiler
|
||||
resource_area()->bias_to(mtCompiler);
|
||||
|
||||
#ifndef PRODUCT
|
||||
_ideal_graph_printer = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
CompilerThread::~CompilerThread() {
|
||||
// Delete objects which were allocated on heap.
|
||||
delete _counters;
|
||||
}
|
||||
|
||||
void CompilerThread::thread_entry(JavaThread* thread, TRAPS) {
|
||||
assert(thread->is_Compiler_thread(), "must be compiler thread");
|
||||
CompileBroker::compiler_thread_loop();
|
||||
}
|
||||
|
||||
bool CompilerThread::can_call_java() const {
|
||||
return _compiler != NULL && _compiler->is_jvmci();
|
||||
}
|
||||
|
||||
// Create sweeper thread
|
||||
CodeCacheSweeperThread::CodeCacheSweeperThread()
|
||||
: JavaThread(&CodeCacheSweeperThread::thread_entry) {
|
||||
_scanned_compiled_method = NULL;
|
||||
}
|
||||
|
||||
void CodeCacheSweeperThread::thread_entry(JavaThread* thread, TRAPS) {
|
||||
NMethodSweeper::sweeper_loop();
|
||||
}
|
||||
|
||||
void CodeCacheSweeperThread::oops_do_no_frames(OopClosure* f, CodeBlobClosure* cf) {
|
||||
JavaThread::oops_do_no_frames(f, cf);
|
||||
if (_scanned_compiled_method != NULL && cf != NULL) {
|
||||
// Safepoints can occur when the sweeper is scanning an nmethod so
|
||||
// process it here to make sure it isn't unloaded in the middle of
|
||||
// a scan.
|
||||
cf->do_code_blob(_scanned_compiled_method);
|
||||
}
|
||||
}
|
||||
|
||||
void CodeCacheSweeperThread::nmethods_do(CodeBlobClosure* cf) {
|
||||
JavaThread::nmethods_do(cf);
|
||||
if (_scanned_compiled_method != NULL && cf != NULL) {
|
||||
// Safepoints can occur when the sweeper is scanning an nmethod so
|
||||
// process it here to make sure it isn't unloaded in the middle of
|
||||
// a scan.
|
||||
cf->do_code_blob(_scanned_compiled_method);
|
||||
}
|
||||
}
|
||||
|
146
src/hotspot/share/compiler/compilerThread.hpp
Normal file
146
src/hotspot/share/compiler/compilerThread.hpp
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_COMPILER_COMPILERTHREAD_HPP
|
||||
#define SHARE_COMPILER_COMPILERTHREAD_HPP
|
||||
|
||||
#include "runtime/thread.hpp"
|
||||
|
||||
class BufferBlob;
|
||||
class AbstractCompiler;
|
||||
class ciEnv;
|
||||
class CompileThread;
|
||||
class CompileLog;
|
||||
class CompileTask;
|
||||
class CompileQueue;
|
||||
class CompilerCounters;
|
||||
class IdealGraphPrinter;
|
||||
class JVMCIEnv;
|
||||
class JVMCIPrimitiveArray;
|
||||
|
||||
// A thread used for Compilation.
|
||||
class CompilerThread : public JavaThread {
|
||||
friend class VMStructs;
|
||||
private:
|
||||
CompilerCounters* _counters;
|
||||
|
||||
ciEnv* _env;
|
||||
CompileLog* _log;
|
||||
CompileTask* volatile _task; // print_threads_compiling can read this concurrently.
|
||||
CompileQueue* _queue;
|
||||
BufferBlob* _buffer_blob;
|
||||
|
||||
AbstractCompiler* _compiler;
|
||||
TimeStamp _idle_time;
|
||||
|
||||
public:
|
||||
|
||||
static CompilerThread* current();
|
||||
|
||||
CompilerThread(CompileQueue* queue, CompilerCounters* counters);
|
||||
~CompilerThread();
|
||||
|
||||
bool is_Compiler_thread() const { return true; }
|
||||
|
||||
virtual bool can_call_java() const;
|
||||
|
||||
// Hide native compiler threads from external view.
|
||||
bool is_hidden_from_external_view() const { return !can_call_java(); }
|
||||
|
||||
void set_compiler(AbstractCompiler* c) { _compiler = c; }
|
||||
AbstractCompiler* compiler() const { return _compiler; }
|
||||
|
||||
CompileQueue* queue() const { return _queue; }
|
||||
CompilerCounters* counters() const { return _counters; }
|
||||
|
||||
// Get/set the thread's compilation environment.
|
||||
ciEnv* env() { return _env; }
|
||||
void set_env(ciEnv* env) { _env = env; }
|
||||
|
||||
BufferBlob* get_buffer_blob() const { return _buffer_blob; }
|
||||
void set_buffer_blob(BufferBlob* b) { _buffer_blob = b; }
|
||||
|
||||
// Get/set the thread's logging information
|
||||
CompileLog* log() { return _log; }
|
||||
void init_log(CompileLog* log) {
|
||||
// Set once, for good.
|
||||
assert(_log == NULL, "set only once");
|
||||
_log = log;
|
||||
}
|
||||
|
||||
void start_idle_timer() { _idle_time.update(); }
|
||||
jlong idle_time_millis() {
|
||||
return TimeHelper::counter_to_millis(_idle_time.ticks_since_update());
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
private:
|
||||
IdealGraphPrinter *_ideal_graph_printer;
|
||||
public:
|
||||
IdealGraphPrinter *ideal_graph_printer() { return _ideal_graph_printer; }
|
||||
void set_ideal_graph_printer(IdealGraphPrinter *n) { _ideal_graph_printer = n; }
|
||||
#endif
|
||||
|
||||
// Get/set the thread's current task
|
||||
CompileTask* task() { return _task; }
|
||||
void set_task(CompileTask* task) { _task = task; }
|
||||
|
||||
static void thread_entry(JavaThread* thread, TRAPS);
|
||||
};
|
||||
|
||||
inline CompilerThread* JavaThread::as_CompilerThread() {
|
||||
assert(is_Compiler_thread(), "just checking");
|
||||
return (CompilerThread*)this;
|
||||
}
|
||||
|
||||
inline CompilerThread* CompilerThread::current() {
|
||||
return JavaThread::current()->as_CompilerThread();
|
||||
}
|
||||
|
||||
// Dedicated thread to sweep the code cache
|
||||
class CodeCacheSweeperThread : public JavaThread {
|
||||
CompiledMethod* _scanned_compiled_method; // nmethod being scanned by the sweeper
|
||||
|
||||
static void thread_entry(JavaThread* thread, TRAPS);
|
||||
|
||||
public:
|
||||
CodeCacheSweeperThread();
|
||||
// Track the nmethod currently being scanned by the sweeper
|
||||
void set_scanned_compiled_method(CompiledMethod* cm) {
|
||||
assert(_scanned_compiled_method == NULL || cm == NULL, "should reset to NULL before writing a new value");
|
||||
_scanned_compiled_method = cm;
|
||||
}
|
||||
|
||||
// Hide sweeper thread from external view.
|
||||
bool is_hidden_from_external_view() const { return true; }
|
||||
|
||||
bool is_Code_cache_sweeper_thread() const { return true; }
|
||||
|
||||
// Prevent GC from unloading _scanned_compiled_method
|
||||
void oops_do_no_frames(OopClosure* f, CodeBlobClosure* cf);
|
||||
void nmethods_do(CodeBlobClosure* cf);
|
||||
};
|
||||
|
||||
|
||||
#endif // SHARE_COMPILER_COMPILERTHREAD_HPP
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,6 +25,7 @@
|
||||
#ifndef SHARE_GC_SHARED_CONCURRENTGCTHREAD_HPP
|
||||
#define SHARE_GC_SHARED_CONCURRENTGCTHREAD_HPP
|
||||
|
||||
#include "runtime/nonJavaThread.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
|
||||
class ConcurrentGCThread: public NamedThread {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,6 +25,7 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "jvm.h"
|
||||
#include "gc/shared/gcId.hpp"
|
||||
#include "runtime/nonJavaThread.hpp"
|
||||
#include "runtime/safepoint.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "oops/access.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/java.hpp"
|
||||
#include "runtime/nonJavaThread.hpp"
|
||||
|
||||
ReferencePolicy* ReferenceProcessor::_always_clear_soft_ref_policy = NULL;
|
||||
ReferencePolicy* ReferenceProcessor::_default_soft_ref_policy = NULL;
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "metaprogramming/enableIf.hpp"
|
||||
#include "metaprogramming/logical.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
#include "runtime/nonJavaThread.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
#include "gc/shared/gcId.hpp"
|
||||
#include "logging/log.hpp"
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -23,6 +23,7 @@
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/z/zThread.inline.hpp"
|
||||
#include "runtime/nonJavaThread.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "runtime/thread.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
class BufferBlob;
|
||||
class CodeBuffer;
|
||||
|
||||
// The InterpreterRuntime is called by the interpreter for everything
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,6 +26,7 @@
|
||||
#define SHARE_VM_JFR_UTILITIES_JFRTHREADITERATOR_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
#include "runtime/nonJavaThread.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
#include "runtime/threadSMR.hpp"
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -24,6 +24,7 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "compiler/compileTask.hpp"
|
||||
#include "compiler/compilerThread.hpp"
|
||||
#include "gc/shared/collectedHeap.hpp"
|
||||
#include "jvmci/jvmci.hpp"
|
||||
#include "jvmci/jvmciJavaClasses.hpp"
|
||||
|
342
src/hotspot/share/runtime/nonJavaThread.cpp
Normal file
342
src/hotspot/share/runtime/nonJavaThread.cpp
Normal file
@ -0,0 +1,342 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "jvm_io.h"
|
||||
#include "gc/shared/barrierSet.hpp"
|
||||
#include "gc/shared/gcId.hpp"
|
||||
#include "runtime/atomic.hpp"
|
||||
#include "runtime/jniHandles.hpp"
|
||||
#include "runtime/nonJavaThread.hpp"
|
||||
#include "runtime/osThread.hpp"
|
||||
#include "runtime/task.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "utilities/defaultStream.hpp"
|
||||
#include "utilities/singleWriterSynchronizer.hpp"
|
||||
#include "utilities/vmError.hpp"
|
||||
|
||||
#if INCLUDE_JFR
|
||||
#include "jfr/jfr.hpp"
|
||||
#endif
|
||||
|
||||
// List of all NonJavaThreads and safe iteration over that list.
|
||||
|
||||
class NonJavaThread::List {
|
||||
public:
|
||||
NonJavaThread* volatile _head;
|
||||
SingleWriterSynchronizer _protect;
|
||||
|
||||
List() : _head(NULL), _protect() {}
|
||||
};
|
||||
|
||||
NonJavaThread::List NonJavaThread::_the_list;
|
||||
|
||||
NonJavaThread::Iterator::Iterator() :
|
||||
_protect_enter(_the_list._protect.enter()),
|
||||
_current(Atomic::load_acquire(&_the_list._head))
|
||||
{}
|
||||
|
||||
NonJavaThread::Iterator::~Iterator() {
|
||||
_the_list._protect.exit(_protect_enter);
|
||||
}
|
||||
|
||||
void NonJavaThread::Iterator::step() {
|
||||
assert(!end(), "precondition");
|
||||
_current = Atomic::load_acquire(&_current->_next);
|
||||
}
|
||||
|
||||
NonJavaThread::NonJavaThread() : Thread(), _next(NULL) {
|
||||
assert(BarrierSet::barrier_set() != NULL, "NonJavaThread created too soon!");
|
||||
}
|
||||
|
||||
NonJavaThread::~NonJavaThread() { }
|
||||
|
||||
void NonJavaThread::add_to_the_list() {
|
||||
MutexLocker ml(NonJavaThreadsList_lock, Mutex::_no_safepoint_check_flag);
|
||||
// Initialize BarrierSet-related data before adding to list.
|
||||
BarrierSet::barrier_set()->on_thread_attach(this);
|
||||
Atomic::release_store(&_next, _the_list._head);
|
||||
Atomic::release_store(&_the_list._head, this);
|
||||
}
|
||||
|
||||
void NonJavaThread::remove_from_the_list() {
|
||||
{
|
||||
MutexLocker ml(NonJavaThreadsList_lock, Mutex::_no_safepoint_check_flag);
|
||||
// Cleanup BarrierSet-related data before removing from list.
|
||||
BarrierSet::barrier_set()->on_thread_detach(this);
|
||||
NonJavaThread* volatile* p = &_the_list._head;
|
||||
for (NonJavaThread* t = *p; t != NULL; p = &t->_next, t = *p) {
|
||||
if (t == this) {
|
||||
*p = _next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Wait for any in-progress iterators. Concurrent synchronize is not
|
||||
// allowed, so do it while holding a dedicated lock. Outside and distinct
|
||||
// from NJTList_lock in case an iteration attempts to lock it.
|
||||
MutexLocker ml(NonJavaThreadsListSync_lock, Mutex::_no_safepoint_check_flag);
|
||||
_the_list._protect.synchronize();
|
||||
_next = NULL; // Safe to drop the link now.
|
||||
}
|
||||
|
||||
void NonJavaThread::pre_run() {
|
||||
add_to_the_list();
|
||||
|
||||
// This is slightly odd in that NamedThread is a subclass, but
|
||||
// in fact name() is defined in Thread
|
||||
assert(this->name() != NULL, "thread name was not set before it was started");
|
||||
this->set_native_thread_name(this->name());
|
||||
}
|
||||
|
||||
void NonJavaThread::post_run() {
|
||||
JFR_ONLY(Jfr::on_thread_exit(this);)
|
||||
remove_from_the_list();
|
||||
unregister_thread_stack_with_NMT();
|
||||
// Ensure thread-local-storage is cleared before termination.
|
||||
Thread::clear_thread_current();
|
||||
osthread()->set_state(ZOMBIE);
|
||||
}
|
||||
|
||||
// NamedThread -- non-JavaThread subclasses with multiple
|
||||
// uniquely named instances should derive from this.
|
||||
NamedThread::NamedThread() :
|
||||
NonJavaThread(),
|
||||
_name(NULL),
|
||||
_processed_thread(NULL),
|
||||
_gc_id(GCId::undefined())
|
||||
{}
|
||||
|
||||
NamedThread::~NamedThread() {
|
||||
FREE_C_HEAP_ARRAY(char, _name);
|
||||
}
|
||||
|
||||
void NamedThread::set_name(const char* format, ...) {
|
||||
guarantee(_name == NULL, "Only get to set name once.");
|
||||
_name = NEW_C_HEAP_ARRAY(char, max_name_len, mtThread);
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
jio_vsnprintf(_name, max_name_len, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void NamedThread::print_on(outputStream* st) const {
|
||||
st->print("\"%s\" ", name());
|
||||
Thread::print_on(st);
|
||||
st->cr();
|
||||
}
|
||||
|
||||
|
||||
// ======= WatcherThread ========
|
||||
|
||||
// The watcher thread exists to simulate timer interrupts. It should
|
||||
// be replaced by an abstraction over whatever native support for
|
||||
// timer interrupts exists on the platform.
|
||||
|
||||
WatcherThread* WatcherThread::_watcher_thread = NULL;
|
||||
bool WatcherThread::_startable = false;
|
||||
volatile bool WatcherThread::_should_terminate = false;
|
||||
|
||||
WatcherThread::WatcherThread() : NonJavaThread() {
|
||||
assert(watcher_thread() == NULL, "we can only allocate one WatcherThread");
|
||||
if (os::create_thread(this, os::watcher_thread)) {
|
||||
_watcher_thread = this;
|
||||
|
||||
// Set the watcher thread to the highest OS priority which should not be
|
||||
// used, unless a Java thread with priority java.lang.Thread.MAX_PRIORITY
|
||||
// is created. The only normal thread using this priority is the reference
|
||||
// handler thread, which runs for very short intervals only.
|
||||
// If the VMThread's priority is not lower than the WatcherThread profiling
|
||||
// will be inaccurate.
|
||||
os::set_priority(this, MaxPriority);
|
||||
os::start_thread(this);
|
||||
}
|
||||
}
|
||||
|
||||
int WatcherThread::sleep() const {
|
||||
// The WatcherThread does not participate in the safepoint protocol
|
||||
// for the PeriodicTask_lock because it is not a JavaThread.
|
||||
MonitorLocker ml(PeriodicTask_lock, Mutex::_no_safepoint_check_flag);
|
||||
|
||||
if (_should_terminate) {
|
||||
// check for termination before we do any housekeeping or wait
|
||||
return 0; // we did not sleep.
|
||||
}
|
||||
|
||||
// remaining will be zero if there are no tasks,
|
||||
// causing the WatcherThread to sleep until a task is
|
||||
// enrolled
|
||||
int remaining = PeriodicTask::time_to_wait();
|
||||
int time_slept = 0;
|
||||
|
||||
// we expect this to timeout - we only ever get unparked when
|
||||
// we should terminate or when a new task has been enrolled
|
||||
OSThreadWaitState osts(this->osthread(), false /* not Object.wait() */);
|
||||
|
||||
jlong time_before_loop = os::javaTimeNanos();
|
||||
|
||||
while (true) {
|
||||
bool timedout = ml.wait(remaining);
|
||||
jlong now = os::javaTimeNanos();
|
||||
|
||||
if (remaining == 0) {
|
||||
// if we didn't have any tasks we could have waited for a long time
|
||||
// consider the time_slept zero and reset time_before_loop
|
||||
time_slept = 0;
|
||||
time_before_loop = now;
|
||||
} else {
|
||||
// need to recalculate since we might have new tasks in _tasks
|
||||
time_slept = (int) ((now - time_before_loop) / 1000000);
|
||||
}
|
||||
|
||||
// Change to task list or spurious wakeup of some kind
|
||||
if (timedout || _should_terminate) {
|
||||
break;
|
||||
}
|
||||
|
||||
remaining = PeriodicTask::time_to_wait();
|
||||
if (remaining == 0) {
|
||||
// Last task was just disenrolled so loop around and wait until
|
||||
// another task gets enrolled
|
||||
continue;
|
||||
}
|
||||
|
||||
remaining -= time_slept;
|
||||
if (remaining <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return time_slept;
|
||||
}
|
||||
|
||||
void WatcherThread::run() {
|
||||
assert(this == watcher_thread(), "just checking");
|
||||
|
||||
this->set_active_handles(JNIHandleBlock::allocate_block());
|
||||
while (true) {
|
||||
assert(watcher_thread() == Thread::current(), "thread consistency check");
|
||||
assert(watcher_thread() == this, "thread consistency check");
|
||||
|
||||
// Calculate how long it'll be until the next PeriodicTask work
|
||||
// should be done, and sleep that amount of time.
|
||||
int time_waited = sleep();
|
||||
|
||||
if (VMError::is_error_reported()) {
|
||||
// A fatal error has happened, the error handler(VMError::report_and_die)
|
||||
// should abort JVM after creating an error log file. However in some
|
||||
// rare cases, the error handler itself might deadlock. Here periodically
|
||||
// check for error reporting timeouts, and if it happens, just proceed to
|
||||
// abort the VM.
|
||||
|
||||
// This code is in WatcherThread because WatcherThread wakes up
|
||||
// periodically so the fatal error handler doesn't need to do anything;
|
||||
// also because the WatcherThread is less likely to crash than other
|
||||
// threads.
|
||||
|
||||
for (;;) {
|
||||
// Note: we use naked sleep in this loop because we want to avoid using
|
||||
// any kind of VM infrastructure which may be broken at this point.
|
||||
if (VMError::check_timeout()) {
|
||||
// We hit error reporting timeout. Error reporting was interrupted and
|
||||
// will be wrapping things up now (closing files etc). Give it some more
|
||||
// time, then quit the VM.
|
||||
os::naked_short_sleep(200);
|
||||
// Print a message to stderr.
|
||||
fdStream err(defaultStream::output_fd());
|
||||
err.print_raw_cr("# [ timer expired, abort... ]");
|
||||
// skip atexit/vm_exit/vm_abort hooks
|
||||
os::die();
|
||||
}
|
||||
|
||||
// Wait a second, then recheck for timeout.
|
||||
os::naked_short_sleep(999);
|
||||
}
|
||||
}
|
||||
|
||||
if (_should_terminate) {
|
||||
// check for termination before posting the next tick
|
||||
break;
|
||||
}
|
||||
|
||||
PeriodicTask::real_time_tick(time_waited);
|
||||
}
|
||||
|
||||
// Signal that it is terminated
|
||||
{
|
||||
MutexLocker mu(Terminator_lock, Mutex::_no_safepoint_check_flag);
|
||||
_watcher_thread = NULL;
|
||||
Terminator_lock->notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
void WatcherThread::start() {
|
||||
assert(PeriodicTask_lock->owned_by_self(), "PeriodicTask_lock required");
|
||||
|
||||
if (watcher_thread() == NULL && _startable) {
|
||||
_should_terminate = false;
|
||||
// Create the single instance of WatcherThread
|
||||
new WatcherThread();
|
||||
}
|
||||
}
|
||||
|
||||
void WatcherThread::make_startable() {
|
||||
assert(PeriodicTask_lock->owned_by_self(), "PeriodicTask_lock required");
|
||||
_startable = true;
|
||||
}
|
||||
|
||||
void WatcherThread::stop() {
|
||||
{
|
||||
// Follow normal safepoint aware lock enter protocol since the
|
||||
// WatcherThread is stopped by another JavaThread.
|
||||
MutexLocker ml(PeriodicTask_lock);
|
||||
_should_terminate = true;
|
||||
|
||||
WatcherThread* watcher = watcher_thread();
|
||||
if (watcher != NULL) {
|
||||
// unpark the WatcherThread so it can see that it should terminate
|
||||
watcher->unpark();
|
||||
}
|
||||
}
|
||||
|
||||
MonitorLocker mu(Terminator_lock);
|
||||
|
||||
while (watcher_thread() != NULL) {
|
||||
// This wait should make safepoint checks, wait without a timeout,
|
||||
// and wait as a suspend-equivalent condition.
|
||||
mu.wait(0, Mutex::_as_suspend_equivalent_flag);
|
||||
}
|
||||
}
|
||||
|
||||
void WatcherThread::unpark() {
|
||||
assert(PeriodicTask_lock->owned_by_self(), "PeriodicTask_lock required");
|
||||
PeriodicTask_lock->notify();
|
||||
}
|
||||
|
||||
void WatcherThread::print_on(outputStream* st) const {
|
||||
st->print("\"%s\" ", name());
|
||||
Thread::print_on(st);
|
||||
st->cr();
|
||||
}
|
||||
|
164
src/hotspot/share/runtime/nonJavaThread.hpp
Normal file
164
src/hotspot/share/runtime/nonJavaThread.hpp
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_RUNTIME_NONJAVATHREAD_HPP
|
||||
#define SHARE_RUNTIME_NONJAVATHREAD_HPP
|
||||
|
||||
#include "runtime/thread.hpp"
|
||||
|
||||
class NonJavaThread: public Thread {
|
||||
friend class VMStructs;
|
||||
|
||||
NonJavaThread* volatile _next;
|
||||
|
||||
class List;
|
||||
static List _the_list;
|
||||
|
||||
void add_to_the_list();
|
||||
void remove_from_the_list();
|
||||
|
||||
protected:
|
||||
virtual void pre_run();
|
||||
virtual void post_run();
|
||||
|
||||
public:
|
||||
NonJavaThread();
|
||||
~NonJavaThread();
|
||||
|
||||
class Iterator;
|
||||
};
|
||||
|
||||
// Provides iteration over the list of NonJavaThreads.
|
||||
// List addition occurs in pre_run(), and removal occurs in post_run(),
|
||||
// so that only live fully-initialized threads can be found in the list.
|
||||
// Threads created after an iterator is constructed will not be visited
|
||||
// by the iterator. The scope of an iterator is a critical section; there
|
||||
// must be no safepoint checks in that scope.
|
||||
class NonJavaThread::Iterator : public StackObj {
|
||||
uint _protect_enter;
|
||||
NonJavaThread* _current;
|
||||
|
||||
NONCOPYABLE(Iterator);
|
||||
|
||||
public:
|
||||
Iterator();
|
||||
~Iterator();
|
||||
|
||||
bool end() const { return _current == NULL; }
|
||||
NonJavaThread* current() const { return _current; }
|
||||
void step();
|
||||
};
|
||||
|
||||
// Name support for threads. non-JavaThread subclasses with multiple
|
||||
// uniquely named instances should derive from this.
|
||||
class NamedThread: public NonJavaThread {
|
||||
friend class VMStructs;
|
||||
enum {
|
||||
max_name_len = 64
|
||||
};
|
||||
private:
|
||||
char* _name;
|
||||
// log Thread being processed by oops_do
|
||||
Thread* _processed_thread;
|
||||
uint _gc_id; // The current GC id when a thread takes part in GC
|
||||
|
||||
public:
|
||||
NamedThread();
|
||||
~NamedThread();
|
||||
// May only be called once per thread.
|
||||
void set_name(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);
|
||||
virtual bool is_Named_thread() const { return true; }
|
||||
virtual char* name() const { return _name == NULL ? (char*)"Unknown Thread" : _name; }
|
||||
Thread *processed_thread() { return _processed_thread; }
|
||||
void set_processed_thread(Thread *thread) { _processed_thread = thread; }
|
||||
virtual void print_on(outputStream* st) const;
|
||||
|
||||
void set_gc_id(uint gc_id) { _gc_id = gc_id; }
|
||||
uint gc_id() { return _gc_id; }
|
||||
};
|
||||
|
||||
// Worker threads are named and have an id of an assigned work.
|
||||
class WorkerThread: public NamedThread {
|
||||
private:
|
||||
uint _id;
|
||||
public:
|
||||
WorkerThread() : _id(0) { }
|
||||
virtual bool is_Worker_thread() const { return true; }
|
||||
|
||||
virtual WorkerThread* as_Worker_thread() const {
|
||||
assert(is_Worker_thread(), "Dubious cast to WorkerThread*?");
|
||||
return (WorkerThread*) this;
|
||||
}
|
||||
|
||||
void set_id(uint work_id) { _id = work_id; }
|
||||
uint id() const { return _id; }
|
||||
};
|
||||
|
||||
// A single WatcherThread is used for simulating timer interrupts.
|
||||
class WatcherThread: public NonJavaThread {
|
||||
friend class VMStructs;
|
||||
protected:
|
||||
virtual void run();
|
||||
|
||||
private:
|
||||
static WatcherThread* _watcher_thread;
|
||||
|
||||
static bool _startable;
|
||||
// volatile due to at least one lock-free read
|
||||
volatile static bool _should_terminate;
|
||||
public:
|
||||
enum SomeConstants {
|
||||
delay_interval = 10 // interrupt delay in milliseconds
|
||||
};
|
||||
|
||||
// Constructor
|
||||
WatcherThread();
|
||||
|
||||
// No destruction allowed
|
||||
~WatcherThread() {
|
||||
guarantee(false, "WatcherThread deletion must fix the race with VM termination");
|
||||
}
|
||||
|
||||
// Tester
|
||||
bool is_Watcher_thread() const { return true; }
|
||||
|
||||
// Printing
|
||||
char* name() const { return (char*)"VM Periodic Task Thread"; }
|
||||
void print_on(outputStream* st) const;
|
||||
void unpark();
|
||||
|
||||
// Returns the single instance of WatcherThread
|
||||
static WatcherThread* watcher_thread() { return _watcher_thread; }
|
||||
|
||||
// Create and start the single instance of WatcherThread, or stop it on shutdown
|
||||
static void start();
|
||||
static void stop();
|
||||
// Only allow start once the VM is sufficiently initialized
|
||||
// Otherwise the first task to enroll will trigger the start
|
||||
static void make_startable();
|
||||
private:
|
||||
int sleep() const;
|
||||
};
|
||||
|
||||
#endif // SHARE_RUNTIME_NONJAVATHREAD_HPP
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,6 +25,7 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "runtime/init.hpp"
|
||||
#include "runtime/nonJavaThread.hpp"
|
||||
#include "runtime/task.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/timer.hpp"
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include "classfile/classLoader.hpp"
|
||||
#include "classfile/javaClasses.hpp"
|
||||
#include "classfile/javaThreadStatus.hpp"
|
||||
#include "classfile/moduleEntry.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "classfile/vmClasses.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
@ -36,6 +35,7 @@
|
||||
#include "code/scopeDesc.hpp"
|
||||
#include "compiler/compileBroker.hpp"
|
||||
#include "compiler/compileTask.hpp"
|
||||
#include "compiler/compilerThread.hpp"
|
||||
#include "gc/shared/barrierSet.hpp"
|
||||
#include "gc/shared/collectedHeap.hpp"
|
||||
#include "gc/shared/gcId.hpp"
|
||||
@ -44,7 +44,6 @@
|
||||
#include "gc/shared/oopStorage.hpp"
|
||||
#include "gc/shared/oopStorageSet.hpp"
|
||||
#include "gc/shared/tlab_globals.hpp"
|
||||
#include "gc/shared/workgroup.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "interpreter/linkResolver.hpp"
|
||||
#include "interpreter/oopMapCache.hpp"
|
||||
@ -90,6 +89,7 @@
|
||||
#include "runtime/memprofiler.hpp"
|
||||
#include "runtime/monitorDeflationThread.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
#include "runtime/nonJavaThread.hpp"
|
||||
#include "runtime/objectMonitor.hpp"
|
||||
#include "runtime/orderAccess.hpp"
|
||||
#include "runtime/osThread.hpp"
|
||||
@ -101,8 +101,6 @@
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
#include "runtime/stackWatermarkSet.hpp"
|
||||
#include "runtime/statSampler.hpp"
|
||||
#include "runtime/stubRoutines.hpp"
|
||||
#include "runtime/sweeper.hpp"
|
||||
#include "runtime/task.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/threadCritical.hpp"
|
||||
@ -127,7 +125,6 @@
|
||||
#include "utilities/events.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/preserveException.hpp"
|
||||
#include "utilities/singleWriterSynchronizer.hpp"
|
||||
#include "utilities/spinYield.hpp"
|
||||
#include "utilities/vmError.hpp"
|
||||
#if INCLUDE_JVMCI
|
||||
@ -1106,306 +1103,6 @@ void JavaThread::allocate_threadObj(Handle thread_group, const char* thread_name
|
||||
THREAD);
|
||||
}
|
||||
|
||||
// List of all NonJavaThreads and safe iteration over that list.
|
||||
|
||||
class NonJavaThread::List {
|
||||
public:
|
||||
NonJavaThread* volatile _head;
|
||||
SingleWriterSynchronizer _protect;
|
||||
|
||||
List() : _head(NULL), _protect() {}
|
||||
};
|
||||
|
||||
NonJavaThread::List NonJavaThread::_the_list;
|
||||
|
||||
NonJavaThread::Iterator::Iterator() :
|
||||
_protect_enter(_the_list._protect.enter()),
|
||||
_current(Atomic::load_acquire(&_the_list._head))
|
||||
{}
|
||||
|
||||
NonJavaThread::Iterator::~Iterator() {
|
||||
_the_list._protect.exit(_protect_enter);
|
||||
}
|
||||
|
||||
void NonJavaThread::Iterator::step() {
|
||||
assert(!end(), "precondition");
|
||||
_current = Atomic::load_acquire(&_current->_next);
|
||||
}
|
||||
|
||||
NonJavaThread::NonJavaThread() : Thread(), _next(NULL) {
|
||||
assert(BarrierSet::barrier_set() != NULL, "NonJavaThread created too soon!");
|
||||
}
|
||||
|
||||
NonJavaThread::~NonJavaThread() { }
|
||||
|
||||
void NonJavaThread::add_to_the_list() {
|
||||
MutexLocker ml(NonJavaThreadsList_lock, Mutex::_no_safepoint_check_flag);
|
||||
// Initialize BarrierSet-related data before adding to list.
|
||||
BarrierSet::barrier_set()->on_thread_attach(this);
|
||||
Atomic::release_store(&_next, _the_list._head);
|
||||
Atomic::release_store(&_the_list._head, this);
|
||||
}
|
||||
|
||||
void NonJavaThread::remove_from_the_list() {
|
||||
{
|
||||
MutexLocker ml(NonJavaThreadsList_lock, Mutex::_no_safepoint_check_flag);
|
||||
// Cleanup BarrierSet-related data before removing from list.
|
||||
BarrierSet::barrier_set()->on_thread_detach(this);
|
||||
NonJavaThread* volatile* p = &_the_list._head;
|
||||
for (NonJavaThread* t = *p; t != NULL; p = &t->_next, t = *p) {
|
||||
if (t == this) {
|
||||
*p = _next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Wait for any in-progress iterators. Concurrent synchronize is not
|
||||
// allowed, so do it while holding a dedicated lock. Outside and distinct
|
||||
// from NJTList_lock in case an iteration attempts to lock it.
|
||||
MutexLocker ml(NonJavaThreadsListSync_lock, Mutex::_no_safepoint_check_flag);
|
||||
_the_list._protect.synchronize();
|
||||
_next = NULL; // Safe to drop the link now.
|
||||
}
|
||||
|
||||
void NonJavaThread::pre_run() {
|
||||
add_to_the_list();
|
||||
|
||||
// This is slightly odd in that NamedThread is a subclass, but
|
||||
// in fact name() is defined in Thread
|
||||
assert(this->name() != NULL, "thread name was not set before it was started");
|
||||
this->set_native_thread_name(this->name());
|
||||
}
|
||||
|
||||
void NonJavaThread::post_run() {
|
||||
JFR_ONLY(Jfr::on_thread_exit(this);)
|
||||
remove_from_the_list();
|
||||
unregister_thread_stack_with_NMT();
|
||||
// Ensure thread-local-storage is cleared before termination.
|
||||
Thread::clear_thread_current();
|
||||
osthread()->set_state(ZOMBIE);
|
||||
}
|
||||
|
||||
// NamedThread -- non-JavaThread subclasses with multiple
|
||||
// uniquely named instances should derive from this.
|
||||
NamedThread::NamedThread() :
|
||||
NonJavaThread(),
|
||||
_name(NULL),
|
||||
_processed_thread(NULL),
|
||||
_gc_id(GCId::undefined())
|
||||
{}
|
||||
|
||||
NamedThread::~NamedThread() {
|
||||
FREE_C_HEAP_ARRAY(char, _name);
|
||||
}
|
||||
|
||||
void NamedThread::set_name(const char* format, ...) {
|
||||
guarantee(_name == NULL, "Only get to set name once.");
|
||||
_name = NEW_C_HEAP_ARRAY(char, max_name_len, mtThread);
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
jio_vsnprintf(_name, max_name_len, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void NamedThread::print_on(outputStream* st) const {
|
||||
st->print("\"%s\" ", name());
|
||||
Thread::print_on(st);
|
||||
st->cr();
|
||||
}
|
||||
|
||||
|
||||
// ======= WatcherThread ========
|
||||
|
||||
// The watcher thread exists to simulate timer interrupts. It should
|
||||
// be replaced by an abstraction over whatever native support for
|
||||
// timer interrupts exists on the platform.
|
||||
|
||||
WatcherThread* WatcherThread::_watcher_thread = NULL;
|
||||
bool WatcherThread::_startable = false;
|
||||
volatile bool WatcherThread::_should_terminate = false;
|
||||
|
||||
WatcherThread::WatcherThread() : NonJavaThread() {
|
||||
assert(watcher_thread() == NULL, "we can only allocate one WatcherThread");
|
||||
if (os::create_thread(this, os::watcher_thread)) {
|
||||
_watcher_thread = this;
|
||||
|
||||
// Set the watcher thread to the highest OS priority which should not be
|
||||
// used, unless a Java thread with priority java.lang.Thread.MAX_PRIORITY
|
||||
// is created. The only normal thread using this priority is the reference
|
||||
// handler thread, which runs for very short intervals only.
|
||||
// If the VMThread's priority is not lower than the WatcherThread profiling
|
||||
// will be inaccurate.
|
||||
os::set_priority(this, MaxPriority);
|
||||
os::start_thread(this);
|
||||
}
|
||||
}
|
||||
|
||||
int WatcherThread::sleep() const {
|
||||
// The WatcherThread does not participate in the safepoint protocol
|
||||
// for the PeriodicTask_lock because it is not a JavaThread.
|
||||
MonitorLocker ml(PeriodicTask_lock, Mutex::_no_safepoint_check_flag);
|
||||
|
||||
if (_should_terminate) {
|
||||
// check for termination before we do any housekeeping or wait
|
||||
return 0; // we did not sleep.
|
||||
}
|
||||
|
||||
// remaining will be zero if there are no tasks,
|
||||
// causing the WatcherThread to sleep until a task is
|
||||
// enrolled
|
||||
int remaining = PeriodicTask::time_to_wait();
|
||||
int time_slept = 0;
|
||||
|
||||
// we expect this to timeout - we only ever get unparked when
|
||||
// we should terminate or when a new task has been enrolled
|
||||
OSThreadWaitState osts(this->osthread(), false /* not Object.wait() */);
|
||||
|
||||
jlong time_before_loop = os::javaTimeNanos();
|
||||
|
||||
while (true) {
|
||||
bool timedout = ml.wait(remaining);
|
||||
jlong now = os::javaTimeNanos();
|
||||
|
||||
if (remaining == 0) {
|
||||
// if we didn't have any tasks we could have waited for a long time
|
||||
// consider the time_slept zero and reset time_before_loop
|
||||
time_slept = 0;
|
||||
time_before_loop = now;
|
||||
} else {
|
||||
// need to recalculate since we might have new tasks in _tasks
|
||||
time_slept = (int) ((now - time_before_loop) / 1000000);
|
||||
}
|
||||
|
||||
// Change to task list or spurious wakeup of some kind
|
||||
if (timedout || _should_terminate) {
|
||||
break;
|
||||
}
|
||||
|
||||
remaining = PeriodicTask::time_to_wait();
|
||||
if (remaining == 0) {
|
||||
// Last task was just disenrolled so loop around and wait until
|
||||
// another task gets enrolled
|
||||
continue;
|
||||
}
|
||||
|
||||
remaining -= time_slept;
|
||||
if (remaining <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return time_slept;
|
||||
}
|
||||
|
||||
void WatcherThread::run() {
|
||||
assert(this == watcher_thread(), "just checking");
|
||||
|
||||
this->set_active_handles(JNIHandleBlock::allocate_block());
|
||||
while (true) {
|
||||
assert(watcher_thread() == Thread::current(), "thread consistency check");
|
||||
assert(watcher_thread() == this, "thread consistency check");
|
||||
|
||||
// Calculate how long it'll be until the next PeriodicTask work
|
||||
// should be done, and sleep that amount of time.
|
||||
int time_waited = sleep();
|
||||
|
||||
if (VMError::is_error_reported()) {
|
||||
// A fatal error has happened, the error handler(VMError::report_and_die)
|
||||
// should abort JVM after creating an error log file. However in some
|
||||
// rare cases, the error handler itself might deadlock. Here periodically
|
||||
// check for error reporting timeouts, and if it happens, just proceed to
|
||||
// abort the VM.
|
||||
|
||||
// This code is in WatcherThread because WatcherThread wakes up
|
||||
// periodically so the fatal error handler doesn't need to do anything;
|
||||
// also because the WatcherThread is less likely to crash than other
|
||||
// threads.
|
||||
|
||||
for (;;) {
|
||||
// Note: we use naked sleep in this loop because we want to avoid using
|
||||
// any kind of VM infrastructure which may be broken at this point.
|
||||
if (VMError::check_timeout()) {
|
||||
// We hit error reporting timeout. Error reporting was interrupted and
|
||||
// will be wrapping things up now (closing files etc). Give it some more
|
||||
// time, then quit the VM.
|
||||
os::naked_short_sleep(200);
|
||||
// Print a message to stderr.
|
||||
fdStream err(defaultStream::output_fd());
|
||||
err.print_raw_cr("# [ timer expired, abort... ]");
|
||||
// skip atexit/vm_exit/vm_abort hooks
|
||||
os::die();
|
||||
}
|
||||
|
||||
// Wait a second, then recheck for timeout.
|
||||
os::naked_short_sleep(999);
|
||||
}
|
||||
}
|
||||
|
||||
if (_should_terminate) {
|
||||
// check for termination before posting the next tick
|
||||
break;
|
||||
}
|
||||
|
||||
PeriodicTask::real_time_tick(time_waited);
|
||||
}
|
||||
|
||||
// Signal that it is terminated
|
||||
{
|
||||
MutexLocker mu(Terminator_lock, Mutex::_no_safepoint_check_flag);
|
||||
_watcher_thread = NULL;
|
||||
Terminator_lock->notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
void WatcherThread::start() {
|
||||
assert(PeriodicTask_lock->owned_by_self(), "PeriodicTask_lock required");
|
||||
|
||||
if (watcher_thread() == NULL && _startable) {
|
||||
_should_terminate = false;
|
||||
// Create the single instance of WatcherThread
|
||||
new WatcherThread();
|
||||
}
|
||||
}
|
||||
|
||||
void WatcherThread::make_startable() {
|
||||
assert(PeriodicTask_lock->owned_by_self(), "PeriodicTask_lock required");
|
||||
_startable = true;
|
||||
}
|
||||
|
||||
void WatcherThread::stop() {
|
||||
{
|
||||
// Follow normal safepoint aware lock enter protocol since the
|
||||
// WatcherThread is stopped by another JavaThread.
|
||||
MutexLocker ml(PeriodicTask_lock);
|
||||
_should_terminate = true;
|
||||
|
||||
WatcherThread* watcher = watcher_thread();
|
||||
if (watcher != NULL) {
|
||||
// unpark the WatcherThread so it can see that it should terminate
|
||||
watcher->unpark();
|
||||
}
|
||||
}
|
||||
|
||||
MonitorLocker mu(Terminator_lock);
|
||||
|
||||
while (watcher_thread() != NULL) {
|
||||
// This wait should make safepoint checks, wait without a timeout,
|
||||
// and wait as a suspend-equivalent condition.
|
||||
mu.wait(0, Mutex::_as_suspend_equivalent_flag);
|
||||
}
|
||||
}
|
||||
|
||||
void WatcherThread::unpark() {
|
||||
assert(PeriodicTask_lock->owned_by_self(), "PeriodicTask_lock required");
|
||||
PeriodicTask_lock->notify();
|
||||
}
|
||||
|
||||
void WatcherThread::print_on(outputStream* st) const {
|
||||
st->print("\"%s\" ", name());
|
||||
Thread::print_on(st);
|
||||
st->cr();
|
||||
}
|
||||
|
||||
// ======= JavaThread ========
|
||||
|
||||
#if INCLUDE_JVMCI
|
||||
@ -1674,19 +1371,14 @@ void JavaThread::block_if_vm_exited() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Remove this ifdef when C1 is ported to the compiler interface.
|
||||
static void compiler_thread_entry(JavaThread* thread, TRAPS);
|
||||
static void sweeper_thread_entry(JavaThread* thread, TRAPS);
|
||||
|
||||
JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) : JavaThread() {
|
||||
_jni_attach_state = _not_attaching_via_jni;
|
||||
set_entry_point(entry_point);
|
||||
// Create the native thread itself.
|
||||
// %note runtime_23
|
||||
os::ThreadType thr_type = os::java_thread;
|
||||
thr_type = entry_point == &compiler_thread_entry ? os::compiler_thread :
|
||||
os::java_thread;
|
||||
thr_type = entry_point == &CompilerThread::thread_entry ? os::compiler_thread :
|
||||
os::java_thread;
|
||||
os::create_thread(this, thr_type, stack_sz);
|
||||
// The _osthread may be NULL here because we ran out of memory (too many threads active).
|
||||
// We need to throw and OutOfMemoryError - however we cannot do this here because the caller
|
||||
@ -3139,70 +2831,6 @@ bool JavaThread::sleep(jlong millis) {
|
||||
}
|
||||
}
|
||||
|
||||
static void compiler_thread_entry(JavaThread* thread, TRAPS) {
|
||||
assert(thread->is_Compiler_thread(), "must be compiler thread");
|
||||
CompileBroker::compiler_thread_loop();
|
||||
}
|
||||
|
||||
static void sweeper_thread_entry(JavaThread* thread, TRAPS) {
|
||||
NMethodSweeper::sweeper_loop();
|
||||
}
|
||||
|
||||
// Create a CompilerThread
|
||||
CompilerThread::CompilerThread(CompileQueue* queue,
|
||||
CompilerCounters* counters)
|
||||
: JavaThread(&compiler_thread_entry) {
|
||||
_env = NULL;
|
||||
_log = NULL;
|
||||
_task = NULL;
|
||||
_queue = queue;
|
||||
_counters = counters;
|
||||
_buffer_blob = NULL;
|
||||
_compiler = NULL;
|
||||
|
||||
// Compiler uses resource area for compilation, let's bias it to mtCompiler
|
||||
resource_area()->bias_to(mtCompiler);
|
||||
|
||||
#ifndef PRODUCT
|
||||
_ideal_graph_printer = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
CompilerThread::~CompilerThread() {
|
||||
// Delete objects which were allocated on heap.
|
||||
delete _counters;
|
||||
}
|
||||
|
||||
bool CompilerThread::can_call_java() const {
|
||||
return _compiler != NULL && _compiler->is_jvmci();
|
||||
}
|
||||
|
||||
// Create sweeper thread
|
||||
CodeCacheSweeperThread::CodeCacheSweeperThread()
|
||||
: JavaThread(&sweeper_thread_entry) {
|
||||
_scanned_compiled_method = NULL;
|
||||
}
|
||||
|
||||
void CodeCacheSweeperThread::oops_do_no_frames(OopClosure* f, CodeBlobClosure* cf) {
|
||||
JavaThread::oops_do_no_frames(f, cf);
|
||||
if (_scanned_compiled_method != NULL && cf != NULL) {
|
||||
// Safepoints can occur when the sweeper is scanning an nmethod so
|
||||
// process it here to make sure it isn't unloaded in the middle of
|
||||
// a scan.
|
||||
cf->do_code_blob(_scanned_compiled_method);
|
||||
}
|
||||
}
|
||||
|
||||
void CodeCacheSweeperThread::nmethods_do(CodeBlobClosure* cf) {
|
||||
JavaThread::nmethods_do(cf);
|
||||
if (_scanned_compiled_method != NULL && cf != NULL) {
|
||||
// Safepoints can occur when the sweeper is scanning an nmethod so
|
||||
// process it here to make sure it isn't unloaded in the middle of
|
||||
// a scan.
|
||||
cf->do_code_blob(_scanned_compiled_method);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ======= Threads ========
|
||||
|
||||
|
@ -69,15 +69,6 @@ class ThreadStatistics;
|
||||
class ConcurrentLocksDump;
|
||||
class MonitorInfo;
|
||||
|
||||
class BufferBlob;
|
||||
class AbstractCompiler;
|
||||
class ciEnv;
|
||||
class CompileThread;
|
||||
class CompileLog;
|
||||
class CompileTask;
|
||||
class CompileQueue;
|
||||
class CompilerCounters;
|
||||
|
||||
class vframeArray;
|
||||
class vframe;
|
||||
class javaVFrame;
|
||||
@ -87,10 +78,6 @@ class JvmtiDeferredUpdates;
|
||||
|
||||
class ThreadClosure;
|
||||
class ICRefillVerifier;
|
||||
class IdealGraphPrinter;
|
||||
|
||||
class JVMCIEnv;
|
||||
class JVMCIPrimitiveArray;
|
||||
|
||||
class Metadata;
|
||||
class ResourceArea;
|
||||
@ -864,141 +851,6 @@ inline Thread* Thread::current_or_null_safe() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
class NonJavaThread: public Thread {
|
||||
friend class VMStructs;
|
||||
|
||||
NonJavaThread* volatile _next;
|
||||
|
||||
class List;
|
||||
static List _the_list;
|
||||
|
||||
void add_to_the_list();
|
||||
void remove_from_the_list();
|
||||
|
||||
protected:
|
||||
virtual void pre_run();
|
||||
virtual void post_run();
|
||||
|
||||
public:
|
||||
NonJavaThread();
|
||||
~NonJavaThread();
|
||||
|
||||
class Iterator;
|
||||
};
|
||||
|
||||
// Provides iteration over the list of NonJavaThreads.
|
||||
// List addition occurs in pre_run(), and removal occurs in post_run(),
|
||||
// so that only live fully-initialized threads can be found in the list.
|
||||
// Threads created after an iterator is constructed will not be visited
|
||||
// by the iterator. The scope of an iterator is a critical section; there
|
||||
// must be no safepoint checks in that scope.
|
||||
class NonJavaThread::Iterator : public StackObj {
|
||||
uint _protect_enter;
|
||||
NonJavaThread* _current;
|
||||
|
||||
NONCOPYABLE(Iterator);
|
||||
|
||||
public:
|
||||
Iterator();
|
||||
~Iterator();
|
||||
|
||||
bool end() const { return _current == NULL; }
|
||||
NonJavaThread* current() const { return _current; }
|
||||
void step();
|
||||
};
|
||||
|
||||
// Name support for threads. non-JavaThread subclasses with multiple
|
||||
// uniquely named instances should derive from this.
|
||||
class NamedThread: public NonJavaThread {
|
||||
friend class VMStructs;
|
||||
enum {
|
||||
max_name_len = 64
|
||||
};
|
||||
private:
|
||||
char* _name;
|
||||
// log Thread being processed by oops_do
|
||||
Thread* _processed_thread;
|
||||
uint _gc_id; // The current GC id when a thread takes part in GC
|
||||
|
||||
public:
|
||||
NamedThread();
|
||||
~NamedThread();
|
||||
// May only be called once per thread.
|
||||
void set_name(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);
|
||||
virtual bool is_Named_thread() const { return true; }
|
||||
virtual char* name() const { return _name == NULL ? (char*)"Unknown Thread" : _name; }
|
||||
Thread *processed_thread() { return _processed_thread; }
|
||||
void set_processed_thread(Thread *thread) { _processed_thread = thread; }
|
||||
virtual void print_on(outputStream* st) const;
|
||||
|
||||
void set_gc_id(uint gc_id) { _gc_id = gc_id; }
|
||||
uint gc_id() { return _gc_id; }
|
||||
};
|
||||
|
||||
// Worker threads are named and have an id of an assigned work.
|
||||
class WorkerThread: public NamedThread {
|
||||
private:
|
||||
uint _id;
|
||||
public:
|
||||
WorkerThread() : _id(0) { }
|
||||
virtual bool is_Worker_thread() const { return true; }
|
||||
|
||||
virtual WorkerThread* as_Worker_thread() const {
|
||||
assert(is_Worker_thread(), "Dubious cast to WorkerThread*?");
|
||||
return (WorkerThread*) this;
|
||||
}
|
||||
|
||||
void set_id(uint work_id) { _id = work_id; }
|
||||
uint id() const { return _id; }
|
||||
};
|
||||
|
||||
// A single WatcherThread is used for simulating timer interrupts.
|
||||
class WatcherThread: public NonJavaThread {
|
||||
friend class VMStructs;
|
||||
protected:
|
||||
virtual void run();
|
||||
|
||||
private:
|
||||
static WatcherThread* _watcher_thread;
|
||||
|
||||
static bool _startable;
|
||||
// volatile due to at least one lock-free read
|
||||
volatile static bool _should_terminate;
|
||||
public:
|
||||
enum SomeConstants {
|
||||
delay_interval = 10 // interrupt delay in milliseconds
|
||||
};
|
||||
|
||||
// Constructor
|
||||
WatcherThread();
|
||||
|
||||
// No destruction allowed
|
||||
~WatcherThread() {
|
||||
guarantee(false, "WatcherThread deletion must fix the race with VM termination");
|
||||
}
|
||||
|
||||
// Tester
|
||||
bool is_Watcher_thread() const { return true; }
|
||||
|
||||
// Printing
|
||||
char* name() const { return (char*)"VM Periodic Task Thread"; }
|
||||
void print_on(outputStream* st) const;
|
||||
void unpark();
|
||||
|
||||
// Returns the single instance of WatcherThread
|
||||
static WatcherThread* watcher_thread() { return _watcher_thread; }
|
||||
|
||||
// Create and start the single instance of WatcherThread, or stop it on shutdown
|
||||
static void start();
|
||||
static void stop();
|
||||
// Only allow start once the VM is sufficiently initialized
|
||||
// Otherwise the first task to enroll will trigger the start
|
||||
static void make_startable();
|
||||
private:
|
||||
int sleep() const;
|
||||
};
|
||||
|
||||
|
||||
class CompilerThread;
|
||||
|
||||
typedef void (*ThreadFunction)(JavaThread*, TRAPS);
|
||||
@ -1897,100 +1749,6 @@ inline JavaThread* JavaThread::current() {
|
||||
return Thread::current()->as_Java_thread();
|
||||
}
|
||||
|
||||
inline CompilerThread* JavaThread::as_CompilerThread() {
|
||||
assert(is_Compiler_thread(), "just checking");
|
||||
return (CompilerThread*)this;
|
||||
}
|
||||
|
||||
// Dedicated thread to sweep the code cache
|
||||
class CodeCacheSweeperThread : public JavaThread {
|
||||
CompiledMethod* _scanned_compiled_method; // nmethod being scanned by the sweeper
|
||||
public:
|
||||
CodeCacheSweeperThread();
|
||||
// Track the nmethod currently being scanned by the sweeper
|
||||
void set_scanned_compiled_method(CompiledMethod* cm) {
|
||||
assert(_scanned_compiled_method == NULL || cm == NULL, "should reset to NULL before writing a new value");
|
||||
_scanned_compiled_method = cm;
|
||||
}
|
||||
|
||||
// Hide sweeper thread from external view.
|
||||
bool is_hidden_from_external_view() const { return true; }
|
||||
|
||||
bool is_Code_cache_sweeper_thread() const { return true; }
|
||||
|
||||
// Prevent GC from unloading _scanned_compiled_method
|
||||
void oops_do_no_frames(OopClosure* f, CodeBlobClosure* cf);
|
||||
void nmethods_do(CodeBlobClosure* cf);
|
||||
};
|
||||
|
||||
// A thread used for Compilation.
|
||||
class CompilerThread : public JavaThread {
|
||||
friend class VMStructs;
|
||||
private:
|
||||
CompilerCounters* _counters;
|
||||
|
||||
ciEnv* _env;
|
||||
CompileLog* _log;
|
||||
CompileTask* volatile _task; // print_threads_compiling can read this concurrently.
|
||||
CompileQueue* _queue;
|
||||
BufferBlob* _buffer_blob;
|
||||
|
||||
AbstractCompiler* _compiler;
|
||||
TimeStamp _idle_time;
|
||||
|
||||
public:
|
||||
|
||||
static CompilerThread* current();
|
||||
|
||||
CompilerThread(CompileQueue* queue, CompilerCounters* counters);
|
||||
~CompilerThread();
|
||||
|
||||
bool is_Compiler_thread() const { return true; }
|
||||
|
||||
virtual bool can_call_java() const;
|
||||
|
||||
// Hide native compiler threads from external view.
|
||||
bool is_hidden_from_external_view() const { return !can_call_java(); }
|
||||
|
||||
void set_compiler(AbstractCompiler* c) { _compiler = c; }
|
||||
AbstractCompiler* compiler() const { return _compiler; }
|
||||
|
||||
CompileQueue* queue() const { return _queue; }
|
||||
CompilerCounters* counters() const { return _counters; }
|
||||
|
||||
// Get/set the thread's compilation environment.
|
||||
ciEnv* env() { return _env; }
|
||||
void set_env(ciEnv* env) { _env = env; }
|
||||
|
||||
BufferBlob* get_buffer_blob() const { return _buffer_blob; }
|
||||
void set_buffer_blob(BufferBlob* b) { _buffer_blob = b; }
|
||||
|
||||
// Get/set the thread's logging information
|
||||
CompileLog* log() { return _log; }
|
||||
void init_log(CompileLog* log) {
|
||||
// Set once, for good.
|
||||
assert(_log == NULL, "set only once");
|
||||
_log = log;
|
||||
}
|
||||
|
||||
void start_idle_timer() { _idle_time.update(); }
|
||||
jlong idle_time_millis() {
|
||||
return TimeHelper::counter_to_millis(_idle_time.ticks_since_update());
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
private:
|
||||
IdealGraphPrinter *_ideal_graph_printer;
|
||||
public:
|
||||
IdealGraphPrinter *ideal_graph_printer() { return _ideal_graph_printer; }
|
||||
void set_ideal_graph_printer(IdealGraphPrinter *n) { _ideal_graph_printer = n; }
|
||||
#endif
|
||||
|
||||
// Get/set the thread's current task
|
||||
CompileTask* task() { return _task; }
|
||||
void set_task(CompileTask* task) { _task = task; }
|
||||
};
|
||||
|
||||
inline JavaThread* Thread::as_Java_thread() {
|
||||
assert(is_Java_thread(), "incorrect cast to JavaThread");
|
||||
return static_cast<JavaThread*>(this);
|
||||
@ -2001,10 +1759,6 @@ inline const JavaThread* Thread::as_Java_thread() const {
|
||||
return static_cast<const JavaThread*>(this);
|
||||
}
|
||||
|
||||
inline CompilerThread* CompilerThread::current() {
|
||||
return JavaThread::current()->as_CompilerThread();
|
||||
}
|
||||
|
||||
// The active thread queue. It also keeps track of the current used
|
||||
// thread priorities.
|
||||
class Threads: AllStatic {
|
||||
|
@ -26,6 +26,7 @@
|
||||
#define SHARE_RUNTIME_VMTHREAD_HPP
|
||||
|
||||
#include "runtime/perfDataTypes.hpp"
|
||||
#include "runtime/nonJavaThread.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
#include "runtime/task.hpp"
|
||||
#include "runtime/vmOperations.hpp"
|
||||
|
Loading…
x
Reference in New Issue
Block a user