--- a/src/hotspot/share/runtime/thread.cpp Wed Mar 06 20:32:03 2019 +0100
+++ b/src/hotspot/share/runtime/thread.cpp Sat Apr 20 19:24:51 2019 +0200
@@ -240,8 +240,8 @@
set_last_handle_mark(NULL);
DEBUG_ONLY(_missed_ic_stub_refill_verifier = NULL);
- // This initial value ==> never claimed.
- _oops_do_parity = 0;
+ // Initial value of zero ==> never claimed.
+ _threads_do_token = 0;
_threads_hazard_ptr = NULL;
_threads_list_ptr = NULL;
_nested_threads_hazard_ptr_cnt = 0;
@@ -887,16 +887,14 @@
// GC Support
-bool Thread::claim_oops_do_par_case(int strong_roots_parity) {
- int thread_parity = _oops_do_parity;
- if (thread_parity != strong_roots_parity) {
- jint res = Atomic::cmpxchg(strong_roots_parity, &_oops_do_parity, thread_parity);
- if (res == thread_parity) {
+bool Thread::claim_par_threads_do(uintx claim_token) {
+ uintx token = _threads_do_token;
+ if (token != claim_token) {
+ uintx res = Atomic::cmpxchg(claim_token, &_threads_do_token, token);
+ if (res == token) {
return true;
- } else {
- guarantee(res == strong_roots_parity, "Or else what?");
- return false;
}
+ guarantee(res == claim_token, "invariant");
}
return false;
}
@@ -1293,29 +1291,35 @@
NonJavaThread::~NonJavaThread() { }
void NonJavaThread::add_to_the_list() {
- MutexLockerEx lock(NonJavaThreadsList_lock, Mutex::_no_safepoint_check_flag);
- _next = _the_list._head;
+ MutexLockerEx ml(NonJavaThreadsList_lock, Mutex::_no_safepoint_check_flag);
+ // Initialize BarrierSet-related data before adding to list.
+ BarrierSet::barrier_set()->on_thread_attach(this);
+ OrderAccess::release_store(&_next, _the_list._head);
OrderAccess::release_store(&_the_list._head, this);
}
void NonJavaThread::remove_from_the_list() {
- MutexLockerEx lock(NonJavaThreadsList_lock, Mutex::_no_safepoint_check_flag);
- NonJavaThread* volatile* p = &_the_list._head;
- for (NonJavaThread* t = *p; t != NULL; p = &t->_next, t = *p) {
- if (t == this) {
- *p = this->_next;
- // Wait for any in-progress iterators. Concurrent synchronize is
- // not allowed, so do it while holding the list lock.
- _the_list._protect.synchronize();
- break;
+ {
+ MutexLockerEx 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.
+ MutexLockerEx ml(NonJavaThreadsListSync_lock, Mutex::_no_safepoint_check_flag);
+ _the_list._protect.synchronize();
+ _next = NULL; // Safe to drop the link now.
}
void NonJavaThread::pre_run() {
- // Initialize BarrierSet-related data before adding to list.
- assert(BarrierSet::barrier_set() != NULL, "invariant");
- BarrierSet::barrier_set()->on_thread_attach(this);
add_to_the_list();
// This is slightly odd in that NamedThread is a subclass, but
@@ -1326,8 +1330,6 @@
void NonJavaThread::post_run() {
JFR_ONLY(Jfr::on_thread_exit(this);)
- // Clean up BarrierSet data before removing from list.
- BarrierSet::barrier_set()->on_thread_detach(this);
remove_from_the_list();
// Ensure thread-local-storage is cleared before termination.
Thread::clear_thread_current();
@@ -1508,7 +1510,7 @@
{
MutexLockerEx mu(Terminator_lock, Mutex::_no_safepoint_check_flag);
_watcher_thread = NULL;
- Terminator_lock->notify();
+ Terminator_lock->notify_all();
}
}
@@ -1837,7 +1839,11 @@
// Thread is now sufficiently initialized to be handled by the safepoint code as being
// in the VM. Change thread state from _thread_new to _thread_in_vm
- ThreadStateTransition::transition_and_fence(this, _thread_new, _thread_in_vm);
+ ThreadStateTransition::transition(this, _thread_new, _thread_in_vm);
+ // Before a thread is on the threads list it is always safe, so after leaving the
+ // _thread_new we should emit a instruction barrier. The distance to modified code
+ // from here is probably far enough, but this is consistent and safe.
+ OrderAccess::cross_modify_fence();
assert(JavaThread::current() == this, "sanity check");
assert(!Thread::current()->owns_locks(), "sanity check");
@@ -2017,6 +2023,10 @@
_timer_exit_phase1.stop();
_timer_exit_phase2.start();
}
+
+ // Capture daemon status before the thread is marked as terminated.
+ bool daemon = is_daemon(threadObj());
+
// Notify waiters on thread object. This has to be done after exit() is called
// on the thread (if the thread is the last thread in a daemon ThreadGroup the
// group should have the destroyed bit set before waiters are notified).
@@ -2085,7 +2095,7 @@
_timer_exit_phase4.start();
}
// Remove from list of active threads list, and notify VM thread if we are the last non-daemon thread
- Threads::remove(this);
+ Threads::remove(this, daemon);
if (log_is_enabled(Debug, os, thread, timer)) {
_timer_exit_phase4.stop();
@@ -2103,7 +2113,7 @@
}
}
-void JavaThread::cleanup_failed_attach_current_thread() {
+void JavaThread::cleanup_failed_attach_current_thread(bool is_daemon) {
if (active_handles() != NULL) {
JNIHandleBlock* block = active_handles();
set_active_handles(NULL);
@@ -2125,7 +2135,7 @@
BarrierSet::barrier_set()->on_thread_detach(this);
- Threads::remove(this);
+ Threads::remove(this, is_daemon);
this->smr_delete();
}
@@ -2266,48 +2276,19 @@
void JavaThread::handle_special_runtime_exit_condition(bool check_asyncs) {
//
- // Check for pending external suspend. Internal suspend requests do
- // not use handle_special_runtime_exit_condition().
+ // Check for pending external suspend.
// If JNIEnv proxies are allowed, don't self-suspend if the target
// thread is not the current thread. In older versions of jdbx, jdbx
// threads could call into the VM with another thread's JNIEnv so we
// can be here operating on behalf of a suspended thread (4432884).
bool do_self_suspend = is_external_suspend_with_lock();
if (do_self_suspend && (!AllowJNIEnvProxy || this == JavaThread::current())) {
- //
- // Because thread is external suspended the safepoint code will count
- // thread as at a safepoint. This can be odd because we can be here
- // as _thread_in_Java which would normally transition to _thread_blocked
- // at a safepoint. We would like to mark the thread as _thread_blocked
- // before calling java_suspend_self like all other callers of it but
- // we must then observe proper safepoint protocol. (We can't leave
- // _thread_blocked with a safepoint in progress). However we can be
- // here as _thread_in_native_trans so we can't use a normal transition
- // constructor/destructor pair because they assert on that type of
- // transition. We could do something like:
- //
- // JavaThreadState state = thread_state();
- // set_thread_state(_thread_in_vm);
- // {
- // ThreadBlockInVM tbivm(this);
- // java_suspend_self()
- // }
- // set_thread_state(_thread_in_vm_trans);
- // if (safepoint) block;
- // set_thread_state(state);
- //
- // but that is pretty messy. Instead we just go with the way the
- // code has worked before and note that this is the only path to
- // java_suspend_self that doesn't put the thread in _thread_blocked
- // mode.
-
frame_anchor()->make_walkable(this);
- java_suspend_self();
-
- // We might be here for reasons in addition to the self-suspend request
- // so check for other async requests.
- }
-
+ java_suspend_self_with_safepoint_check();
+ }
+
+ // We might be here for reasons in addition to the self-suspend request
+ // so check for other async requests.
if (check_asyncs) {
check_and_handle_async_exceptions();
}
@@ -2426,6 +2407,7 @@
// to complete an external suspend request.
//
int JavaThread::java_suspend_self() {
+ assert(thread_state() == _thread_blocked, "wrong state for java_suspend_self()");
int ret = 0;
// we are in the process of exiting so don't suspend
@@ -2469,10 +2451,41 @@
this->SR_lock()->wait(Mutex::_no_safepoint_check_flag);
}
}
-
return ret;
}
+// Helper routine to set up the correct thread state before calling java_suspend_self.
+// This is called when regular thread-state transition helpers can't be used because
+// we can be in various states, in particular _thread_in_native_trans.
+// Because this thread is external suspended the safepoint code will count it as at
+// a safepoint, regardless of what its actual current thread-state is. But
+// is_ext_suspend_completed() may be waiting to see a thread transition from
+// _thread_in_native_trans to _thread_blocked. So we set the thread state directly
+// to _thread_blocked. The problem with setting thread state directly is that a
+// safepoint could happen just after java_suspend_self() returns after being resumed,
+// and the VM thread will see the _thread_blocked state. So we must check for a safepoint
+// after restoring the state to make sure we won't leave while a safepoint is in progress.
+// However, not all initial-states are allowed when performing a safepoint check, as we
+// should never be blocking at a safepoint whilst in those states. Of these 'bad' states
+// only _thread_in_native is possible when executing this code (based on our two callers).
+// A thread that is _thread_in_native is already safepoint-safe and so it doesn't matter
+// whether the VMThread sees the _thread_blocked state, or the _thread_in_native state,
+// and so we don't need the explicit safepoint check.
+
+void JavaThread::java_suspend_self_with_safepoint_check() {
+ assert(this == Thread::current(), "invariant");
+ JavaThreadState state = thread_state();
+ set_thread_state(_thread_blocked);
+ java_suspend_self();
+ set_thread_state_fence(state);
+ // Since we are not using a regular thread-state transition helper here,
+ // we must manually emit the instruction barrier after leaving a safe state.
+ OrderAccess::cross_modify_fence();
+ if (state != _thread_in_native) {
+ SafepointMechanism::block_if_requested(this);
+ }
+}
+
#ifdef ASSERT
// Verify the JavaThread has not yet been published in the Threads::list, and
// hence doesn't need protection from concurrent access at this stage.
@@ -2504,32 +2517,10 @@
// threads could call into the VM with another thread's JNIEnv so we
// can be here operating on behalf of a suspended thread (4432884).
if (do_self_suspend && (!AllowJNIEnvProxy || curJT == thread)) {
- JavaThreadState state = thread->thread_state();
-
- // We mark this thread_blocked state as a suspend-equivalent so
- // that a caller to is_ext_suspend_completed() won't be confused.
- // The suspend-equivalent state is cleared by java_suspend_self().
- thread->set_suspend_equivalent();
-
- // If the safepoint code sees the _thread_in_native_trans state, it will
- // wait until the thread changes to other thread state. There is no
- // guarantee on how soon we can obtain the SR_lock and complete the
- // self-suspend request. It would be a bad idea to let safepoint wait for
- // too long. Temporarily change the state to _thread_blocked to
- // let the VM thread know that this thread is ready for GC. The problem
- // of changing thread state is that safepoint could happen just after
- // java_suspend_self() returns after being resumed, and VM thread will
- // see the _thread_blocked state. We must check for safepoint
- // after restoring the state and make sure we won't leave while a safepoint
- // is in progress.
- thread->set_thread_state(_thread_blocked);
- thread->java_suspend_self();
- thread->set_thread_state(state);
-
- InterfaceSupport::serialize_thread_state_with_handler(thread);
- }
-
- SafepointMechanism::block_if_requested(curJT);
+ thread->java_suspend_self_with_safepoint_check();
+ } else {
+ SafepointMechanism::block_if_requested(curJT);
+ }
if (thread->is_deopt_suspend()) {
thread->clear_deopt_suspend();
@@ -2950,9 +2941,21 @@
}
}
+#ifdef ASSERT
+void JavaThread::verify_states_for_handshake() {
+ // This checks that the thread has a correct frame state during a handshake.
+ assert((!has_last_Java_frame() && java_call_counter() == 0) ||
+ (has_last_Java_frame() && java_call_counter() > 0),
+ "unexpected frame info: has_last_frame=%d, java_call_counter=%d",
+ has_last_Java_frame(), java_call_counter());
+}
+#endif
+
void JavaThread::nmethods_do(CodeBlobClosure* cf) {
assert((!has_last_Java_frame() && java_call_counter() == 0) ||
- (has_last_Java_frame() && java_call_counter() > 0), "wrong java_sp info!");
+ (has_last_Java_frame() && java_call_counter() > 0),
+ "unexpected frame info: has_last_frame=%d, java_call_counter=%d",
+ has_last_Java_frame(), java_call_counter());
if (has_last_Java_frame()) {
// Traverse the execution stack
@@ -2962,7 +2965,7 @@
}
}
-void JavaThread::metadata_do(void f(Metadata*)) {
+void JavaThread::metadata_do(MetadataClosure* f) {
if (has_last_Java_frame()) {
// Traverse the execution stack to call f() on the methods in the stack
for (StackFrameStream fst(this); !fst.is_done(); fst.next()) {
@@ -3472,7 +3475,7 @@
int Threads::_number_of_threads = 0;
int Threads::_number_of_non_daemon_threads = 0;
int Threads::_return_code = 0;
-int Threads::_thread_claim_parity = 0;
+uintx Threads::_thread_claim_token = 1; // Never zero.
size_t JavaThread::_stack_size_at_create = 0;
#ifdef ASSERT
@@ -3532,14 +3535,14 @@
}
void Threads::possibly_parallel_threads_do(bool is_par, ThreadClosure* tc) {
- int cp = Threads::thread_claim_parity();
+ uintx claim_token = Threads::thread_claim_token();
ALL_JAVA_THREADS(p) {
- if (p->claim_oops_do(is_par, cp)) {
+ if (p->claim_threads_do(is_par, claim_token)) {
tc->do_thread(p);
}
}
VMThread* vmt = VMThread::vm_thread();
- if (vmt->claim_oops_do(is_par, cp)) {
+ if (vmt->claim_threads_do(is_par, claim_token)) {
tc->do_thread(vmt);
}
}
@@ -3626,6 +3629,7 @@
initialize_class(vmSymbols::java_lang_Thread(), CHECK);
oop thread_object = create_initial_thread(thread_group, main_thread, CHECK);
main_thread->set_threadObj(thread_object);
+
// Set thread status to running since main thread has
// been started and running.
java_lang_Thread::set_thread_status(thread_object,
@@ -3634,6 +3638,15 @@
// The VM creates objects of this class.
initialize_class(vmSymbols::java_lang_Module(), CHECK);
+#ifdef ASSERT
+ InstanceKlass *k = SystemDictionary::UnsafeConstants_klass();
+ assert(k->is_not_initialized(), "UnsafeConstants should not already be initialized");
+#endif
+
+ // initialize the hardware-specific constants needed by Unsafe
+ initialize_class(vmSymbols::jdk_internal_misc_UnsafeConstants(), CHECK);
+ jdk_internal_misc_UnsafeConstants::set_unsafe_constants();
+
// The VM preresolves methods to these classes. Make sure that they get initialized
initialize_class(vmSymbols::java_lang_reflect_Method(), CHECK);
initialize_class(vmSymbols::java_lang_ref_Finalizer(), CHECK);
@@ -4466,9 +4479,9 @@
Events::log(p, "Thread added: " INTPTR_FORMAT, p2i(p));
}
-void Threads::remove(JavaThread* p) {
-
- // Reclaim the objectmonitors from the omInUseList and omFreeList of the moribund thread.
+void Threads::remove(JavaThread* p, bool is_daemon) {
+
+ // Reclaim the ObjectMonitors from the omInUseList and omFreeList of the moribund thread.
ObjectSynchronizer::omFlush(p);
// Extra scope needed for Thread_lock, so we can check
@@ -4495,11 +4508,8 @@
}
_number_of_threads--;
- oop threadObj = p->threadObj();
- bool daemon = true;
- if (!is_daemon(threadObj)) {
+ if (!is_daemon) {
_number_of_non_daemon_threads--;
- daemon = false;
// Only one thread left, do a notify on the Threads_lock so a thread waiting
// on destroy_vm will wake up.
@@ -4507,7 +4517,7 @@
Threads_lock->notify_all();
}
}
- ThreadService::remove_thread(p, daemon);
+ ThreadService::remove_thread(p, is_daemon);
// Make sure that safepoint code disregard this thread. This is needed since
// the thread might mess around with locks after this point. This can cause it
@@ -4534,27 +4544,39 @@
VMThread::vm_thread()->oops_do(f, cf);
}
-void Threads::change_thread_claim_parity() {
- // Set the new claim parity.
- assert(_thread_claim_parity >= 0 && _thread_claim_parity <= 2,
- "Not in range.");
- _thread_claim_parity++;
- if (_thread_claim_parity == 3) _thread_claim_parity = 1;
- assert(_thread_claim_parity >= 1 && _thread_claim_parity <= 2,
- "Not in range.");
+void Threads::change_thread_claim_token() {
+ if (++_thread_claim_token == 0) {
+ // On overflow of the token counter, there is a risk of future
+ // collisions between a new global token value and a stale token
+ // for a thread, because not all iterations visit all threads.
+ // (Though it's pretty much a theoretical concern for non-trivial
+ // token counter sizes.) To deal with the possibility, reset all
+ // the thread tokens to zero on global token overflow.
+ struct ResetClaims : public ThreadClosure {
+ virtual void do_thread(Thread* t) {
+ t->claim_threads_do(false, 0);
+ }
+ } reset_claims;
+ Threads::threads_do(&reset_claims);
+ // On overflow, update the global token to non-zero, to
+ // avoid the special "never claimed" initial thread value.
+ _thread_claim_token = 1;
+ }
}
#ifdef ASSERT
+void assert_thread_claimed(const char* kind, Thread* t, uintx expected) {
+ const uintx token = t->threads_do_token();
+ assert(token == expected,
+ "%s " PTR_FORMAT " has incorrect value " UINTX_FORMAT " != "
+ UINTX_FORMAT, kind, p2i(t), token, expected);
+}
+
void Threads::assert_all_threads_claimed() {
ALL_JAVA_THREADS(p) {
- const int thread_parity = p->oops_do_parity();
- assert((thread_parity == _thread_claim_parity),
- "Thread " PTR_FORMAT " has incorrect parity %d != %d", p2i(p), thread_parity, _thread_claim_parity);
- }
- VMThread* vmt = VMThread::vm_thread();
- const int thread_parity = vmt->oops_do_parity();
- assert((thread_parity == _thread_claim_parity),
- "VMThread " PTR_FORMAT " has incorrect parity %d != %d", p2i(vmt), thread_parity, _thread_claim_parity);
+ assert_thread_claimed("Thread", p, _thread_claim_token);
+ }
+ assert_thread_claimed("VMThread", VMThread::vm_thread(), _thread_claim_token);
}
#endif // ASSERT
@@ -4585,7 +4607,7 @@
}
}
-void Threads::metadata_do(void f(Metadata*)) {
+void Threads::metadata_do(MetadataClosure* f) {
ALL_JAVA_THREADS(p) {
p->metadata_do(f);
}
@@ -4784,7 +4806,7 @@
print_threads_compiling(st, buf, buflen);
}
-void Threads::print_threads_compiling(outputStream* st, char* buf, int buflen) {
+void Threads::print_threads_compiling(outputStream* st, char* buf, int buflen, bool short_form) {
ALL_JAVA_THREADS(thread) {
if (thread->is_Compiler_thread()) {
CompilerThread* ct = (CompilerThread*) thread;
@@ -4797,7 +4819,7 @@
if (task != NULL) {
thread->print_name_on_error(st, buf, buflen);
st->print(" ");
- task->print(st, NULL, true, true);
+ task->print(st, NULL, short_form, true);
}
}
}