mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 23:34:52 +02:00
8263191: Consolidate ThreadInVMfromJavaNoAsyncException and ThreadBlockInVMWithDeadlockCheck with existing wrappers
Reviewed-by: coleenp, dholmes, dcubed
This commit is contained in:
parent
80cdf7882d
commit
d6b5e1809b
3 changed files with 34 additions and 80 deletions
|
@ -150,8 +150,9 @@ class ThreadInVMForHandshake : public ThreadStateTransition {
|
||||||
};
|
};
|
||||||
|
|
||||||
class ThreadInVMfromJava : public ThreadStateTransition {
|
class ThreadInVMfromJava : public ThreadStateTransition {
|
||||||
|
bool _check_asyncs;
|
||||||
public:
|
public:
|
||||||
ThreadInVMfromJava(JavaThread* thread) : ThreadStateTransition(thread) {
|
ThreadInVMfromJava(JavaThread* thread, bool check_asyncs = true) : ThreadStateTransition(thread), _check_asyncs(check_asyncs) {
|
||||||
trans_from_java(_thread_in_vm);
|
trans_from_java(_thread_in_vm);
|
||||||
}
|
}
|
||||||
~ThreadInVMfromJava() {
|
~ThreadInVMfromJava() {
|
||||||
|
@ -159,8 +160,9 @@ class ThreadInVMfromJava : public ThreadStateTransition {
|
||||||
_thread->stack_overflow_state()->enable_stack_yellow_reserved_zone();
|
_thread->stack_overflow_state()->enable_stack_yellow_reserved_zone();
|
||||||
}
|
}
|
||||||
trans(_thread_in_vm, _thread_in_Java);
|
trans(_thread_in_vm, _thread_in_Java);
|
||||||
// Check for pending. async. exceptions or suspends.
|
// We prevent asynchronous exceptions from being installed on return to Java in situations
|
||||||
if (_thread->has_special_runtime_exit_condition()) _thread->handle_special_runtime_exit_condition();
|
// where we can't tolerate them. See bugs: 4324348, 4854693, 4998314, 5040492, 5050705.
|
||||||
|
if (_thread->has_special_runtime_exit_condition()) _thread->handle_special_runtime_exit_condition(_check_asyncs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -222,93 +224,45 @@ class ThreadToNativeFromVM : public ThreadStateTransition {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Parameter in_flight_mutex_addr is only used by class Mutex to avoid certain deadlock
|
||||||
|
// scenarios while making transitions that might block for a safepoint or handshake.
|
||||||
|
// It's the address of a pointer to the mutex we are trying to acquire. This will be used to
|
||||||
|
// access and release said mutex when transitioning back from blocked to vm (destructor) in
|
||||||
|
// case we need to stop for a safepoint or handshake.
|
||||||
class ThreadBlockInVM : public ThreadStateTransition {
|
class ThreadBlockInVM : public ThreadStateTransition {
|
||||||
public:
|
|
||||||
ThreadBlockInVM(JavaThread *thread)
|
|
||||||
: ThreadStateTransition(thread) {
|
|
||||||
// Once we are blocked vm expects stack to be walkable
|
|
||||||
thread->frame_anchor()->make_walkable(thread);
|
|
||||||
trans(_thread_in_vm, _thread_blocked);
|
|
||||||
}
|
|
||||||
~ThreadBlockInVM() {
|
|
||||||
trans(_thread_blocked, _thread_in_vm);
|
|
||||||
// We don't need to clear_walkable because it will happen automagically when we return to java
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Unlike ThreadBlockInVM, this class is designed to avoid certain deadlock scenarios while making
|
|
||||||
// transitions inside class Mutex in cases where we need to block for a safepoint or handshake. It
|
|
||||||
// receives an extra argument compared to ThreadBlockInVM, the address of a pointer to the mutex we
|
|
||||||
// are trying to acquire. This will be used to access and release the mutex if needed to avoid
|
|
||||||
// said deadlocks.
|
|
||||||
// It works like ThreadBlockInVM but differs from it in two ways:
|
|
||||||
// - When transitioning in (constructor), it checks for safepoints without blocking, i.e., calls
|
|
||||||
// back if needed to allow a pending safepoint to continue but does not block in it.
|
|
||||||
// - When transitioning back (destructor), if there is a pending safepoint or handshake it releases
|
|
||||||
// the mutex that is only partially acquired.
|
|
||||||
class ThreadBlockInVMWithDeadlockCheck : public ThreadStateTransition {
|
|
||||||
private:
|
private:
|
||||||
Mutex** _in_flight_mutex_addr;
|
Mutex** _in_flight_mutex_addr;
|
||||||
|
|
||||||
void release_mutex() {
|
|
||||||
assert(_in_flight_mutex_addr != NULL, "_in_flight_mutex_addr should have been set on constructor");
|
|
||||||
Mutex* in_flight_mutex = *_in_flight_mutex_addr;
|
|
||||||
if (in_flight_mutex != NULL) {
|
|
||||||
in_flight_mutex->release_for_safepoint();
|
|
||||||
*_in_flight_mutex_addr = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public:
|
public:
|
||||||
ThreadBlockInVMWithDeadlockCheck(JavaThread* thread, Mutex** in_flight_mutex_addr)
|
ThreadBlockInVM(JavaThread* thread, Mutex** in_flight_mutex_addr = NULL)
|
||||||
: ThreadStateTransition(thread), _in_flight_mutex_addr(in_flight_mutex_addr) {
|
: ThreadStateTransition(thread), _in_flight_mutex_addr(in_flight_mutex_addr) {
|
||||||
|
assert(thread->thread_state() == _thread_in_vm, "coming from wrong thread state");
|
||||||
|
thread->check_possible_safepoint();
|
||||||
// Once we are blocked vm expects stack to be walkable
|
// Once we are blocked vm expects stack to be walkable
|
||||||
thread->frame_anchor()->make_walkable(thread);
|
thread->frame_anchor()->make_walkable(thread);
|
||||||
|
|
||||||
// All unsafe states are treated the same by the VMThread
|
|
||||||
// so we can skip the _thread_in_vm_trans state here. Since
|
|
||||||
// we don't read poll, it's enough to order the stores.
|
|
||||||
OrderAccess::storestore();
|
|
||||||
|
|
||||||
thread->set_thread_state(_thread_blocked);
|
thread->set_thread_state(_thread_blocked);
|
||||||
}
|
}
|
||||||
~ThreadBlockInVMWithDeadlockCheck() {
|
~ThreadBlockInVM() {
|
||||||
|
assert(_thread->thread_state() == _thread_blocked, "coming from wrong thread state");
|
||||||
// Change to transition state and ensure it is seen by the VM thread.
|
// Change to transition state and ensure it is seen by the VM thread.
|
||||||
_thread->set_thread_state_fence((JavaThreadState)(_thread_blocked_trans));
|
_thread->set_thread_state_fence(_thread_blocked_trans);
|
||||||
|
|
||||||
if (SafepointMechanism::should_process(_thread)) {
|
if (SafepointMechanism::should_process(_thread)) {
|
||||||
release_mutex();
|
if (_in_flight_mutex_addr != NULL) {
|
||||||
|
release_mutex();
|
||||||
|
}
|
||||||
SafepointMechanism::process_if_requested(_thread);
|
SafepointMechanism::process_if_requested(_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
_thread->set_thread_state(_thread_in_vm);
|
_thread->set_thread_state(_thread_in_vm);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
void release_mutex() {
|
||||||
// This special transition class is only used to prevent asynchronous exceptions
|
Mutex* in_flight_mutex = *_in_flight_mutex_addr;
|
||||||
// from being installed on vm exit in situations where we can't tolerate them.
|
if (in_flight_mutex != NULL) {
|
||||||
// See bugs: 4324348, 4854693, 4998314, 5040492, 5050705.
|
in_flight_mutex->release_for_safepoint();
|
||||||
class ThreadInVMfromJavaNoAsyncException : public ThreadStateTransition {
|
*_in_flight_mutex_addr = NULL;
|
||||||
public:
|
|
||||||
ThreadInVMfromJavaNoAsyncException(JavaThread* thread) : ThreadStateTransition(thread) {
|
|
||||||
trans_from_java(_thread_in_vm);
|
|
||||||
}
|
|
||||||
~ThreadInVMfromJavaNoAsyncException() {
|
|
||||||
if (_thread->stack_overflow_state()->stack_yellow_reserved_zone_disabled()) {
|
|
||||||
_thread->stack_overflow_state()->enable_stack_yellow_reserved_zone();
|
|
||||||
}
|
}
|
||||||
trans(_thread_in_vm, _thread_in_Java);
|
|
||||||
// NOTE: We do not check for pending. async. exceptions.
|
|
||||||
// If we did and moved the pending async exception over into the
|
|
||||||
// pending exception field, we would need to deopt (currently C2
|
|
||||||
// only). However, to do so would require that we transition back
|
|
||||||
// to the _thread_in_vm state. Instead we postpone the handling of
|
|
||||||
// the async exception.
|
|
||||||
|
|
||||||
|
|
||||||
// Check for pending. suspends only.
|
|
||||||
if (_thread->has_special_runtime_exit_condition())
|
|
||||||
_thread->handle_special_runtime_exit_condition(false);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -383,7 +337,7 @@ class VMNativeEntryWrapper {
|
||||||
|
|
||||||
#define JRT_ENTRY_NO_ASYNC(result_type, header) \
|
#define JRT_ENTRY_NO_ASYNC(result_type, header) \
|
||||||
result_type header { \
|
result_type header { \
|
||||||
ThreadInVMfromJavaNoAsyncException __tiv(thread); \
|
ThreadInVMfromJava __tiv(thread, false /* check asyncs */); \
|
||||||
VM_ENTRY_BASE(result_type, header, thread) \
|
VM_ENTRY_BASE(result_type, header, thread) \
|
||||||
debug_only(VMEntryWrapper __vew;)
|
debug_only(VMEntryWrapper __vew;)
|
||||||
|
|
||||||
|
@ -401,7 +355,7 @@ class VMNativeEntryWrapper {
|
||||||
|
|
||||||
#define JRT_BLOCK_NO_ASYNC \
|
#define JRT_BLOCK_NO_ASYNC \
|
||||||
{ \
|
{ \
|
||||||
ThreadInVMfromJavaNoAsyncException __tiv(thread); \
|
ThreadInVMfromJava __tiv(thread, false /* check asyncs */); \
|
||||||
Thread* THREAD = thread; \
|
Thread* THREAD = thread; \
|
||||||
debug_only(VMEntryWrapper __vew;)
|
debug_only(VMEntryWrapper __vew;)
|
||||||
|
|
||||||
|
|
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -84,12 +84,12 @@ void Mutex::lock_contended(Thread* self) {
|
||||||
// Is it a JavaThread participating in the safepoint protocol.
|
// Is it a JavaThread participating in the safepoint protocol.
|
||||||
if (is_active_Java_thread) {
|
if (is_active_Java_thread) {
|
||||||
assert(rank() > Mutex::special, "Potential deadlock with special or lesser rank mutex");
|
assert(rank() > Mutex::special, "Potential deadlock with special or lesser rank mutex");
|
||||||
{ ThreadBlockInVMWithDeadlockCheck tbivmdc(self->as_Java_thread(), &in_flight_mutex);
|
{ ThreadBlockInVM tbivmdc(self->as_Java_thread(), &in_flight_mutex);
|
||||||
in_flight_mutex = this; // save for ~ThreadBlockInVMWithDeadlockCheck
|
in_flight_mutex = this; // save for ~ThreadBlockInVM
|
||||||
_lock.lock();
|
_lock.lock();
|
||||||
}
|
}
|
||||||
if (in_flight_mutex != NULL) {
|
if (in_flight_mutex != NULL) {
|
||||||
// Not unlocked by ~ThreadBlockInVMWithDeadlockCheck
|
// Not unlocked by ~ThreadBlockInVM
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -236,7 +236,7 @@ bool Monitor::wait(int64_t timeout, bool as_suspend_equivalent) {
|
||||||
Mutex* in_flight_mutex = NULL;
|
Mutex* in_flight_mutex = NULL;
|
||||||
|
|
||||||
{
|
{
|
||||||
ThreadBlockInVMWithDeadlockCheck tbivmdc(self, &in_flight_mutex);
|
ThreadBlockInVM tbivmdc(self, &in_flight_mutex);
|
||||||
OSThreadWaitState osts(self->osthread(), false /* not Object.wait() */);
|
OSThreadWaitState osts(self->osthread(), false /* not Object.wait() */);
|
||||||
if (as_suspend_equivalent) {
|
if (as_suspend_equivalent) {
|
||||||
self->set_suspend_equivalent();
|
self->set_suspend_equivalent();
|
||||||
|
@ -245,7 +245,7 @@ bool Monitor::wait(int64_t timeout, bool as_suspend_equivalent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
wait_status = _lock.wait(timeout);
|
wait_status = _lock.wait(timeout);
|
||||||
in_flight_mutex = this; // save for ~ThreadBlockInVMWithDeadlockCheck
|
in_flight_mutex = this; // save for ~ThreadBlockInVM
|
||||||
|
|
||||||
// were we externally suspended while we were waiting?
|
// were we externally suspended while we were waiting?
|
||||||
if (as_suspend_equivalent && self->handle_special_suspend_equivalent_condition()) {
|
if (as_suspend_equivalent && self->handle_special_suspend_equivalent_condition()) {
|
||||||
|
@ -260,7 +260,7 @@ bool Monitor::wait(int64_t timeout, bool as_suspend_equivalent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_flight_mutex != NULL) {
|
if (in_flight_mutex != NULL) {
|
||||||
// Not unlocked by ~ThreadBlockInVMWithDeadlockCheck
|
// Not unlocked by ~ThreadBlockInVM
|
||||||
assert_owner(NULL);
|
assert_owner(NULL);
|
||||||
// Conceptually reestablish ownership of the lock.
|
// Conceptually reestablish ownership of the lock.
|
||||||
set_owner(self);
|
set_owner(self);
|
||||||
|
|
|
@ -968,7 +968,7 @@ void ThreadSafepointState::handle_polling_page_exception() {
|
||||||
// If we have a pending async exception deoptimize the frame
|
// If we have a pending async exception deoptimize the frame
|
||||||
// as otherwise we may never deliver it.
|
// as otherwise we may never deliver it.
|
||||||
if (self->has_async_condition()) {
|
if (self->has_async_condition()) {
|
||||||
ThreadInVMfromJavaNoAsyncException __tiv(self);
|
ThreadInVMfromJava __tiv(self, false /* check asyncs */);
|
||||||
Deoptimization::deoptimize_frame(self, caller_fr.id());
|
Deoptimization::deoptimize_frame(self, caller_fr.id());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue