# HG changeset patch # User dlong # Date 1539834959 25200 # Wed Oct 17 20:55:59 2018 -0700 # Node ID aee8454df07bcdb62c660bbc579364d991fad02a # Parent 367b2cd49ec5efad2f89346d3c0d1ddcc115d70c [mq]: 8021335 diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -1819,6 +1819,9 @@ thread->clear_pending_exception(); } +static bool is_daemon(oop threadObj) { + return (threadObj != NULL && java_lang_Thread::is_daemon(threadObj)); +} // For any new cleanup additions, please check to see if they need to be applied to // cleanup_failed_attach_current_thread as well. @@ -1910,7 +1913,6 @@ MutexLockerEx ml(SR_lock(), Mutex::_no_safepoint_check_flag); if (!is_external_suspend()) { set_terminated(_thread_exiting); - ThreadService::current_thread_exiting(this); break; } // Implied else: @@ -1929,7 +1931,11 @@ // exiting. } // no more external suspends are allowed at this point + { MutexLocker mu(Threads_lock); + ThreadService::current_thread_exiting(this, is_daemon(threadObj())); + } } else { + assert(!is_terminated() && !is_exiting(), "must not be exiting"); // before_exit() has already posted JVMTI THREAD_END events } @@ -4332,7 +4338,7 @@ void Threads::add(JavaThread* p, bool force_daemon) { // The threads lock must be owned at this point - assert_locked_or_safepoint(Threads_lock); + assert(Threads_lock->owned_by_self(), "must have threads lock"); BarrierSet::barrier_set()->on_thread_attach(p); @@ -4348,7 +4354,7 @@ bool daemon = true; // Bootstrapping problem: threadObj can be null for initial // JavaThread (or for threads attached via JNI) - if ((!force_daemon) && (threadObj == NULL || !java_lang_Thread::is_daemon(threadObj))) { + if ((!force_daemon) && !is_daemon((threadObj))) { _number_of_non_daemon_threads++; daemon = false; } @@ -4393,7 +4399,7 @@ _number_of_threads--; oop threadObj = p->threadObj(); bool daemon = true; - if (threadObj == NULL || !java_lang_Thread::is_daemon(threadObj)) { + if (!is_daemon(threadObj)) { _number_of_non_daemon_threads--; daemon = false; diff --git a/src/hotspot/share/services/threadService.cpp b/src/hotspot/share/services/threadService.cpp --- a/src/hotspot/share/services/threadService.cpp +++ b/src/hotspot/share/services/threadService.cpp @@ -57,8 +57,6 @@ PerfVariable* ThreadService::_live_threads_count = NULL; PerfVariable* ThreadService::_peak_threads_count = NULL; PerfVariable* ThreadService::_daemon_threads_count = NULL; -volatile int ThreadService::_exiting_threads_count = 0; -volatile int ThreadService::_exiting_daemon_threads_count = 0; ThreadDumpResult* ThreadService::_threaddump_list = NULL; @@ -101,10 +99,16 @@ _peak_threads_count->set_value(get_live_thread_count()); } +static bool is_hidden_thread(JavaThread *thread) { + // hide VM internal or JVMTI agent threads + return thread->is_hidden_from_external_view() || thread->is_jvmti_agent_thread(); +} + void ThreadService::add_thread(JavaThread* thread, bool daemon) { - // Do not count VM internal or JVMTI agent threads - if (thread->is_hidden_from_external_view() || - thread->is_jvmti_agent_thread()) { + assert(Threads_lock->owned_by_self(), "must have threads lock"); + + // Do not count hidden threads + if (is_hidden_thread(thread)) { return; } @@ -120,31 +124,44 @@ } } +void ThreadService::decrement_thread_counts(JavaThread* jt, bool daemon) { + assert(Threads_lock->owned_by_self(), "must have threads lock"); + + _live_threads_count->dec(1); + + if (daemon) { + _daemon_threads_count->dec(1); + } +} + void ThreadService::remove_thread(JavaThread* thread, bool daemon) { - Atomic::dec(&_exiting_threads_count); - if (daemon) { - Atomic::dec(&_exiting_daemon_threads_count); - } + assert(Threads_lock->owned_by_self(), "must have threads lock"); - if (thread->is_hidden_from_external_view() || - thread->is_jvmti_agent_thread()) { + // Do not count hidden threads + if (is_hidden_thread(thread)) { return; } - _live_threads_count->set_value(_live_threads_count->get_value() - 1); - if (daemon) { - _daemon_threads_count->set_value(_daemon_threads_count->get_value() - 1); + assert(!thread->is_terminated(), "must not be terminated"); + if (!thread->is_exiting()) { + // JavaThread::exit() skipped calling current_thread_exiting() + decrement_thread_counts(thread, daemon); } + } -void ThreadService::current_thread_exiting(JavaThread* jt) { +void ThreadService::current_thread_exiting(JavaThread* jt, bool daemon) { + assert(Threads_lock->owned_by_self(), "must have threads lock"); + + // Do not count hidden threads + if (is_hidden_thread(jt)) { + return; + } + assert(jt == JavaThread::current(), "Called by current thread"); - Atomic::inc(&_exiting_threads_count); + assert(!jt->is_terminated() && jt->is_exiting(), "must be exiting"); - oop threadObj = jt->threadObj(); - if (threadObj != NULL && java_lang_Thread::is_daemon(threadObj)) { - Atomic::inc(&_exiting_daemon_threads_count); - } + decrement_thread_counts(jt, daemon); } // FIXME: JVMTI should call this function diff --git a/src/hotspot/share/services/threadService.hpp b/src/hotspot/share/services/threadService.hpp --- a/src/hotspot/share/services/threadService.hpp +++ b/src/hotspot/share/services/threadService.hpp @@ -58,11 +58,6 @@ static PerfVariable* _peak_threads_count; static PerfVariable* _daemon_threads_count; - // These 2 counters are atomically incremented once the thread is exiting. - // They will be atomically decremented when ThreadService::remove_thread is called. - static volatile int _exiting_threads_count; - static volatile int _exiting_daemon_threads_count; - static bool _thread_monitoring_contention_enabled; static bool _thread_cpu_time_enabled; static bool _thread_allocated_memory_enabled; @@ -72,11 +67,13 @@ // requested by multiple threads concurrently. static ThreadDumpResult* _threaddump_list; + static void decrement_thread_counts(JavaThread* jt, bool daemon); + public: static void init(); static void add_thread(JavaThread* thread, bool daemon); static void remove_thread(JavaThread* thread, bool daemon); - static void current_thread_exiting(JavaThread* jt); + static void current_thread_exiting(JavaThread* jt, bool daemon); static bool set_thread_monitoring_contention(bool flag); static bool is_thread_monitoring_contention() { return _thread_monitoring_contention_enabled; } @@ -89,11 +86,8 @@ static jlong get_total_thread_count() { return _total_threads_count->get_value(); } static jlong get_peak_thread_count() { return _peak_threads_count->get_value(); } - static jlong get_live_thread_count() { return _live_threads_count->get_value() - _exiting_threads_count; } - static jlong get_daemon_thread_count() { return _daemon_threads_count->get_value() - _exiting_daemon_threads_count; } - - static int exiting_threads_count() { return _exiting_threads_count; } - static int exiting_daemon_threads_count() { return _exiting_daemon_threads_count; } + static jlong get_live_thread_count() { return _live_threads_count->get_value(); } + static jlong get_daemon_thread_count() { return _daemon_threads_count->get_value(); } // Support for thread dump static void add_thread_dump(ThreadDumpResult* dump);