8269466: Factor out the common code for initializing and starting internal VM JavaThreads

Reviewed-by: sspitsyn, pchilanomate, dcubed, coleenp, kvn
This commit is contained in:
David Holmes 2021-07-02 04:29:47 +00:00
parent 2baf498eb5
commit 4107dcf6ec
13 changed files with 152 additions and 225 deletions

View File

@ -875,90 +875,75 @@ void DeoptimizeObjectsALotThread::deoptimize_objects_alot_loop_all() {
JavaThread* CompileBroker::make_thread(ThreadType type, jobject thread_handle, CompileQueue* queue, AbstractCompiler* comp, JavaThread* THREAD) {
JavaThread* new_thread = NULL;
{
MutexLocker mu(THREAD, Threads_lock);
switch (type) {
case compiler_t:
assert(comp != NULL, "Compiler instance missing.");
if (!InjectCompilerCreationFailure || comp->num_compiler_threads() == 0) {
CompilerCounters* counters = new CompilerCounters();
new_thread = new CompilerThread(queue, counters);
}
break;
case sweeper_t:
new_thread = new CodeCacheSweeperThread();
break;
switch (type) {
case compiler_t:
assert(comp != NULL, "Compiler instance missing.");
if (!InjectCompilerCreationFailure || comp->num_compiler_threads() == 0) {
CompilerCounters* counters = new CompilerCounters();
new_thread = new CompilerThread(queue, counters);
}
break;
case sweeper_t:
new_thread = new CodeCacheSweeperThread();
break;
#if defined(ASSERT) && COMPILER2_OR_JVMCI
case deoptimizer_t:
new_thread = new DeoptimizeObjectsALotThread();
break;
case deoptimizer_t:
new_thread = new DeoptimizeObjectsALotThread();
break;
#endif // ASSERT
default:
ShouldNotReachHere();
}
// At this point the new CompilerThread data-races with this startup
// thread (which I believe is the primoridal thread and NOT the VM
// thread). This means Java bytecodes being executed at startup can
// queue compile jobs which will run at whatever default priority the
// newly created CompilerThread runs at.
// At this point it may be possible that no osthread was created for the
// JavaThread due to lack of memory. We would have to throw an exception
// in that case. However, since this must work and we do not allow
// exceptions anyway, check and abort if this fails. But first release the
// lock.
if (new_thread != NULL && new_thread->osthread() != NULL) {
java_lang_Thread::set_thread(JNIHandles::resolve_non_null(thread_handle), new_thread);
// Note that this only sets the JavaThread _priority field, which by
// definition is limited to Java priorities and not OS priorities.
// The os-priority is set in the CompilerThread startup code itself
java_lang_Thread::set_priority(JNIHandles::resolve_non_null(thread_handle), NearMaxPriority);
// Note that we cannot call os::set_priority because it expects Java
// priorities and we are *explicitly* using OS priorities so that it's
// possible to set the compiler thread priority higher than any Java
// thread.
int native_prio = CompilerThreadPriority;
if (native_prio == -1) {
if (UseCriticalCompilerThreadPriority) {
native_prio = os::java_to_os_priority[CriticalPriority];
} else {
native_prio = os::java_to_os_priority[NearMaxPriority];
}
}
os::set_native_priority(new_thread, native_prio);
java_lang_Thread::set_daemon(JNIHandles::resolve_non_null(thread_handle));
new_thread->set_threadObj(JNIHandles::resolve_non_null(thread_handle));
if (type == compiler_t) {
CompilerThread::cast(new_thread)->set_compiler(comp);
}
Threads::add(new_thread);
Thread::start(new_thread);
}
default:
ShouldNotReachHere();
}
// First release lock before aborting VM.
if (new_thread == NULL || new_thread->osthread() == NULL) {
if (UseDynamicNumberOfCompilerThreads && type == compiler_t && comp->num_compiler_threads() > 0) {
if (new_thread != NULL) {
new_thread->smr_delete();
// At this point the new CompilerThread data-races with this startup
// thread (which is the main thread and NOT the VM thread).
// This means Java bytecodes being executed at startup can
// queue compile jobs which will run at whatever default priority the
// newly created CompilerThread runs at.
// At this point it may be possible that no osthread was created for the
// JavaThread due to lack of resources. We will handle that failure below.
// Also check new_thread so that static analysis is happy.
if (new_thread != NULL && new_thread->osthread() != NULL) {
Handle thread_oop(THREAD, JNIHandles::resolve_non_null(thread_handle));
if (type == compiler_t) {
CompilerThread::cast(new_thread)->set_compiler(comp);
}
// Note that we cannot call os::set_priority because it expects Java
// priorities and we are *explicitly* using OS priorities so that it's
// possible to set the compiler thread priority higher than any Java
// thread.
int native_prio = CompilerThreadPriority;
if (native_prio == -1) {
if (UseCriticalCompilerThreadPriority) {
native_prio = os::java_to_os_priority[CriticalPriority];
} else {
native_prio = os::java_to_os_priority[NearMaxPriority];
}
}
os::set_native_priority(new_thread, native_prio);
// Note that this only sets the JavaThread _priority field, which by
// definition is limited to Java priorities and not OS priorities.
JavaThread::start_internal_daemon(THREAD, new_thread, thread_oop, NearMaxPriority);
} else { // osthread initialization failure
if (UseDynamicNumberOfCompilerThreads && type == compiler_t
&& comp->num_compiler_threads() > 0) {
// The new thread is not known to Thread-SMR yet so we can just delete.
delete new_thread;
return NULL;
} else {
vm_exit_during_initialization("java.lang.OutOfMemoryError",
os::native_thread_creation_failed_msg());
}
vm_exit_during_initialization("java.lang.OutOfMemoryError",
os::native_thread_creation_failed_msg());
}
// Let go of Threads_lock before yielding
os::naked_yield(); // make sure that the compiler thread is started early (especially helpful on SOLARIS)
return new_thread;

View File

@ -46,29 +46,18 @@ static Thread* start_thread(instanceHandle thread_oop, ThreadFunction proc, TRAP
assert(thread_oop.not_null(), "invariant");
assert(proc != NULL, "invariant");
bool allocation_failed = false;
JavaThread* new_thread = NULL;
{
MutexLocker mu(THREAD, Threads_lock);
new_thread = new JavaThread(proc);
// At this point it may be possible that no
// osthread was created for the JavaThread due to lack of memory.
if (new_thread == NULL || new_thread->osthread() == NULL) {
delete new_thread;
allocation_failed = true;
} else {
java_lang_Thread::set_thread(thread_oop(), new_thread);
java_lang_Thread::set_priority(thread_oop(), NormPriority);
java_lang_Thread::set_daemon(thread_oop());
new_thread->set_threadObj(thread_oop());
Threads::add(new_thread);
}
JavaThread* new_thread = new JavaThread(proc);
// At this point it may be possible that no
// osthread was created for the JavaThread due to lack of resources.
if (new_thread->osthread() == NULL) {
delete new_thread;
JfrJavaSupport::throw_out_of_memory_error("Unable to create native recording thread for JFR", THREAD);
return NULL;
} else {
JavaThread::start_internal_daemon(THREAD, new_thread, thread_oop, NormPriority);
return new_thread;
}
if (allocation_failed) {
JfrJavaSupport::throw_out_of_memory_error("Unable to create native recording thread for JFR", CHECK_NULL);
}
Thread::start(new_thread);
return new_thread;
}
JfrPostBox* JfrRecorderThread::_post_box = NULL;

View File

@ -1326,28 +1326,19 @@ JvmtiEnv::RunAgentThread(jthread thread, jvmtiStartFunction proc, const void* ar
}
Handle thread_hndl(current_thread, thread_oop);
{
MutexLocker mu(current_thread, Threads_lock); // grab Threads_lock
JvmtiAgentThread *new_thread = new JvmtiAgentThread(this, proc, arg);
JvmtiAgentThread* new_thread = new JvmtiAgentThread(this, proc, arg);
// At this point it may be possible that no osthread was created for the
// JavaThread due to lack of memory.
if (new_thread == NULL || new_thread->osthread() == NULL) {
if (new_thread != NULL) {
new_thread->smr_delete();
}
return JVMTI_ERROR_OUT_OF_MEMORY;
}
// At this point it may be possible that no osthread was created for the
// JavaThread due to lack of resources.
if (new_thread->osthread() == NULL) {
// The new thread is not known to Thread-SMR yet so we can just delete.
delete new_thread;
return JVMTI_ERROR_OUT_OF_MEMORY;
}
java_lang_Thread::set_thread(thread_hndl(), new_thread);
java_lang_Thread::set_priority(thread_hndl(), (ThreadPriority)priority);
java_lang_Thread::set_daemon(thread_hndl());
new_thread->set_threadObj(thread_hndl());
Threads::add(new_thread);
Thread::start(new_thread);
} // unlock Threads_lock
JavaThread::start_internal_daemon(current_thread, new_thread, thread_hndl,
(ThreadPriority)priority);
return JVMTI_ERROR_NONE;
} /* end RunAgentThread */

View File

@ -33,8 +33,6 @@
#include "runtime/monitorDeflationThread.hpp"
#include "runtime/mutexLocker.hpp"
MonitorDeflationThread* MonitorDeflationThread::_instance = NULL;
void MonitorDeflationThread::initialize() {
EXCEPTION_MARK;
@ -50,28 +48,10 @@ void MonitorDeflationThread::initialize() {
string,
CHECK);
{
MutexLocker mu(THREAD, Threads_lock);
MonitorDeflationThread* thread = new MonitorDeflationThread(&monitor_deflation_thread_entry);
MonitorDeflationThread* thread = new MonitorDeflationThread(&monitor_deflation_thread_entry);
JavaThread::vm_exit_on_osthread_failure(thread);
// At this point it may be possible that no osthread was created for the
// JavaThread due to lack of memory. We would have to throw an exception
// in that case. However, since this must work and we do not allow
// exceptions anyway, check and abort if this fails.
if (thread == NULL || thread->osthread() == NULL) {
vm_exit_during_initialization("java.lang.OutOfMemoryError",
os::native_thread_creation_failed_msg());
}
java_lang_Thread::set_thread(thread_oop(), thread);
java_lang_Thread::set_priority(thread_oop(), NearMaxPriority);
java_lang_Thread::set_daemon(thread_oop());
thread->set_threadObj(thread_oop());
_instance = thread;
Threads::add(thread);
Thread::start(thread);
}
JavaThread::start_internal_daemon(THREAD, thread, thread_oop, NearMaxPriority);
}
void MonitorDeflationThread::monitor_deflation_thread_entry(JavaThread* jt, TRAPS) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 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
@ -32,7 +32,6 @@
class MonitorDeflationThread : public JavaThread {
friend class VMStructs;
private:
static MonitorDeflationThread* _instance;
static void monitor_deflation_thread_entry(JavaThread* thread, TRAPS);
MonitorDeflationThread(ThreadFunction entry_point) : JavaThread(entry_point) {};

View File

@ -35,8 +35,6 @@
#include "services/gcNotifier.hpp"
#include "services/lowMemoryDetector.hpp"
NotificationThread* NotificationThread::_instance = NULL;
void NotificationThread::initialize() {
EXCEPTION_MARK;
@ -61,28 +59,11 @@ void NotificationThread::initialize() {
vmSymbols::thread_void_signature(),
thread_oop,
THREAD);
{
MutexLocker mu(THREAD, Threads_lock);
NotificationThread* thread = new NotificationThread(&notification_thread_entry);
// At this point it may be possible that no osthread was created for the
// JavaThread due to lack of memory. We would have to throw an exception
// in that case. However, since this must work and we do not allow
// exceptions anyway, check and abort if this fails.
if (thread == NULL || thread->osthread() == NULL) {
vm_exit_during_initialization("java.lang.OutOfMemoryError",
os::native_thread_creation_failed_msg());
}
NotificationThread* thread = new NotificationThread(&notification_thread_entry);
JavaThread::vm_exit_on_osthread_failure(thread);
java_lang_Thread::set_thread(thread_oop(), thread);
java_lang_Thread::set_priority(thread_oop(), NearMaxPriority);
java_lang_Thread::set_daemon(thread_oop());
thread->set_threadObj(thread_oop());
_instance = thread;
Threads::add(thread);
Thread::start(thread);
}
JavaThread::start_internal_daemon(THREAD, thread, thread_oop, NearMaxPriority);
}
@ -128,4 +109,3 @@ void NotificationThread::notification_thread_entry(JavaThread* jt, TRAPS) {
}
}

View File

@ -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
@ -36,8 +36,6 @@ class NotificationThread : public JavaThread {
friend class VMStructs;
private:
static NotificationThread* _instance;
static void notification_thread_entry(JavaThread* thread, TRAPS);
NotificationThread(ThreadFunction entry_point) : JavaThread(entry_point) {};

View File

@ -490,26 +490,11 @@ void os::initialize_jdk_signal_support(TRAPS) {
thread_oop,
CHECK);
{ MutexLocker mu(THREAD, Threads_lock);
JavaThread* signal_thread = new JavaThread(&signal_thread_entry);
JavaThread* thread = new JavaThread(&signal_thread_entry);
JavaThread::vm_exit_on_osthread_failure(thread);
// At this point it may be possible that no osthread was created for the
// JavaThread due to lack of memory. We would have to throw an exception
// in that case. However, since this must work and we do not allow
// exceptions anyway, check and abort if this fails.
if (signal_thread == NULL || signal_thread->osthread() == NULL) {
vm_exit_during_initialization("java.lang.OutOfMemoryError",
os::native_thread_creation_failed_msg());
}
JavaThread::start_internal_daemon(THREAD, thread, thread_oop, NearMaxPriority);
java_lang_Thread::set_thread(thread_oop(), signal_thread);
java_lang_Thread::set_priority(thread_oop(), NearMaxPriority);
java_lang_Thread::set_daemon(thread_oop());
signal_thread->set_threadObj(thread_oop());
Threads::add(signal_thread);
Thread::start(signal_thread);
}
// Handle ^BREAK
os::signal(SIGBREAK, os::user_handler());
}

View File

@ -51,7 +51,7 @@
#include "services/lowMemoryDetector.hpp"
#include "services/threadIdTable.hpp"
ServiceThread* ServiceThread::_instance = NULL;
DEBUG_ONLY(JavaThread* ServiceThread::_instance = NULL;)
JvmtiDeferredEvent* ServiceThread::_jvmti_event = NULL;
// The service thread has it's own static deferred event queue.
// Events can be posted before JVMTI vm_start, so it's too early to call JvmtiThreadState::state_for
@ -103,28 +103,11 @@ void ServiceThread::initialize() {
string,
CHECK);
{
MutexLocker mu(THREAD, Threads_lock);
ServiceThread* thread = new ServiceThread(&service_thread_entry);
ServiceThread* thread = new ServiceThread(&service_thread_entry);
JavaThread::vm_exit_on_osthread_failure(thread);
// At this point it may be possible that no osthread was created for the
// JavaThread due to lack of memory. We would have to throw an exception
// in that case. However, since this must work and we do not allow
// exceptions anyway, check and abort if this fails.
if (thread == NULL || thread->osthread() == NULL) {
vm_exit_during_initialization("java.lang.OutOfMemoryError",
os::native_thread_creation_failed_msg());
}
java_lang_Thread::set_thread(thread_oop(), thread);
java_lang_Thread::set_priority(thread_oop(), NearMaxPriority);
java_lang_Thread::set_daemon(thread_oop());
thread->set_threadObj(thread_oop());
_instance = thread;
Threads::add(thread);
Thread::start(thread);
}
JavaThread::start_internal_daemon(THREAD, thread, thread_oop, NearMaxPriority);
DEBUG_ONLY(_instance = thread;)
}
static void cleanup_oopstorages() {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 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
@ -36,7 +36,7 @@ class JvmtiDeferredEvent;
class ServiceThread : public JavaThread {
friend class VMStructs;
private:
static ServiceThread* _instance;
DEBUG_ONLY(static JavaThread* _instance;)
static JvmtiDeferredEvent* _jvmti_event;
static JvmtiDeferredEventQueue _jvmti_service_queue;

View File

@ -3900,3 +3900,44 @@ void JavaThread::verify_cross_modify_fence_failure(JavaThread *thread) {
report_vm_error(__FILE__, __LINE__, "Cross modify fence failure", "%p", thread);
}
#endif
// Starts the target JavaThread as a daemon of the given priority, and
// bound to the given java.lang.Thread instance.
// The Threads_lock is held for the duration.
void JavaThread::start_internal_daemon(JavaThread* current, JavaThread* target,
Handle thread_oop, ThreadPriority prio) {
assert(target->osthread()!= NULL, "target thread is not properly initialized");
MutexLocker mu(current, Threads_lock);
// Initialize the fields of the thread_oop first.
java_lang_Thread::set_thread(thread_oop(), target); // isAlive == true now
if (prio != NoPriority) {
java_lang_Thread::set_priority(thread_oop(), prio);
// Note: we don't call os::set_priority here. Possibly we should,
// else all threads should call it themselves when they first run.
}
java_lang_Thread::set_daemon(thread_oop());
// Now bind the thread_oop to the target JavaThread.
target->set_threadObj(thread_oop());
Threads::add(target); // target is now visible for safepoint/handshake
Thread::start(target);
}
void JavaThread::vm_exit_on_osthread_failure(JavaThread* thread) {
// At this point it may be possible that no osthread was created for the
// JavaThread due to lack of resources. However, since this must work
// for critical system threads just check and abort if this fails.
if (thread->osthread() == nullptr) {
// This isn't really an OOM condition, but historically this is what
// we report.
vm_exit_during_initialization("java.lang.OutOfMemoryError",
os::native_thread_creation_failed_msg());
}
}

View File

@ -54,7 +54,6 @@
#include "jfr/support/jfrThreadExtension.hpp"
#endif
class SafeThreadsListPtr;
class ThreadSafepointState;
class ThreadsList;
@ -1594,6 +1593,15 @@ public:
static OopStorage* thread_oop_storage();
static void verify_cross_modify_fence_failure(JavaThread *thread) PRODUCT_RETURN;
// Helper function to start a VM-internal daemon thread.
// E.g. ServiceThread, NotificationThread, CompilerThread etc.
static void start_internal_daemon(JavaThread* current, JavaThread* target,
Handle thread_oop, ThreadPriority prio);
// Helper function to do vm_exit_on_initialization for osthread
// resource allocation failure.
static void vm_exit_on_osthread_failure(JavaThread* thread);
};
// The active thread queue. It also keeps track of the current used

View File

@ -484,22 +484,10 @@ void AttachListener::init() {
return;
}
{ MutexLocker mu(THREAD, Threads_lock);
JavaThread* listener_thread = new JavaThread(&attach_listener_thread_entry);
JavaThread* thread = new JavaThread(&attach_listener_thread_entry);
JavaThread::vm_exit_on_osthread_failure(thread);
// Check that thread and osthread were created
if (listener_thread == NULL || listener_thread->osthread() == NULL) {
vm_exit_during_initialization("java.lang.OutOfMemoryError",
os::native_thread_creation_failed_msg());
}
java_lang_Thread::set_thread(thread_oop(), listener_thread);
java_lang_Thread::set_daemon(thread_oop());
listener_thread->set_threadObj(thread_oop());
Threads::add(listener_thread);
Thread::start(listener_thread);
}
JavaThread::start_internal_daemon(THREAD, thread, thread_oop, NoPriority);
}
// Performs clean-up tasks on platforms where we can detect that the last