Skip to content

Commit 39549f8

Browse files
committed
8352116: Deadlock with GCLocker and JVMTI after JDK-8192647
Reviewed-by: kbarrett, tschatzl, eosterlund
1 parent d63b561 commit 39549f8

File tree

4 files changed

+24
-11
lines changed

4 files changed

+24
-11
lines changed

src/hotspot/share/gc/shared/gcLocker.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ volatile bool GCLocker::_is_gc_request_pending;
6565
DEBUG_ONLY(uint64_t GCLocker::_verify_in_cr_count;)
6666

6767
void GCLocker::initialize() {
68-
assert(Heap_lock != nullptr, "inv");
69-
_lock = Heap_lock;
68+
assert(JNICritical_lock != nullptr, "inv");
69+
_lock = JNICritical_lock;
7070
_is_gc_request_pending = false;
7171

7272
DEBUG_ONLY(_verify_in_cr_count = 0;)
@@ -82,7 +82,8 @@ bool GCLocker::is_active() {
8282
}
8383

8484
void GCLocker::block() {
85-
assert(_lock->is_locked(), "precondition");
85+
// _lock is held from the beginning of block() to the end of of unblock().
86+
_lock->lock();
8687
assert(Atomic::load(&_is_gc_request_pending) == false, "precondition");
8788

8889
GCLockerTimingDebugLogger logger("Thread blocked to start GC.");
@@ -116,10 +117,10 @@ void GCLocker::block() {
116117
}
117118

118119
void GCLocker::unblock() {
119-
assert(_lock->is_locked(), "precondition");
120120
assert(Atomic::load(&_is_gc_request_pending) == true, "precondition");
121121

122122
Atomic::store(&_is_gc_request_pending, false);
123+
_lock->unlock();
123124
}
124125

125126
void GCLocker::enter_slow(JavaThread* current_thread) {

src/hotspot/share/gc/shared/gcVMOperations.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ bool VM_GC_Operation::skip_operation() const {
9393
return skip;
9494
}
9595

96+
static bool should_use_gclocker() {
97+
// Only Serial and Parallel use GCLocker to synchronize with threads in JNI critical-sections, in order to handle pinned objects.
98+
return UseSerialGC || UseParallelGC;
99+
}
100+
96101
bool VM_GC_Operation::doit_prologue() {
97102
assert(((_gc_cause != GCCause::_no_gc) &&
98103
(_gc_cause != GCCause::_no_cause_specified)), "Illegal GCCause");
@@ -106,34 +111,38 @@ bool VM_GC_Operation::doit_prologue() {
106111
proper_unit_for_byte_size(NewSize)));
107112
}
108113

114+
115+
if (should_use_gclocker()) {
116+
GCLocker::block();
117+
}
109118
VM_GC_Sync_Operation::doit_prologue();
110119

111120
// Check invocations
112121
if (skip_operation()) {
113122
// skip collection
114123
Heap_lock->unlock();
124+
if (should_use_gclocker()) {
125+
GCLocker::unblock();
126+
}
115127
_prologue_succeeded = false;
116128
} else {
117-
if (UseSerialGC || UseParallelGC) {
118-
GCLocker::block();
119-
}
120129
_prologue_succeeded = true;
121130
}
122131
return _prologue_succeeded;
123132
}
124133

125134

126135
void VM_GC_Operation::doit_epilogue() {
127-
if (UseSerialGC || UseParallelGC) {
128-
GCLocker::unblock();
129-
}
130136
// GC thread root traversal likely used OopMapCache a lot, which
131137
// might have created lots of old entries. Trigger the cleanup now.
132138
OopMapCache::try_trigger_cleanup();
133139
if (Universe::has_reference_pending_list()) {
134140
Heap_lock->notify_all();
135141
}
136142
VM_GC_Sync_Operation::doit_epilogue();
143+
if (should_use_gclocker()) {
144+
GCLocker::unblock();
145+
}
137146
}
138147

139148
bool VM_GC_HeapInspection::doit_prologue() {

src/hotspot/share/runtime/mutexLocker.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ Mutex* CompiledIC_lock = nullptr;
4646
Mutex* VMStatistic_lock = nullptr;
4747
Mutex* JmethodIdCreation_lock = nullptr;
4848
Mutex* JfieldIdCreation_lock = nullptr;
49+
Monitor* JNICritical_lock = nullptr;
4950
Mutex* JvmtiThreadState_lock = nullptr;
5051
Monitor* EscapeBarrier_lock = nullptr;
5152
Monitor* JvmtiVTMSTransition_lock = nullptr;
@@ -318,7 +319,8 @@ void mutex_init() {
318319

319320
MUTEX_DEFL(Threads_lock , PaddedMonitor, CompileThread_lock, true);
320321
MUTEX_DEFL(Compile_lock , PaddedMutex , MethodCompileQueue_lock);
321-
MUTEX_DEFL(Heap_lock , PaddedMonitor, AdapterHandlerLibrary_lock);
322+
MUTEX_DEFL(JNICritical_lock , PaddedMonitor, AdapterHandlerLibrary_lock); // used for JNI critical regions
323+
MUTEX_DEFL(Heap_lock , PaddedMonitor, JNICritical_lock);
322324

323325
MUTEX_DEFL(PerfDataMemAlloc_lock , PaddedMutex , Heap_lock);
324326
MUTEX_DEFL(PerfDataManager_lock , PaddedMutex , Heap_lock);

src/hotspot/share/runtime/mutexLocker.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ extern Mutex* CompiledIC_lock; // a lock used to guard compile
4444
extern Mutex* VMStatistic_lock; // a lock used to guard statistics count increment
4545
extern Mutex* JmethodIdCreation_lock; // a lock on creating JNI method identifiers
4646
extern Mutex* JfieldIdCreation_lock; // a lock on creating JNI static field identifiers
47+
extern Monitor* JNICritical_lock; // a lock used while synchronizing with threads entering/leaving JNI critical regions
4748
extern Mutex* JvmtiThreadState_lock; // a lock on modification of JVMTI thread data
4849
extern Monitor* EscapeBarrier_lock; // a lock to sync reallocating and relocking objects because of JVMTI access
4950
extern Monitor* JvmtiVTMSTransition_lock; // a lock for Virtual Thread Mount State transition (VTMS transition) management

0 commit comments

Comments
 (0)