Skip to content

Commit 97ec5ad

Browse files
committed
8265753: Remove manual JavaThread transitions to blocked
Reviewed-by: dcubed, rrich, dholmes, pchilanomate
1 parent 6eb9114 commit 97ec5ad

8 files changed

+190
-221
lines changed

src/hotspot/share/prims/jvmtiEnv.cpp

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3191,31 +3191,7 @@ JvmtiEnv::RawMonitorEnter(JvmtiRawMonitor * rmonitor) {
31913191
// in thread.cpp.
31923192
JvmtiPendingMonitors::enter(rmonitor);
31933193
} else {
3194-
Thread* thread = Thread::current();
3195-
if (thread->is_Java_thread()) {
3196-
JavaThread* current_thread = thread->as_Java_thread();
3197-
3198-
/* Transition to thread_blocked without entering vm state */
3199-
/* This is really evil. Normally you can't undo _thread_blocked */
3200-
/* transitions like this because it would cause us to miss a */
3201-
/* safepoint but since the thread was already in _thread_in_native */
3202-
/* the thread is not leaving a safepoint safe state and it will */
3203-
/* block when it tries to return from native. We can't safepoint */
3204-
/* block in here because we could deadlock the vmthread. Blech. */
3205-
3206-
JavaThreadState state = current_thread->thread_state();
3207-
assert(state == _thread_in_native, "Must be _thread_in_native");
3208-
// frame should already be walkable since we are in native
3209-
assert(!current_thread->has_last_Java_frame() ||
3210-
current_thread->frame_anchor()->walkable(), "Must be walkable");
3211-
current_thread->set_thread_state(_thread_blocked);
3212-
3213-
rmonitor->raw_enter(current_thread);
3214-
// restore state, still at a safepoint safe state
3215-
current_thread->set_thread_state(state);
3216-
} else {
3217-
rmonitor->raw_enter(thread);
3218-
}
3194+
rmonitor->raw_enter(Thread::current());
32193195
}
32203196
return JVMTI_ERROR_NONE;
32213197
} /* end RawMonitorEnter */

src/hotspot/share/prims/jvmtiRawMonitor.cpp

Lines changed: 60 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,12 @@ void JvmtiPendingMonitors::transition_raw_monitors() {
4343
"Java thread has not been created yet or more than one java thread "
4444
"is running. Raw monitor transition will not work");
4545
JavaThread* current_java_thread = JavaThread::current();
46-
assert(current_java_thread->thread_state() == _thread_in_vm, "Must be in vm");
47-
for (int i = 0; i < count(); i++) {
48-
JvmtiRawMonitor* rmonitor = monitors()->at(i);
49-
rmonitor->raw_enter(current_java_thread);
46+
{
47+
ThreadToNativeFromVM ttnfvm(current_java_thread);
48+
for (int i = 0; i < count(); i++) {
49+
JvmtiRawMonitor* rmonitor = monitors()->at(i);
50+
rmonitor->raw_enter(current_java_thread);
51+
}
5052
}
5153
// pending monitors are converted to real monitor so delete them all.
5254
dispose();
@@ -60,7 +62,6 @@ JvmtiRawMonitor::JvmtiRawMonitor(const char* name) : _owner(NULL),
6062
_recursions(0),
6163
_entry_list(NULL),
6264
_wait_set(NULL),
63-
_waiters(0),
6465
_magic(JVMTI_RM_MAGIC),
6566
_name(NULL) {
6667
#ifdef ASSERT
@@ -217,11 +218,12 @@ inline void JvmtiRawMonitor::dequeue_waiter(QNode& node) {
217218
// simple_wait is not quite so simple as we have to deal with the interaction
218219
// with the Thread interrupt state, which resides in the java.lang.Thread object.
219220
// That state must only be accessed while _thread_in_vm and requires proper thread-state
220-
// transitions. However, we cannot perform such transitions whilst we hold the RawMonitor,
221-
// else we can deadlock with the VMThread (which may also use RawMonitors as part of
222-
// executing various callbacks).
221+
// transitions.
223222
// Returns M_OK usually, but M_INTERRUPTED if the thread is a JavaThread and was
224223
// interrupted.
224+
// Note:
225+
// - simple_wait never reenters the monitor.
226+
// - A JavaThread must be in native.
225227
int JvmtiRawMonitor::simple_wait(Thread* self, jlong millis) {
226228
guarantee(_owner == self , "invariant");
227229
guarantee(_recursions == 0, "invariant");
@@ -235,21 +237,24 @@ int JvmtiRawMonitor::simple_wait(Thread* self, jlong millis) {
235237
int ret = M_OK;
236238
if (self->is_Java_thread()) {
237239
JavaThread* jt = self->as_Java_thread();
238-
// Transition to VM so we can check interrupt state
239-
ThreadInVMfromNative tivm(jt);
240-
if (jt->is_interrupted(true)) {
240+
guarantee(jt->thread_state() == _thread_in_native, "invariant");
241+
{
242+
// This transition must be after we exited the monitor.
243+
ThreadInVMfromNative tivmfn(jt);
244+
if (jt->is_interrupted(true)) {
241245
ret = M_INTERRUPTED;
242-
} else {
243-
ThreadBlockInVM tbivm(jt);
244-
if (millis <= 0) {
245-
self->_ParkEvent->park();
246246
} else {
247-
self->_ParkEvent->park(millis);
247+
ThreadBlockInVM tbivm(jt);
248+
if (millis <= 0) {
249+
self->_ParkEvent->park();
250+
} else {
251+
self->_ParkEvent->park(millis);
252+
}
253+
// Return to VM before post-check of interrupt state
254+
}
255+
if (jt->is_interrupted(true)) {
256+
ret = M_INTERRUPTED;
248257
}
249-
// Return to VM before post-check of interrupt state
250-
}
251-
if (jt->is_interrupted(true)) {
252-
ret = M_INTERRUPTED;
253258
}
254259
} else {
255260
if (millis <= 0) {
@@ -261,10 +266,6 @@ int JvmtiRawMonitor::simple_wait(Thread* self, jlong millis) {
261266

262267
dequeue_waiter(node);
263268

264-
simple_enter(self);
265-
guarantee(_owner == self, "invariant");
266-
guarantee(_recursions == 0, "invariant");
267-
268269
return ret;
269270
}
270271

@@ -306,75 +307,37 @@ void JvmtiRawMonitor::simple_notify(Thread* self, bool all) {
306307
return;
307308
}
308309

309-
// Any JavaThread will enter here with state _thread_blocked unless we
310-
// are in single-threaded mode during startup.
311-
void JvmtiRawMonitor::raw_enter(Thread* self) {
312-
void* contended;
313-
JavaThread* jt = NULL;
314-
// don't enter raw monitor if thread is being externally suspended, it will
315-
// surprise the suspender if a "suspended" thread can still enter monitor
316-
if (self->is_Java_thread()) {
317-
jt = self->as_Java_thread();
318-
while (true) {
319-
// To pause suspend requests while in blocked we must block handshakes.
320-
jt->handshake_state()->lock();
321-
// Suspend request flag can only be set in handshakes.
322-
// By blocking handshakes, suspend request flag cannot change its value.
323-
if (!jt->handshake_state()->is_suspended()) {
324-
contended = Atomic::cmpxchg(&_owner, (Thread*)NULL, jt);
325-
jt->handshake_state()->unlock();
326-
break;
327-
}
328-
jt->handshake_state()->unlock();
329-
330-
// We may only be in states other than _thread_blocked when we are
331-
// in single-threaded mode during startup.
332-
guarantee(jt->thread_state() == _thread_blocked, "invariant");
333-
334-
jt->set_thread_state_fence(_thread_blocked_trans);
335-
SafepointMechanism::process_if_requested(jt);
336-
// We should transition to thread_in_vm and then to thread_in_vm_trans,
337-
// but those are always treated the same as _thread_blocked_trans.
338-
jt->set_thread_state(_thread_blocked);
339-
}
340-
} else {
341-
contended = Atomic::cmpxchg(&_owner, (Thread*)NULL, self);
342-
}
310+
void JvmtiRawMonitor::ExitOnSuspend::operator()(JavaThread* current) {
311+
// We must exit the monitor in case of a safepoint.
312+
_rm->simple_exit(current);
313+
_rm_exited = true;
314+
}
343315

344-
if (contended == self) {
316+
// JavaThreads will enter here with state _thread_in_native.
317+
void JvmtiRawMonitor::raw_enter(Thread* self) {
318+
// TODO Atomic::load on _owner field
319+
if (_owner == self) {
345320
_recursions++;
346321
return;
347322
}
348323

349-
if (contended == NULL) {
350-
guarantee(_owner == self, "invariant");
351-
guarantee(_recursions == 0, "invariant");
352-
return;
353-
}
354-
355324
self->set_current_pending_raw_monitor(this);
356325

357326
if (!self->is_Java_thread()) {
358327
simple_enter(self);
359328
} else {
360-
// In multi-threaded mode, we must enter this method blocked.
361-
guarantee(jt->thread_state() == _thread_blocked, "invariant");
329+
JavaThread* jt = self->as_Java_thread();
330+
guarantee(jt->thread_state() == _thread_in_native, "invariant");
331+
ThreadInVMfromNative tivmfn(jt);
362332
for (;;) {
363-
simple_enter(jt);
364-
if (!SafepointMechanism::should_process(jt)) {
365-
// Not suspended so we're done here.
366-
break;
333+
ExitOnSuspend eos(this);
334+
{
335+
ThreadBlockInVMPreprocess<ExitOnSuspend> tbivmp(jt, eos);
336+
simple_enter(jt);
367337
}
368-
if (!jt->is_suspended()) {
369-
// Not suspended so we're done here.
338+
if (!eos.monitor_exited()) {
370339
break;
371340
}
372-
simple_exit(jt);
373-
jt->set_thread_state_fence(_thread_blocked_trans);
374-
SafepointMechanism::process_if_requested(jt);
375-
// We should transition to thread_in_vm and then to thread_in_vm_trans,
376-
// but those are always treated the same as _thread_blocked_trans.
377-
jt->set_thread_state(_thread_blocked);
378341
}
379342
}
380343

@@ -411,37 +374,34 @@ int JvmtiRawMonitor::raw_wait(jlong millis, Thread* self) {
411374

412375
intptr_t save = _recursions;
413376
_recursions = 0;
414-
_waiters++;
415377
ret = simple_wait(self, millis);
416-
_recursions = save;
417-
_waiters--;
418-
419-
guarantee(self == _owner, "invariant");
420378

421-
if (self->is_Java_thread()) {
379+
// Now we need to re-enter the monitor. For JavaThreads
380+
// we need to manage suspend requests.
381+
if (self->is_Java_thread()) { // JavaThread re-enter
422382
JavaThread* jt = self->as_Java_thread();
423-
guarantee(jt->thread_state() == _thread_in_native, "invariant");
383+
ThreadInVMfromNative tivmfn(jt);
424384
for (;;) {
425-
if (!SafepointMechanism::should_process(jt)) {
426-
// Not suspended so we're done here:
427-
break;
385+
ExitOnSuspend eos(this);
386+
{
387+
ThreadBlockInVMPreprocess<ExitOnSuspend> tbivmp(jt, eos);
388+
simple_enter(jt);
428389
}
429-
simple_exit(jt);
430-
jt->set_thread_state_fence(_thread_in_native_trans);
431-
SafepointMechanism::process_if_requested(jt);
432-
if (jt->is_interrupted(true)) {
433-
ret = M_INTERRUPTED;
390+
if (!eos.monitor_exited()) {
391+
break;
434392
}
435-
// We should transition to thread_in_vm and then to thread_in_vm_trans,
436-
// but those are always treated the same as _thread_in_native_trans.
437-
jt->set_thread_state(_thread_in_native);
438-
simple_enter(jt);
439393
}
440-
guarantee(jt == _owner, "invariant");
441-
} else {
394+
if (jt->is_interrupted(true)) {
395+
ret = M_INTERRUPTED;
396+
}
397+
} else { // Non-JavaThread re-enter
442398
assert(ret != M_INTERRUPTED, "Only JavaThreads can be interrupted");
399+
simple_enter(self);
443400
}
444401

402+
_recursions = save;
403+
404+
guarantee(self == _owner, "invariant");
445405
return ret;
446406
}
447407

src/hotspot/share/prims/jvmtiRawMonitor.hpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,21 @@
3737
// A simplified version of the ObjectMonitor code.
3838
//
3939

40+
// Important note:
41+
// Raw monitors can be used in callbacks which happen during safepoint by the VM
42+
// thread (e.g., heapRootCallback). This means we may not transition/safepoint
43+
// poll in many cases, else the agent JavaThread can deadlock with the VM thread,
44+
// as this old comment says:
45+
// "We can't safepoint block in here because we could deadlock the vmthread. Blech."
46+
// The rules are:
47+
// - We must never safepoint poll if raw monitor is owned.
48+
// - We may safepoint poll before it is owned and after it has been released.
49+
// If this were the only thing we needed to think about we could just stay in
50+
// native for all operations. However we need to honor a suspend request, not
51+
// entering a monitor if suspended, and check for interrupts. Honoring a suspend
52+
// request and reading the interrupt flag must be done from VM state
53+
// (a safepoint unsafe state).
54+
4055
class JvmtiRawMonitor : public CHeapObj<mtSynchronizer> {
4156

4257
// Helper class to allow Threads to be linked into queues.
@@ -59,7 +74,6 @@ class JvmtiRawMonitor : public CHeapObj<mtSynchronizer> {
5974
// The list is actually composed of nodes,
6075
// acting as proxies for Threads.
6176
QNode* volatile _wait_set; // Threads wait()ing on the monitor
62-
volatile jint _waiters; // number of waiting threads
6377
int _magic;
6478
char* _name;
6579
// JVMTI_RM_MAGIC is set in contructor and unset in destructor.
@@ -75,6 +89,16 @@ class JvmtiRawMonitor : public CHeapObj<mtSynchronizer> {
7589
int simple_wait(Thread* self, jlong millis);
7690
void simple_notify(Thread* self, bool all);
7791

92+
class ExitOnSuspend {
93+
protected:
94+
JvmtiRawMonitor* _rm;
95+
bool _rm_exited;
96+
public:
97+
ExitOnSuspend(JvmtiRawMonitor* rm) : _rm(rm), _rm_exited(false) {}
98+
void operator()(JavaThread* current);
99+
bool monitor_exited() { return _rm_exited; }
100+
};
101+
78102
public:
79103

80104
// return codes

src/hotspot/share/runtime/handshake.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -600,14 +600,6 @@ HandshakeState::ProcessResult HandshakeState::try_process(HandshakeOperation* ma
600600
return pr_ret;
601601
}
602602

603-
void HandshakeState::lock() {
604-
_lock.lock_without_safepoint_check();
605-
}
606-
607-
void HandshakeState::unlock() {
608-
_lock.unlock();
609-
}
610-
611603
void HandshakeState::do_self_suspend() {
612604
assert(Thread::current() == _handshakee, "should call from _handshakee");
613605
assert(_lock.owned_by_self(), "Lock must be held");

src/hotspot/share/runtime/handshake.hpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ class JvmtiRawMonitor;
7373
// operation is only done by either VMThread/Handshaker on behalf of the
7474
// JavaThread or by the target JavaThread itself.
7575
class HandshakeState {
76-
friend JvmtiRawMonitor;
7776
friend ThreadSelfSuspensionHandshake;
7877
friend SuspendThreadHandshake;
7978
friend JavaThread;
@@ -103,9 +102,6 @@ class HandshakeState {
103102
HandshakeOperation* pop_for_self();
104103
HandshakeOperation* pop();
105104

106-
void lock();
107-
void unlock();
108-
109105
public:
110106
HandshakeState(JavaThread* thread);
111107

0 commit comments

Comments
 (0)