8231289: Disentangle JvmtiRawMonitor from ObjectMonitor and clean it up

Reviewed-by: sspitsyn, dcubed, coleenp
This commit is contained in:
David Holmes 2019-10-07 18:44:53 -04:00
parent b1bffdfa00
commit f3df804e24
9 changed files with 333 additions and 326 deletions

View File

@ -3229,23 +3229,23 @@ JvmtiEnv::CreateRawMonitor(const char* name, jrawMonitorID* monitor_ptr) {
jvmtiError
JvmtiEnv::DestroyRawMonitor(JvmtiRawMonitor * rmonitor) {
if (Threads::number_of_threads() == 0) {
// Remove this monitor from pending raw monitors list
// Remove this monitor from pending raw monitors list
// if it has entered in onload or start phase.
JvmtiPendingMonitors::destroy(rmonitor);
} else {
Thread* thread = Thread::current();
if (rmonitor->is_entered(thread)) {
if (rmonitor->owner() == thread) {
// The caller owns this monitor which we are about to destroy.
// We exit the underlying synchronization object so that the
// "delete monitor" call below can work without an assertion
// failure on systems that don't like destroying synchronization
// objects that are locked.
int r;
intptr_t recursion = rmonitor->recursions();
for (intptr_t i = 0; i <= recursion; i++) {
int recursion = rmonitor->recursions();
for (int i = 0; i <= recursion; i++) {
r = rmonitor->raw_exit(thread);
assert(r == ObjectMonitor::OM_OK, "raw_exit should have worked");
if (r != ObjectMonitor::OM_OK) { // robustness
assert(r == JvmtiRawMonitor::M_OK, "raw_exit should have worked");
if (r != JvmtiRawMonitor::M_OK) { // robustness
return JVMTI_ERROR_INTERNAL;
}
}
@ -3271,7 +3271,7 @@ JvmtiEnv::DestroyRawMonitor(JvmtiRawMonitor * rmonitor) {
jvmtiError
JvmtiEnv::RawMonitorEnter(JvmtiRawMonitor * rmonitor) {
if (Threads::number_of_threads() == 0) {
// No JavaThreads exist so ObjectMonitor enter cannot be
// No JavaThreads exist so JvmtiRawMonitor enter cannot be
// used, add this raw monitor to the pending list.
// The pending monitors will be actually entered when
// the VM is setup.
@ -3279,20 +3279,10 @@ JvmtiEnv::RawMonitorEnter(JvmtiRawMonitor * rmonitor) {
// in thread.cpp.
JvmtiPendingMonitors::enter(rmonitor);
} else {
int r = 0;
Thread* thread = Thread::current();
if (thread->is_Java_thread()) {
JavaThread* current_thread = (JavaThread*)thread;
#ifdef PROPER_TRANSITIONS
// Not really unknown but ThreadInVMfromNative does more than we want
ThreadInVMfromUnknown __tiv;
{
ThreadBlockInVM __tbivm(current_thread);
r = rmonitor->raw_enter(current_thread);
}
#else
/* Transition to thread_blocked without entering vm state */
/* This is really evil. Normally you can't undo _thread_blocked */
/* transitions like this because it would cause us to miss a */
@ -3308,22 +3298,11 @@ JvmtiEnv::RawMonitorEnter(JvmtiRawMonitor * rmonitor) {
current_thread->frame_anchor()->walkable(), "Must be walkable");
current_thread->set_thread_state(_thread_blocked);
r = rmonitor->raw_enter(current_thread);
rmonitor->raw_enter(current_thread);
// restore state, still at a safepoint safe state
current_thread->set_thread_state(state);
#endif /* PROPER_TRANSITIONS */
assert(r == ObjectMonitor::OM_OK, "raw_enter should have worked");
} else {
if (thread->is_Named_thread()) {
r = rmonitor->raw_enter(thread);
} else {
ShouldNotReachHere();
}
}
if (r != ObjectMonitor::OM_OK) { // robustness
return JVMTI_ERROR_INTERNAL;
rmonitor->raw_enter(thread);
}
}
return JVMTI_ERROR_NONE;
@ -3342,31 +3321,10 @@ JvmtiEnv::RawMonitorExit(JvmtiRawMonitor * rmonitor) {
err = JVMTI_ERROR_NOT_MONITOR_OWNER;
}
} else {
int r = 0;
Thread* thread = Thread::current();
if (thread->is_Java_thread()) {
JavaThread* current_thread = (JavaThread*)thread;
#ifdef PROPER_TRANSITIONS
// Not really unknown but ThreadInVMfromNative does more than we want
ThreadInVMfromUnknown __tiv;
#endif /* PROPER_TRANSITIONS */
r = rmonitor->raw_exit(current_thread);
} else {
if (thread->is_Named_thread()) {
r = rmonitor->raw_exit(thread);
} else {
ShouldNotReachHere();
}
}
if (r == ObjectMonitor::OM_ILLEGAL_MONITOR_STATE) {
int r = rmonitor->raw_exit(thread);
if (r == JvmtiRawMonitor::M_ILLEGAL_MONITOR_STATE) {
err = JVMTI_ERROR_NOT_MONITOR_OWNER;
} else {
assert(r == ObjectMonitor::OM_OK, "raw_exit should have worked");
if (r != ObjectMonitor::OM_OK) { // robustness
err = JVMTI_ERROR_INTERNAL;
}
}
}
return err;
@ -3381,14 +3339,7 @@ JvmtiEnv::RawMonitorWait(JvmtiRawMonitor * rmonitor, jlong millis) {
if (thread->is_Java_thread()) {
JavaThread* current_thread = (JavaThread*)thread;
#ifdef PROPER_TRANSITIONS
// Not really unknown but ThreadInVMfromNative does more than we want
ThreadInVMfromUnknown __tiv;
{
ThreadBlockInVM __tbivm(current_thread);
r = rmonitor->raw_wait(millis, true, current_thread);
}
#else
/* Transition to thread_blocked without entering vm state */
/* This is really evil. Normally you can't undo _thread_blocked */
/* transitions like this because it would cause us to miss a */
@ -3408,57 +3359,31 @@ JvmtiEnv::RawMonitorWait(JvmtiRawMonitor * rmonitor, jlong millis) {
// restore state, still at a safepoint safe state
current_thread->set_thread_state(state);
#endif /* PROPER_TRANSITIONS */
} else {
if (thread->is_Named_thread()) {
r = rmonitor->raw_wait(millis, false, thread);
} else {
ShouldNotReachHere();
}
assert(r != JvmtiRawMonitor::M_INTERRUPTED, "non-JavaThread can't be interrupted");
}
switch (r) {
case ObjectMonitor::OM_INTERRUPTED:
case JvmtiRawMonitor::M_INTERRUPTED:
return JVMTI_ERROR_INTERRUPT;
case ObjectMonitor::OM_ILLEGAL_MONITOR_STATE:
case JvmtiRawMonitor::M_ILLEGAL_MONITOR_STATE:
return JVMTI_ERROR_NOT_MONITOR_OWNER;
default:
return JVMTI_ERROR_NONE;
}
assert(r == ObjectMonitor::OM_OK, "raw_wait should have worked");
if (r != ObjectMonitor::OM_OK) { // robustness
return JVMTI_ERROR_INTERNAL;
}
return JVMTI_ERROR_NONE;
} /* end RawMonitorWait */
// rmonitor - pre-checked for validity
jvmtiError
JvmtiEnv::RawMonitorNotify(JvmtiRawMonitor * rmonitor) {
int r = 0;
Thread* thread = Thread::current();
int r = rmonitor->raw_notify(thread);
if (thread->is_Java_thread()) {
JavaThread* current_thread = (JavaThread*)thread;
// Not really unknown but ThreadInVMfromNative does more than we want
ThreadInVMfromUnknown __tiv;
r = rmonitor->raw_notify(current_thread);
} else {
if (thread->is_Named_thread()) {
r = rmonitor->raw_notify(thread);
} else {
ShouldNotReachHere();
}
}
if (r == ObjectMonitor::OM_ILLEGAL_MONITOR_STATE) {
if (r == JvmtiRawMonitor::M_ILLEGAL_MONITOR_STATE) {
return JVMTI_ERROR_NOT_MONITOR_OWNER;
}
assert(r == ObjectMonitor::OM_OK, "raw_notify should have worked");
if (r != ObjectMonitor::OM_OK) { // robustness
return JVMTI_ERROR_INTERNAL;
}
return JVMTI_ERROR_NONE;
} /* end RawMonitorNotify */
@ -3466,29 +3391,12 @@ JvmtiEnv::RawMonitorNotify(JvmtiRawMonitor * rmonitor) {
// rmonitor - pre-checked for validity
jvmtiError
JvmtiEnv::RawMonitorNotifyAll(JvmtiRawMonitor * rmonitor) {
int r = 0;
Thread* thread = Thread::current();
int r = rmonitor->raw_notifyAll(thread);
if (thread->is_Java_thread()) {
JavaThread* current_thread = (JavaThread*)thread;
ThreadInVMfromUnknown __tiv;
r = rmonitor->raw_notifyAll(current_thread);
} else {
if (thread->is_Named_thread()) {
r = rmonitor->raw_notifyAll(thread);
} else {
ShouldNotReachHere();
}
}
if (r == ObjectMonitor::OM_ILLEGAL_MONITOR_STATE) {
if (r == JvmtiRawMonitor::M_ILLEGAL_MONITOR_STATE) {
return JVMTI_ERROR_NOT_MONITOR_OWNER;
}
assert(r == ObjectMonitor::OM_OK, "raw_notifyAll should have worked");
if (r != ObjectMonitor::OM_OK) { // robustness
return JVMTI_ERROR_INTERNAL;
}
return JVMTI_ERROR_NONE;
} /* end RawMonitorNotifyAll */

View File

@ -659,10 +659,9 @@ JvmtiEnvBase::get_current_contended_monitor(JavaThread *calling_thread, JavaThre
// thread is not doing an Object.wait() call
mon = java_thread->current_pending_monitor();
if (mon != NULL) {
// The thread is trying to enter() or raw_enter() an ObjectMonitor.
// The thread is trying to enter() an ObjectMonitor.
obj = (oop)mon->object();
// If obj == NULL, then ObjectMonitor is raw which doesn't count
// as contended for this API
assert(obj != NULL, "ObjectMonitor should have a valid object!");
}
// implied else: no contended ObjectMonitor
} else {

View File

@ -30,21 +30,23 @@
#include "runtime/orderAccess.hpp"
#include "runtime/thread.inline.hpp"
GrowableArray<JvmtiRawMonitor*> *JvmtiPendingMonitors::_monitors = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<JvmtiRawMonitor*>(1,true);
JvmtiRawMonitor::QNode::QNode(Thread* thread) : _next(NULL), _prev(NULL),
_event(thread->_ParkEvent),
_notified(0), TState(TS_RUN) {
}
GrowableArray<JvmtiRawMonitor*> *JvmtiPendingMonitors::_monitors =
new (ResourceObj::C_HEAP, mtInternal) GrowableArray<JvmtiRawMonitor*>(1, true);
void JvmtiPendingMonitors::transition_raw_monitors() {
assert((Threads::number_of_threads()==1),
"Java thread has not created yet or more than one java thread \
"Java thread has not been created yet or more than one java thread \
is running. Raw monitor transition will not work");
JavaThread *current_java_thread = JavaThread::current();
assert(current_java_thread->thread_state() == _thread_in_vm, "Must be in vm");
{
ThreadBlockInVM __tbivm(current_java_thread);
for(int i=0; i< count(); i++) {
JvmtiRawMonitor *rmonitor = monitors()->at(i);
int r = rmonitor->raw_enter(current_java_thread);
assert(r == ObjectMonitor::OM_OK, "raw_enter should have worked");
}
for(int i=0; i< count(); i++) {
JvmtiRawMonitor *rmonitor = monitors()->at(i);
rmonitor->raw_enter(current_java_thread);
}
// pending monitors are converted to real monitor so delete them all.
dispose();
@ -54,13 +56,16 @@ is running. Raw monitor transition will not work");
// class JvmtiRawMonitor
//
JvmtiRawMonitor::JvmtiRawMonitor(const char *name) {
JvmtiRawMonitor::JvmtiRawMonitor(const char *name) : _owner(NULL),
_recursions(0),
_EntryList(NULL),
_WaitSet(NULL),
_waiters(0),
_magic(JVMTI_RM_MAGIC),
_name(NULL) {
#ifdef ASSERT
_name = strcpy(NEW_C_HEAP_ARRAY(char, strlen(name) + 1, mtInternal), name);
#else
_name = NULL;
#endif
_magic = JVMTI_RM_MAGIC;
}
JvmtiRawMonitor::~JvmtiRawMonitor() {
@ -100,41 +105,29 @@ JvmtiRawMonitor::is_valid() {
}
// -------------------------------------------------------------------------
// The raw monitor subsystem is entirely distinct from normal
// java-synchronization or jni-synchronization. raw monitors are not
// The JVMTI raw monitor subsystem is entirely distinct from normal
// java-synchronization or jni-synchronization. JVMTI raw monitors are not
// associated with objects. They can be implemented in any manner
// that makes sense. The original implementors decided to piggy-back
// the raw-monitor implementation on the existing Java objectMonitor mechanism.
// This flaw needs to fixed. We should reimplement raw monitors as sui-generis.
// Specifically, we should not implement raw monitors via java monitors.
// Time permitting, we should disentangle and deconvolve the two implementations
// and move the resulting raw monitor implementation over to the JVMTI directories.
// Ideally, the raw monitor implementation would be built on top of
// park-unpark and nothing else.
//
// raw monitors are used mainly by JVMTI
// The raw monitor implementation borrows the ObjectMonitor structure,
// but the operators are degenerate and extremely simple.
//
// Mixed use of a single objectMonitor instance -- as both a raw monitor
// and a normal java monitor -- is not permissible.
// the raw-monitor implementation on the existing Java ObjectMonitor mechanism.
// Now we just use a simplified form of that ObjectMonitor code.
//
// Note that we use the single RawMonitor_lock to protect queue operations for
// _all_ raw monitors. This is a scalability impediment, but since raw monitor usage
// is deprecated and rare, this is not of concern. The RawMonitor_lock can not
// is fairly rare, this is not of concern. The RawMonitor_lock can not
// be held indefinitely. The critical sections must be short and bounded.
//
// -------------------------------------------------------------------------
int JvmtiRawMonitor::SimpleEnter (Thread * Self) {
void JvmtiRawMonitor::SimpleEnter (Thread * Self) {
for (;;) {
if (Atomic::replace_if_null(Self, &_owner)) {
return OS_OK ;
return ;
}
ObjectWaiter Node (Self) ;
QNode Node (Self) ;
Self->_ParkEvent->reset() ; // strictly optional
Node.TState = ObjectWaiter::TS_ENTER ;
Node.TState = QNode::TS_ENTER ;
RawMonitor_lock->lock_without_safepoint_check() ;
Node._next = _EntryList ;
@ -143,21 +136,21 @@ int JvmtiRawMonitor::SimpleEnter (Thread * Self) {
if (_owner == NULL && Atomic::replace_if_null(Self, &_owner)) {
_EntryList = Node._next ;
RawMonitor_lock->unlock() ;
return OS_OK ;
return ;
}
RawMonitor_lock->unlock() ;
while (Node.TState == ObjectWaiter::TS_ENTER) {
while (Node.TState == QNode::TS_ENTER) {
Self->_ParkEvent->park() ;
}
}
}
int JvmtiRawMonitor::SimpleExit (Thread * Self) {
void JvmtiRawMonitor::SimpleExit (Thread * Self) {
guarantee (_owner == Self, "invariant") ;
OrderAccess::release_store(&_owner, (void*)NULL) ;
OrderAccess::release_store(&_owner, (Thread*)NULL) ;
OrderAccess::fence() ;
if (_EntryList == NULL) return OS_OK ;
ObjectWaiter * w ;
if (_EntryList == NULL) return ;
QNode * w ;
RawMonitor_lock->lock_without_safepoint_check() ;
w = _EntryList ;
@ -166,27 +159,27 @@ int JvmtiRawMonitor::SimpleExit (Thread * Self) {
}
RawMonitor_lock->unlock() ;
if (w != NULL) {
guarantee (w ->TState == ObjectWaiter::TS_ENTER, "invariant") ;
guarantee (w ->TState == QNode::TS_ENTER, "invariant") ;
// Once we set TState to TS_RUN the waiting thread can complete
// SimpleEnter and 'w' is pointing into random stack space. So we have
// to ensure we extract the ParkEvent (which is in type-stable memory)
// before we set the state, and then don't access 'w'.
ParkEvent * ev = w->_event ;
OrderAccess::loadstore();
w->TState = ObjectWaiter::TS_RUN ;
w->TState = QNode::TS_RUN ;
OrderAccess::fence() ;
ev->unpark() ;
}
return OS_OK ;
return ;
}
int JvmtiRawMonitor::SimpleWait (Thread * Self, jlong millis) {
guarantee (_owner == Self , "invariant") ;
guarantee (_recursions == 0, "invariant") ;
ObjectWaiter Node (Self) ;
QNode Node (Self) ;
Node._notified = 0 ;
Node.TState = ObjectWaiter::TS_WAIT ;
Node.TState = QNode::TS_WAIT ;
RawMonitor_lock->lock_without_safepoint_check() ;
Node._next = _WaitSet ;
@ -208,12 +201,12 @@ int JvmtiRawMonitor::SimpleWait (Thread * Self, jlong millis) {
// as TState is volatile and the lock-unlock operators are
// serializing (barrier-equivalent).
if (Node.TState == ObjectWaiter::TS_WAIT) {
if (Node.TState == QNode::TS_WAIT) {
RawMonitor_lock->lock_without_safepoint_check() ;
if (Node.TState == ObjectWaiter::TS_WAIT) {
if (Node.TState == QNode::TS_WAIT) {
// Simple O(n) unlink, but performance isn't critical here.
ObjectWaiter * p ;
ObjectWaiter * q = NULL ;
QNode * p ;
QNode * q = NULL ;
for (p = _WaitSet ; p != &Node; p = p->_next) {
q = p ;
}
@ -225,12 +218,12 @@ int JvmtiRawMonitor::SimpleWait (Thread * Self, jlong millis) {
guarantee (p == q->_next, "invariant") ;
q->_next = p->_next ;
}
Node.TState = ObjectWaiter::TS_RUN ;
Node.TState = QNode::TS_RUN ;
}
RawMonitor_lock->unlock() ;
}
guarantee (Node.TState == ObjectWaiter::TS_RUN, "invariant") ;
guarantee (Node.TState == QNode::TS_RUN, "invariant") ;
SimpleEnter (Self) ;
guarantee (_owner == Self, "invariant") ;
@ -238,9 +231,9 @@ int JvmtiRawMonitor::SimpleWait (Thread * Self, jlong millis) {
return ret ;
}
int JvmtiRawMonitor::SimpleNotify (Thread * Self, bool All) {
void JvmtiRawMonitor::SimpleNotify (Thread * Self, bool All) {
guarantee (_owner == Self, "invariant") ;
if (_WaitSet == NULL) return OS_OK ;
if (_WaitSet == NULL) return ;
// We have two options:
// A. Transfer the threads from the WaitSet to the EntryList
@ -252,29 +245,29 @@ int JvmtiRawMonitor::SimpleNotify (Thread * Self, bool All) {
ParkEvent * ev = NULL ; // consider using a small auto array ...
RawMonitor_lock->lock_without_safepoint_check() ;
for (;;) {
ObjectWaiter * w = _WaitSet ;
QNode * w = _WaitSet ;
if (w == NULL) break ;
_WaitSet = w->_next ;
if (ev != NULL) { ev->unpark(); ev = NULL; }
ev = w->_event ;
OrderAccess::loadstore() ;
w->TState = ObjectWaiter::TS_RUN ;
w->TState = QNode::TS_RUN ;
OrderAccess::storeload();
if (!All) break ;
}
RawMonitor_lock->unlock() ;
if (ev != NULL) ev->unpark();
return OS_OK ;
return ;
}
// Any JavaThread will enter here with state _thread_blocked
int JvmtiRawMonitor::raw_enter(TRAPS) {
void JvmtiRawMonitor::raw_enter(Thread * Self) {
void * Contended ;
JavaThread * jt = NULL;
// don't enter raw monitor if thread is being externally suspended, it will
// surprise the suspender if a "suspended" thread can still enter monitor
JavaThread * jt = (JavaThread *)THREAD;
if (THREAD->is_Java_thread()) {
if (Self->is_Java_thread()) {
jt = (JavaThread*) Self;
jt->SR_lock()->lock_without_safepoint_check();
while (jt->is_external_suspend()) {
jt->SR_lock()->unlock();
@ -282,150 +275,136 @@ int JvmtiRawMonitor::raw_enter(TRAPS) {
jt->SR_lock()->lock_without_safepoint_check();
}
// guarded by SR_lock to avoid racing with new external suspend requests.
Contended = Atomic::cmpxchg(THREAD, &_owner, (void*)NULL);
Contended = Atomic::cmpxchg(jt, &_owner, (Thread*)NULL);
jt->SR_lock()->unlock();
} else {
Contended = Atomic::cmpxchg(THREAD, &_owner, (void*)NULL);
Contended = Atomic::cmpxchg(Self, &_owner, (Thread*)NULL);
}
if (Contended == THREAD) {
if (Contended == Self) {
_recursions ++ ;
return OM_OK ;
return ;
}
if (Contended == NULL) {
guarantee (_owner == THREAD, "invariant") ;
guarantee (_owner == Self, "invariant") ;
guarantee (_recursions == 0, "invariant") ;
return OM_OK ;
return ;
}
THREAD->set_current_pending_monitor(this);
Self->set_current_pending_raw_monitor(this);
if (!THREAD->is_Java_thread()) {
// No other non-Java threads besides VM thread would acquire
// a raw monitor.
assert(THREAD->is_VM_thread(), "must be VM thread");
SimpleEnter (THREAD) ;
} else {
guarantee (jt->thread_state() == _thread_blocked, "invariant") ;
for (;;) {
jt->set_suspend_equivalent();
// cleared by handle_special_suspend_equivalent_condition() or
// java_suspend_self()
SimpleEnter (THREAD) ;
if (!Self->is_Java_thread()) {
SimpleEnter (Self) ;
} else {
guarantee (jt->thread_state() == _thread_blocked, "invariant") ;
for (;;) {
jt->set_suspend_equivalent();
// cleared by handle_special_suspend_equivalent_condition() or
// java_suspend_self()
SimpleEnter (jt) ;
// were we externally suspended while we were waiting?
if (!jt->handle_special_suspend_equivalent_condition()) break ;
// were we externally suspended while we were waiting?
if (!jt->handle_special_suspend_equivalent_condition()) break ;
// This thread was externally suspended
//
// This logic isn't needed for JVMTI raw monitors,
// but doesn't hurt just in case the suspend rules change. This
// logic is needed for the JvmtiRawMonitor.wait() reentry phase.
// We have reentered the contended monitor, but while we were
// waiting another thread suspended us. We don't want to reenter
// the monitor while suspended because that would surprise the
// thread that suspended us.
//
// Drop the lock -
SimpleExit (THREAD) ;
// This thread was externally suspended
// We have reentered the contended monitor, but while we were
// waiting another thread suspended us. We don't want to reenter
// the monitor while suspended because that would surprise the
// thread that suspended us.
//
// Drop the lock
SimpleExit (jt) ;
jt->java_suspend_self();
}
assert(_owner == THREAD, "Fatal error with monitor owner!");
assert(_recursions == 0, "Fatal error with monitor recursions!");
jt->java_suspend_self();
}
}
THREAD->set_current_pending_monitor(NULL);
Self->set_current_pending_raw_monitor(NULL);
guarantee (_owner == Self, "invariant") ;
guarantee (_recursions == 0, "invariant") ;
return OM_OK;
}
// Used mainly for JVMTI raw monitor implementation
// Also used for JvmtiRawMonitor::wait().
int JvmtiRawMonitor::raw_exit(TRAPS) {
if (THREAD != _owner) {
return OM_ILLEGAL_MONITOR_STATE;
int JvmtiRawMonitor::raw_exit(Thread * Self) {
if (Self != _owner) {
return M_ILLEGAL_MONITOR_STATE;
}
if (_recursions > 0) {
--_recursions ;
return OM_OK ;
} else {
SimpleExit (Self) ;
}
void * List = _EntryList ;
SimpleExit (THREAD) ;
return OM_OK;
return M_OK;
}
// Used for JVMTI raw monitor implementation.
// All JavaThreads will enter here with state _thread_blocked
int JvmtiRawMonitor::raw_wait(jlong millis, bool interruptible, TRAPS) {
if (THREAD != _owner) {
return OM_ILLEGAL_MONITOR_STATE;
int JvmtiRawMonitor::raw_wait(jlong millis, bool interruptible, Thread * Self) {
if (Self != _owner) {
return M_ILLEGAL_MONITOR_STATE;
}
// To avoid spurious wakeups we reset the parkevent -- This is strictly optional.
// The caller must be able to tolerate spurious returns from raw_wait().
THREAD->_ParkEvent->reset() ;
Self->_ParkEvent->reset() ;
OrderAccess::fence() ;
JavaThread * jt = NULL;
// check interrupt event
if (interruptible) {
assert(THREAD->is_Java_thread(), "Only JavaThreads can be interruptible");
JavaThread* jt = (JavaThread*) THREAD;
assert(Self->is_Java_thread(), "Only JavaThreads can be interruptible");
jt = (JavaThread*) Self;
if (jt->is_interrupted(true)) {
return OM_INTERRUPTED;
return M_INTERRUPTED;
}
} else {
assert(!Self->is_Java_thread(), "JavaThreads must be interuptible");
}
intptr_t save = _recursions ;
_recursions = 0 ;
_waiters ++ ;
if (THREAD->is_Java_thread()) {
guarantee (((JavaThread *) THREAD)->thread_state() == _thread_blocked, "invariant") ;
((JavaThread *)THREAD)->set_suspend_equivalent();
if (Self->is_Java_thread()) {
guarantee (jt->thread_state() == _thread_blocked, "invariant") ;
jt->set_suspend_equivalent();
}
int rv = SimpleWait (THREAD, millis) ;
int rv = SimpleWait (Self, millis) ;
_recursions = save ;
_waiters -- ;
guarantee (THREAD == _owner, "invariant") ;
if (THREAD->is_Java_thread()) {
JavaThread * jSelf = (JavaThread *) THREAD ;
guarantee (Self == _owner, "invariant") ;
if (Self->is_Java_thread()) {
for (;;) {
if (!jSelf->handle_special_suspend_equivalent_condition()) break ;
SimpleExit (THREAD) ;
jSelf->java_suspend_self();
SimpleEnter (THREAD) ;
jSelf->set_suspend_equivalent() ;
if (!jt->handle_special_suspend_equivalent_condition()) break ;
SimpleExit (jt) ;
jt->java_suspend_self();
SimpleEnter (jt) ;
jt->set_suspend_equivalent() ;
}
guarantee (jt == _owner, "invariant") ;
}
guarantee (THREAD == _owner, "invariant") ;
if (interruptible) {
JavaThread* jt = (JavaThread*) THREAD;
if (jt->is_interrupted(true)) {
return OM_INTERRUPTED;
}
if (interruptible && jt->is_interrupted(true)) {
return M_INTERRUPTED;
}
return OM_OK ;
return M_OK ;
}
int JvmtiRawMonitor::raw_notify(TRAPS) {
if (THREAD != _owner) {
return OM_ILLEGAL_MONITOR_STATE;
int JvmtiRawMonitor::raw_notify(Thread * Self) {
if (Self != _owner) {
return M_ILLEGAL_MONITOR_STATE;
}
SimpleNotify (THREAD, false) ;
return OM_OK;
SimpleNotify (Self, false) ;
return M_OK;
}
int JvmtiRawMonitor::raw_notifyAll(TRAPS) {
if (THREAD != _owner) {
return OM_ILLEGAL_MONITOR_STATE;
int JvmtiRawMonitor::raw_notifyAll(Thread * Self) {
if (Self != _owner) {
return M_ILLEGAL_MONITOR_STATE;
}
SimpleNotify (THREAD, true) ;
return OM_OK;
SimpleNotify (Self, true) ;
return M_OK;
}

View File

@ -25,7 +25,8 @@
#ifndef SHARE_PRIMS_JVMTIRAWMONITOR_HPP
#define SHARE_PRIMS_JVMTIRAWMONITOR_HPP
#include "runtime/objectMonitor.hpp"
#include "memory/allocation.hpp"
#include "runtime/park.hpp"
#include "utilities/growableArray.hpp"
//
@ -33,31 +34,69 @@
//
// Used by JVMTI methods: All RawMonitor methods (CreateRawMonitor, EnterRawMonitor, etc.)
//
// Wrapper for ObjectMonitor class that saves the Monitor's name
// A simplified version of the ObjectMonitor code.
//
class JvmtiRawMonitor : public ObjectMonitor {
private:
class JvmtiRawMonitor : public CHeapObj<mtSynchronizer> {
// Helper class to allow Threads to be linked into queues.
// This is a stripped down version of ObjectWaiter.
class QNode : public StackObj {
friend class JvmtiRawMonitor;
enum TStates { TS_READY, TS_RUN, TS_WAIT, TS_ENTER };
QNode* volatile _next;
QNode* volatile _prev;
ParkEvent * _event;
volatile int _notified;
volatile TStates TState;
QNode(Thread* thread);
};
Thread* volatile _owner; // pointer to owning thread
volatile int _recursions; // recursion count, 0 for first entry
QNode* volatile _EntryList; // Threads blocked on entry or reentry.
// The list is actually composed of nodes,
// acting as proxies for Threads.
QNode* volatile _WaitSet; // Threads wait()ing on the monitor
volatile jint _waiters; // number of waiting threads
int _magic;
char * _name;
// JVMTI_RM_MAGIC is set in contructor and unset in destructor.
enum { JVMTI_RM_MAGIC = (int)(('T' << 24) | ('I' << 16) | ('R' << 8) | 'M') };
int SimpleEnter (Thread * Self) ;
int SimpleExit (Thread * Self) ;
void SimpleEnter (Thread * Self) ;
void SimpleExit (Thread * Self) ;
int SimpleWait (Thread * Self, jlong millis) ;
int SimpleNotify (Thread * Self, bool All) ;
void SimpleNotify(Thread * Self, bool All) ;
public:
// return codes
enum {
M_OK, // no error
M_ILLEGAL_MONITOR_STATE, // IllegalMonitorStateException
M_INTERRUPTED // Thread.interrupt()
};
// Non-aborting operator new
void* operator new(size_t size) throw() {
return CHeapObj::operator new(size, std::nothrow);
}
JvmtiRawMonitor(const char *name);
~JvmtiRawMonitor();
int raw_enter(TRAPS);
int raw_exit(TRAPS);
int raw_wait(jlong millis, bool interruptable, TRAPS);
int raw_notify(TRAPS);
int raw_notifyAll(TRAPS);
int magic() { return _magic; }
const char *get_name() { return _name; }
Thread * owner() const { return _owner; }
void set_owner(Thread * owner) { _owner = owner; }
int recursions() const { return _recursions; }
void raw_enter(Thread * Self);
int raw_exit(Thread * Self);
int raw_wait(jlong millis, bool interruptable, Thread * Self);
int raw_notify(Thread * Self);
int raw_notifyAll(Thread * Self);
int magic() const { return _magic; }
const char *get_name() const { return _name; }
bool is_valid();
};

View File

@ -43,7 +43,6 @@ class ObjectMonitor;
class ObjectWaiter : public StackObj {
public:
enum TStates { TS_UNDEF, TS_READY, TS_RUN, TS_WAIT, TS_ENTER, TS_CXQ };
enum Sorted { PREPEND, APPEND, SORTED };
ObjectWaiter* volatile _next;
ObjectWaiter* volatile _prev;
Thread* _thread;
@ -51,7 +50,6 @@ class ObjectWaiter : public StackObj {
ParkEvent * _event;
volatile int _notified;
volatile TStates TState;
Sorted _Sorted; // List placement disposition
bool _active; // Contention monitoring is enabled
public:
ObjectWaiter(Thread* thread);
@ -68,10 +66,6 @@ class ObjectWaiter : public StackObj {
// WARNING: This is a very sensitive and fragile class. DO NOT make any
// changes unless you are fully aware of the underlying semantics.
//
// Class JvmtiRawMonitor currently inherits from ObjectMonitor so
// changes in this class must be careful to not break JvmtiRawMonitor.
// These two subsystems should be separated.
//
// ObjectMonitor Layout Overview/Highlights/Restrictions:
//
// - The _header field must be at offset 0 because the displaced header
@ -127,16 +121,6 @@ class ObjectWaiter : public StackObj {
// in a 64-bit JVM.
class ObjectMonitor {
public:
enum {
OM_OK, // no error
OM_SYSTEM_ERROR, // operating system error
OM_ILLEGAL_MONITOR_STATE, // IllegalMonitorStateException
OM_INTERRUPTED, // Thread.interrupt()
OM_TIMED_OUT // Object.wait() timed out
};
private:
friend class ObjectSynchronizer;
friend class ObjectWaiter;
friend class VMStructs;
@ -158,16 +142,13 @@ class ObjectMonitor {
DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE,
sizeof(volatile markWord) + sizeof(void* volatile) +
sizeof(ObjectMonitor *));
protected: // protected for JvmtiRawMonitor
void* volatile _owner; // pointer to owning thread OR BasicLock
private:
volatile jlong _previous_owner_tid; // thread id of the previous owner of the monitor
protected: // protected for JvmtiRawMonitor
volatile intptr_t _recursions; // recursion count, 0 for first entry
ObjectWaiter* volatile _EntryList; // Threads blocked on entry or reentry.
// The list is actually composed of WaitNodes,
// acting as proxies for Threads.
private:
ObjectWaiter* volatile _cxq; // LL of recently-arrived threads blocked on entry.
Thread* volatile _succ; // Heir presumptive thread - used for futile wakeup throttling
Thread* volatile _Responsible;

View File

@ -258,6 +258,7 @@ Thread::Thread() {
_current_pending_monitor = NULL;
_current_pending_monitor_is_from_java = true;
_current_waiting_monitor = NULL;
_current_pending_raw_monitor = NULL;
_num_nested_signal = 0;
om_free_list = NULL;
om_free_count = 0;
@ -3847,7 +3848,7 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
// Create the VMThread
{ TraceTime timer("Start VMThread", TRACETIME_LOG(Info, startuptime));
VMThread::create();
VMThread::create();
Thread* vmthread = VMThread::vm_thread();
if (!os::create_thread(vmthread, os::vm_thread)) {

View File

@ -62,6 +62,7 @@ class ThreadSafepointState;
class ThreadsList;
class ThreadsSMRSupport;
class JvmtiRawMonitor;
class JvmtiThreadState;
class ThreadStatistics;
class ConcurrentLocksDump;
@ -404,6 +405,9 @@ class Thread: public ThreadShadow {
ObjectMonitor* _current_pending_monitor; // ObjectMonitor this thread
// is waiting to lock
bool _current_pending_monitor_is_from_java; // locking is from Java code
JvmtiRawMonitor* _current_pending_raw_monitor; // JvmtiRawMonitor this thread
// is waiting to lock
// ObjectMonitor on which this thread called Object.wait()
ObjectMonitor* _current_waiting_monitor;
@ -640,6 +644,14 @@ class Thread: public ThreadShadow {
_current_waiting_monitor = monitor;
}
// For tracking the Jvmti raw monitor the thread is pending on.
JvmtiRawMonitor* current_pending_raw_monitor() {
return _current_pending_raw_monitor;
}
void set_current_pending_raw_monitor(JvmtiRawMonitor* monitor) {
_current_pending_raw_monitor = monitor;
}
// GC support
// Apply "f->do_oop" to all root oops in "this".
// Used by JavaThread::oops_do.
@ -786,7 +798,7 @@ protected:
public:
volatile intptr_t _Stalled;
volatile int _TypeTag;
ParkEvent * _ParkEvent; // for synchronized()
ParkEvent * _ParkEvent; // for Object monitors and JVMTI raw monitors
ParkEvent * _MuxEvent; // for low-level muxAcquire-muxRelease
int NativeSyncRecursion; // diagnostic

View File

@ -32,6 +32,7 @@
#include "oops/objArrayKlass.hpp"
#include "oops/objArrayOop.inline.hpp"
#include "oops/oop.inline.hpp"
#include "prims/jvmtiRawMonitor.hpp"
#include "runtime/atomic.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/init.hpp"
@ -217,10 +218,10 @@ Handle ThreadService::get_current_contended_monitor(JavaThread* thread) {
} else {
ObjectMonitor *enter_obj = thread->current_pending_monitor();
if (enter_obj != NULL) {
// thread is trying to enter() or raw_enter() an ObjectMonitor.
// thread is trying to enter() an ObjectMonitor.
obj = (oop) enter_obj->object();
assert(obj != NULL, "ObjectMonitor should have an associated object!");
}
// If obj == NULL, then ObjectMonitor is raw which doesn't count.
}
Handle h(Thread::current(), obj);
@ -354,13 +355,15 @@ void ThreadService::reset_contention_time_stat(JavaThread* thread) {
}
}
// Find deadlocks involving object monitors and concurrent locks if concurrent_locks is true
// Find deadlocks involving raw monitors, object monitors and concurrent locks
// if concurrent_locks is true.
DeadlockCycle* ThreadService::find_deadlocks_at_safepoint(ThreadsList * t_list, bool concurrent_locks) {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
// This code was modified from the original Threads::find_deadlocks code.
int globalDfn = 0, thisDfn;
ObjectMonitor* waitingToLockMonitor = NULL;
JvmtiRawMonitor* waitingToLockRawMonitor = NULL;
oop waitingToLockBlocker = NULL;
bool blocked_on_monitor = false;
JavaThread *currentThread, *previousThread;
@ -391,13 +394,30 @@ DeadlockCycle* ThreadService::find_deadlocks_at_safepoint(ThreadsList * t_list,
// When there is a deadlock, all the monitors involved in the dependency
// cycle must be contended and heavyweight. So we only care about the
// heavyweight monitor a thread is waiting to lock.
waitingToLockMonitor = (ObjectMonitor*)jt->current_pending_monitor();
waitingToLockMonitor = jt->current_pending_monitor();
// JVM TI raw monitors can also be involved in deadlocks, and we can be
// waiting to lock both a raw monitor and ObjectMonitor at the same time.
// It isn't clear how to make deadlock detection work correctly if that
// happens.
waitingToLockRawMonitor = jt->current_pending_raw_monitor();
if (concurrent_locks) {
waitingToLockBlocker = jt->current_park_blocker();
}
while (waitingToLockMonitor != NULL || waitingToLockBlocker != NULL) {
while (waitingToLockMonitor != NULL ||
waitingToLockRawMonitor != NULL ||
waitingToLockBlocker != NULL) {
cycle->add_thread(currentThread);
if (waitingToLockMonitor != NULL) {
// Give preference to the raw monitor
if (waitingToLockRawMonitor != NULL) {
Thread* owner = waitingToLockRawMonitor->owner();
if (owner != NULL && // the raw monitor could be released at any time
owner->is_Java_thread()) {
// only JavaThreads can be reported here
currentThread = (JavaThread*) owner;
}
} else if (waitingToLockMonitor != NULL) {
address currentOwner = (address)waitingToLockMonitor->owner();
if (currentOwner != NULL) {
currentThread = Threads::owning_thread_from_monitor_owner(t_list,
@ -948,28 +968,44 @@ void DeadlockCycle::print_on_with(ThreadsList * t_list, outputStream* st) const
JavaThread* currentThread;
ObjectMonitor* waitingToLockMonitor;
JvmtiRawMonitor* waitingToLockRawMonitor;
oop waitingToLockBlocker;
int len = _threads->length();
for (int i = 0; i < len; i++) {
currentThread = _threads->at(i);
waitingToLockMonitor = (ObjectMonitor*)currentThread->current_pending_monitor();
waitingToLockMonitor = currentThread->current_pending_monitor();
waitingToLockRawMonitor = currentThread->current_pending_raw_monitor();
waitingToLockBlocker = currentThread->current_park_blocker();
st->cr();
st->print_cr("\"%s\":", currentThread->get_thread_name());
const char* owner_desc = ",\n which is held by";
// Note: As the JVM TI "monitor contended enter" event callback is executed after ObjectMonitor
// sets the current pending monitor, it is possible to then see a pending raw monitor as well.
if (waitingToLockRawMonitor != NULL) {
st->print(" waiting to lock JVM TI raw monitor " INTPTR_FORMAT, p2i(waitingToLockRawMonitor));
Thread* owner = waitingToLockRawMonitor->owner();
// Could be NULL as the raw monitor could be released at any time if held by non-JavaThread
if (owner != NULL) {
if (owner->is_Java_thread()) {
currentThread = (JavaThread*) owner;
st->print_cr("%s \"%s\"", owner_desc, currentThread->get_thread_name());
} else {
st->print_cr(",\n which has now been released");
}
} else {
st->print_cr("%s non-Java thread=" PTR_FORMAT, owner_desc, p2i(owner));
}
}
if (waitingToLockMonitor != NULL) {
st->print(" waiting to lock monitor " INTPTR_FORMAT, p2i(waitingToLockMonitor));
oop obj = (oop)waitingToLockMonitor->object();
if (obj != NULL) {
st->print(" (object " INTPTR_FORMAT ", a %s)", p2i(obj),
obj->klass()->external_name());
st->print(" (object " INTPTR_FORMAT ", a %s)", p2i(obj),
obj->klass()->external_name());
if (!currentThread->current_pending_monitor_is_from_java()) {
owner_desc = "\n in JNI, which is held by";
}
} else {
// No Java object associated - a JVMTI raw monitor
owner_desc = " (JVMTI raw monitor),\n which is held by";
if (!currentThread->current_pending_monitor_is_from_java()) {
owner_desc = "\n in JNI, which is held by";
}
currentThread = Threads::owning_thread_from_monitor_owner(t_list,
(address)waitingToLockMonitor->owner());
@ -978,7 +1014,7 @@ void DeadlockCycle::print_on_with(ThreadsList * t_list, outputStream* st) const
// that owns waitingToLockMonitor should be findable, but
// if it is not findable, then the previous currentThread is
// blocked permanently.
st->print("%s UNKNOWN_owner_addr=" PTR_FORMAT, owner_desc,
st->print_cr("%s UNKNOWN_owner_addr=" PTR_FORMAT, owner_desc,
p2i(waitingToLockMonitor->owner()));
continue;
}
@ -992,10 +1028,9 @@ void DeadlockCycle::print_on_with(ThreadsList * t_list, outputStream* st) const
currentThread = java_lang_Thread::thread(ownerObj);
assert(currentThread != NULL, "AbstractOwnableSynchronizer owning thread is unexpectedly NULL");
}
st->print("%s \"%s\"", owner_desc, currentThread->get_thread_name());
st->print_cr("%s \"%s\"", owner_desc, currentThread->get_thread_name());
}
st->cr();
st->cr();
// Print stack traces

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -37,7 +37,7 @@ extern "C" {
static jvmtiEnv *jvmti = NULL;
static jvmtiCapabilities caps;
static jint result = PASSED;
static jboolean printdump = JNI_FALSE;
static jboolean printdump = JNI_TRUE;
static jrawMonitorID monitor;
static jrawMonitorID wait_lock;
static jlong wait_time;
@ -100,6 +100,8 @@ test_thread(jvmtiEnv* jvmti, JNIEnv* jni, void *unused) {
jvmtiError err;
const char* const thread_name = "test thread";
// Once we hold this monitor we know we can't get interrupted
// until we have called wait().
err = jvmti->RawMonitorEnter(monitor);
if (err != JVMTI_ERROR_NONE) {
printf("(RawMonitorEnter#test) unexpected error: %s (%d)\n",
@ -110,6 +112,7 @@ test_thread(jvmtiEnv* jvmti, JNIEnv* jni, void *unused) {
printf(">>> [%s] acquired lock for 'monitor' ...\n", thread_name);
}
// We can't get this monitor until the main thread has called wait() on it.
err = jvmti->RawMonitorEnter(wait_lock);
if (err != JVMTI_ERROR_NONE) {
printf("(RawMonitorEnter#wait) unexpected error: %s (%d)\n",
@ -156,6 +159,36 @@ test_thread(jvmtiEnv* jvmti, JNIEnv* jni, void *unused) {
result = STATUS_FAILED;
}
// We can't reacquire this monitor until the main thread is waiting for us to
// complete.
err = jvmti->RawMonitorEnter(wait_lock);
if (err != JVMTI_ERROR_NONE) {
printf("(RawMonitorEnter#wait) unexpected error: %s (%d)\n",
TranslateError(err), err);
result = STATUS_FAILED;
return;
}
if (printdump == JNI_TRUE) {
printf(">>> [%s] acquired lock for 'wait_lock' ...\n", thread_name);
printf(">>> [%s] notifying main thread we are done ...\n", thread_name);
}
err = jvmti->RawMonitorNotify(wait_lock);
if (err != JVMTI_ERROR_NONE) {
printf("(RawMonitorWait#wait) unexpected error: %s (%d)\n",
TranslateError(err), err);
result = STATUS_FAILED;
return;
}
err = jvmti->RawMonitorExit(wait_lock);
if (err != JVMTI_ERROR_NONE) {
printf("(RawMonitorExit#wait) unexpected error: %s (%d)\n",
TranslateError(err), err);
result = STATUS_FAILED;
return;
}
if (printdump == JNI_TRUE) {
printf(">>> [%s] all done\n", thread_name);
}
@ -223,6 +256,11 @@ Java_nsk_jvmti_RawMonitorWait_rawmnwait005_check(JNIEnv *env,
if (printdump == JNI_TRUE) {
printf(">>> [%s] starting test thread ...\n", thread_name);
}
// This starts a daemon thread, so we need to synchronize with it
// before we terminate - else the test will end before it checks
// it was interrupted!
err = jvmti->RunAgentThread(thr, test_thread, NULL,
JVMTI_THREAD_NORM_PRIORITY);
if (err != JVMTI_ERROR_NONE) {
@ -244,12 +282,7 @@ Java_nsk_jvmti_RawMonitorWait_rawmnwait005_check(JNIEnv *env,
printf(">>> [%s] got notification from test thread ...\n", thread_name);
}
err = jvmti->RawMonitorExit(wait_lock);
if (err != JVMTI_ERROR_NONE) {
printf("(RawMonitorExit#wait) unexpected error: %s (%d)\n",
TranslateError(err), err);
return STATUS_FAILED;
}
// Keep the wait_lock so we can wait again at the end.
err = jvmti->RawMonitorEnter(monitor);
if (err != JVMTI_ERROR_NONE) {
@ -279,6 +312,26 @@ Java_nsk_jvmti_RawMonitorWait_rawmnwait005_check(JNIEnv *env,
result = STATUS_FAILED;
}
if (printdump == JNI_TRUE) {
printf(">>> [%s] waiting for test thread to complete its wait and notify us ...\n", thread_name);
}
err = jvmti->RawMonitorWait(wait_lock, (jlong)0);
if (err != JVMTI_ERROR_NONE) {
printf("(RawMonitorWait#wait) unexpected error: %s (%d)\n",
TranslateError(err), err);
return STATUS_FAILED;
}
if (printdump == JNI_TRUE) {
printf(">>> [%s] got final notification from test thread ...\n", thread_name);
}
err = jvmti->RawMonitorExit(wait_lock);
if (err != JVMTI_ERROR_NONE) {
printf("(RawMonitorExit#wait) unexpected error: %s (%d)\n",
TranslateError(err), err);
return STATUS_FAILED;
}
if (printdump == JNI_TRUE) {
printf(">>> [%s] all done\n", thread_name);
}