8230003: Make Monitor inherit from Mutex

Reverse inheritance that makes more sense.

Reviewed-by: dholmes, rehn, pchilanomate
This commit is contained in:
Coleen Phillimore 2019-08-22 09:51:36 -04:00
parent a405118f90
commit da18495f38
10 changed files with 143 additions and 169 deletions

View File

@ -2674,8 +2674,8 @@ void CompileBroker::print_heapinfo(outputStream* out, const char* function, size
// for the entire duration of aggregation and printing. That makes sure
// we see a consistent picture and do not run into issues caused by
// the CodeHeap being altered concurrently.
Monitor* global_lock = allFun ? CodeCache_lock : NULL;
Monitor* function_lock = allFun ? NULL : CodeCache_lock;
Mutex* global_lock = allFun ? CodeCache_lock : NULL;
Mutex* function_lock = allFun ? NULL : CodeCache_lock;
ts_global.update(); // record starting point
MutexLocker mu2(global_lock, Mutex::_no_safepoint_check_flag);
if (global_lock != NULL) {

View File

@ -356,9 +356,9 @@ static void prepare_for_emergency_dump(Thread* thread) {
}
#ifdef ASSERT
Monitor* owned_lock = thread->owned_locks();
Mutex* owned_lock = thread->owned_locks();
while (owned_lock != NULL) {
Monitor* next = owned_lock->next();
Mutex* next = owned_lock->next();
owned_lock->unlock();
owned_lock = next;
}

View File

@ -171,7 +171,7 @@
LOG_TAG(mirror) \
LOG_TAG(verification) \
LOG_TAG(verify) \
LOG_TAG(vmmonitor) \
LOG_TAG(vmmutex) \
LOG_TAG(vmoperation) \
LOG_TAG(vmthread) \
LOG_TAG(vtables) \

View File

@ -254,30 +254,30 @@ class ThreadBlockInVM : public ThreadStateTransition {
};
// Unlike ThreadBlockInVM, this class is designed to avoid certain deadlock scenarios while making
// transitions inside class Monitor 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 monitor we
// are trying to acquire. This will be used to access and release the monitor if needed to avoid
// 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 monitor that is only partially acquired.
// the mutex that is only partially acquired.
class ThreadBlockInVMWithDeadlockCheck : public ThreadStateTransition {
private:
Monitor** _in_flight_monitor_adr;
Mutex** _in_flight_mutex_addr;
void release_monitor() {
assert(_in_flight_monitor_adr != NULL, "_in_flight_monitor_adr should have been set on constructor");
Monitor* in_flight_monitor = *_in_flight_monitor_adr;
if (in_flight_monitor != NULL) {
in_flight_monitor->release_for_safepoint();
*_in_flight_monitor_adr = NULL;
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:
ThreadBlockInVMWithDeadlockCheck(JavaThread* thread, Monitor** in_flight_monitor_adr)
: ThreadStateTransition(thread), _in_flight_monitor_adr(in_flight_monitor_adr) {
ThreadBlockInVMWithDeadlockCheck(JavaThread* thread, Mutex** in_flight_mutex_addr)
: ThreadStateTransition(thread), _in_flight_mutex_addr(in_flight_mutex_addr) {
// Once we are blocked vm expects stack to be walkable
thread->frame_anchor()->make_walkable(thread);
@ -293,7 +293,7 @@ class ThreadBlockInVMWithDeadlockCheck : public ThreadStateTransition {
_thread->set_thread_state_fence((JavaThreadState)(_thread_blocked_trans));
if (SafepointMechanism::should_block(_thread)) {
release_monitor();
release_mutex();
SafepointMechanism::block_if_requested(_thread);
}

View File

@ -33,27 +33,27 @@
#include "utilities/macros.hpp"
#ifdef ASSERT
void Monitor::check_safepoint_state(Thread* thread, bool do_safepoint_check) {
void Mutex::check_safepoint_state(Thread* thread, bool do_safepoint_check) {
// If the JavaThread checks for safepoint, verify that the lock wasn't created with safepoint_check_never.
SafepointCheckRequired not_allowed = do_safepoint_check ? Monitor::_safepoint_check_never :
Monitor::_safepoint_check_always;
SafepointCheckRequired not_allowed = do_safepoint_check ? Mutex::_safepoint_check_never :
Mutex::_safepoint_check_always;
assert(!thread->is_active_Java_thread() || _safepoint_check_required != not_allowed,
"This lock should %s have a safepoint check for Java threads: %s",
_safepoint_check_required ? "always" : "never", name());
// If defined with safepoint_check_never, a NonJavaThread should never ask to safepoint check either.
assert(thread->is_Java_thread() || !do_safepoint_check || _safepoint_check_required != Monitor::_safepoint_check_never,
assert(thread->is_Java_thread() || !do_safepoint_check || _safepoint_check_required != Mutex::_safepoint_check_never,
"NonJavaThread should not check for safepoint");
}
#endif // ASSERT
void Monitor::lock(Thread * self) {
void Mutex::lock(Thread * self) {
check_safepoint_state(self, true);
DEBUG_ONLY(check_prelock_state(self, true));
assert(_owner != self, "invariant");
Monitor* in_flight_monitor = NULL;
Mutex* in_flight_mutex = NULL;
DEBUG_ONLY(int retry_cnt = 0;)
bool is_active_Java_thread = self->is_active_Java_thread();
while (!_lock.try_lock()) {
@ -62,18 +62,18 @@ void Monitor::lock(Thread * self) {
#ifdef ASSERT
check_block_state(self);
if (retry_cnt++ > 3) {
log_trace(vmmonitor)("JavaThread " INTPTR_FORMAT " on %d attempt trying to acquire vmmonitor %s", p2i(self), retry_cnt, _name);
log_trace(vmmutex)("JavaThread " INTPTR_FORMAT " on %d attempt trying to acquire vmmutex %s", p2i(self), retry_cnt, _name);
}
#endif // ASSERT
// Is it a JavaThread participating in the safepoint protocol.
if (is_active_Java_thread) {
assert(rank() > Mutex::special, "Potential deadlock with special or lesser rank mutex");
{ ThreadBlockInVMWithDeadlockCheck tbivmdc((JavaThread *) self, &in_flight_monitor);
in_flight_monitor = this; // save for ~ThreadBlockInVMWithDeadlockCheck
{ ThreadBlockInVMWithDeadlockCheck tbivmdc((JavaThread *) self, &in_flight_mutex);
in_flight_mutex = this; // save for ~ThreadBlockInVMWithDeadlockCheck
_lock.lock();
}
if (in_flight_monitor != NULL) {
if (in_flight_mutex != NULL) {
// Not unlocked by ~ThreadBlockInVMWithDeadlockCheck
break;
}
@ -87,7 +87,7 @@ void Monitor::lock(Thread * self) {
set_owner(self);
}
void Monitor::lock() {
void Mutex::lock() {
this->lock(Thread::current());
}
@ -97,7 +97,7 @@ void Monitor::lock() {
// safepoint-safe and so will prevent a safepoint from being reached. If used
// in the wrong way this can lead to a deadlock with the safepoint code.
void Monitor::lock_without_safepoint_check(Thread * self) {
void Mutex::lock_without_safepoint_check(Thread * self) {
check_safepoint_state(self, false);
assert(_owner != self, "invariant");
_lock.lock();
@ -105,14 +105,14 @@ void Monitor::lock_without_safepoint_check(Thread * self) {
set_owner(self);
}
void Monitor::lock_without_safepoint_check() {
void Mutex::lock_without_safepoint_check() {
lock_without_safepoint_check(Thread::current());
}
// Returns true if thread succeeds in grabbing the lock, otherwise false.
bool Monitor::try_lock() {
bool Mutex::try_lock() {
Thread * const self = Thread::current();
DEBUG_ONLY(check_prelock_state(self, false);)
@ -124,12 +124,12 @@ bool Monitor::try_lock() {
return false;
}
void Monitor::release_for_safepoint() {
void Mutex::release_for_safepoint() {
assert_owner(NULL);
_lock.unlock();
}
void Monitor::unlock() {
void Mutex::unlock() {
assert_owner(Thread::current());
set_owner(NULL);
_lock.unlock();
@ -147,7 +147,7 @@ void Monitor::notify_all() {
#ifdef ASSERT
void Monitor::assert_wait_lock_state(Thread* self) {
Monitor* least = get_least_ranked_lock_besides_this(self->owned_locks());
Mutex* least = get_least_ranked_lock_besides_this(self->owned_locks());
assert(least != this, "Specification of get_least_... call above");
if (least != NULL && least->rank() <= special) {
::tty->print("Attempting to wait on monitor %s/%d while holding"
@ -194,10 +194,10 @@ bool Monitor::wait(long timeout, bool as_suspend_equivalent) {
// abdicating the lock in wait
set_owner(NULL);
JavaThread *jt = (JavaThread *)self;
Monitor* in_flight_monitor = NULL;
Mutex* in_flight_mutex = NULL;
{
ThreadBlockInVMWithDeadlockCheck tbivmdc(jt, &in_flight_monitor);
ThreadBlockInVMWithDeadlockCheck tbivmdc(jt, &in_flight_mutex);
OSThreadWaitState osts(self->osthread(), false /* not Object.wait() */);
if (as_suspend_equivalent) {
jt->set_suspend_equivalent();
@ -206,7 +206,7 @@ bool Monitor::wait(long timeout, bool as_suspend_equivalent) {
}
wait_status = _lock.wait(timeout);
in_flight_monitor = this; // save for ~ThreadBlockInVMWithDeadlockCheck
in_flight_mutex = this; // save for ~ThreadBlockInVMWithDeadlockCheck
// were we externally suspended while we were waiting?
if (as_suspend_equivalent && jt->handle_special_suspend_equivalent_condition()) {
@ -220,7 +220,7 @@ bool Monitor::wait(long timeout, bool as_suspend_equivalent) {
}
}
if (in_flight_monitor != NULL) {
if (in_flight_mutex != NULL) {
// Not unlocked by ~ThreadBlockInVMWithDeadlockCheck
assert_owner(NULL);
// Conceptually reestablish ownership of the lock.
@ -232,7 +232,7 @@ bool Monitor::wait(long timeout, bool as_suspend_equivalent) {
return wait_status != 0; // return true IFF timeout
}
Monitor::~Monitor() {
Mutex::~Mutex() {
assert_owner(NULL);
}
@ -241,34 +241,34 @@ bool is_sometimes_ok(const char* name) {
return (strcmp(name, "Threads_lock") == 0 || strcmp(name, "Heap_lock") == 0 || strcmp(name, "SR_lock") == 0);
}
Monitor::Monitor(int Rank, const char * name, bool allow_vm_block,
SafepointCheckRequired safepoint_check_required) : _owner(NULL) {
Mutex::Mutex(int Rank, const char * name, bool allow_vm_block,
SafepointCheckRequired safepoint_check_required) : _owner(NULL) {
assert(os::mutex_init_done(), "Too early!");
if (name == NULL) {
strcpy(_name, "UNKNOWN");
} else {
strncpy(_name, name, MONITOR_NAME_LEN - 1);
_name[MONITOR_NAME_LEN - 1] = '\0';
strncpy(_name, name, MUTEX_NAME_LEN - 1);
_name[MUTEX_NAME_LEN - 1] = '\0';
}
#ifdef ASSERT
_allow_vm_block = allow_vm_block;
_rank = Rank;
_safepoint_check_required = safepoint_check_required;
assert(_safepoint_check_required != Monitor::_safepoint_check_sometimes || is_sometimes_ok(name),
assert(_safepoint_check_required != Mutex::_safepoint_check_sometimes || is_sometimes_ok(name),
"Lock has _safepoint_check_sometimes %s", name);
#endif
}
Mutex::Mutex(int Rank, const char * name, bool allow_vm_block,
Monitor::Monitor(int Rank, const char * name, bool allow_vm_block,
SafepointCheckRequired safepoint_check_required) :
Monitor(Rank, name, allow_vm_block, safepoint_check_required) {}
Mutex(Rank, name, allow_vm_block, safepoint_check_required) {}
bool Monitor::owned_by_self() const {
bool Mutex::owned_by_self() const {
return _owner == Thread::current();
}
void Monitor::print_on_error(outputStream* st) const {
void Mutex::print_on_error(outputStream* st) const {
st->print("[" PTR_FORMAT, p2i(this));
st->print("] %s", _name);
st->print(" - owner thread: " PTR_FORMAT, p2i(_owner));
@ -278,7 +278,7 @@ void Monitor::print_on_error(outputStream* st) const {
// Non-product code
#ifndef PRODUCT
void Monitor::print_on(outputStream* st) const {
void Mutex::print_on(outputStream* st) const {
st->print_cr("Mutex: [" PTR_FORMAT "] %s - owner: " PTR_FORMAT,
p2i(this), _name, p2i(_owner));
}
@ -287,7 +287,7 @@ void Monitor::print_on(outputStream* st) const {
#ifndef PRODUCT
#ifdef ASSERT
void Monitor::assert_owner(Thread * expected) {
void Mutex::assert_owner(Thread * expected) {
const char* msg = "invalid owner";
if (expected == NULL) {
msg = "should be un-owned";
@ -300,8 +300,8 @@ void Monitor::assert_owner(Thread * expected) {
msg, p2i(_owner), p2i(expected));
}
Monitor * Monitor::get_least_ranked_lock(Monitor * locks) {
Monitor *res, *tmp;
Mutex* Mutex::get_least_ranked_lock(Mutex* locks) {
Mutex *res, *tmp;
for (res = tmp = locks; tmp != NULL; tmp = tmp->next()) {
if (tmp->rank() < res->rank()) {
res = tmp;
@ -320,8 +320,8 @@ Monitor * Monitor::get_least_ranked_lock(Monitor * locks) {
return res;
}
Monitor* Monitor::get_least_ranked_lock_besides_this(Monitor* locks) {
Monitor *res, *tmp;
Mutex* Mutex::get_least_ranked_lock_besides_this(Mutex* locks) {
Mutex *res, *tmp;
for (res = NULL, tmp = locks; tmp != NULL; tmp = tmp->next()) {
if (tmp != this && (res == NULL || tmp->rank() < res->rank())) {
res = tmp;
@ -341,7 +341,7 @@ Monitor* Monitor::get_least_ranked_lock_besides_this(Monitor* locks) {
}
bool Monitor::contains(Monitor* locks, Monitor * lock) {
bool Mutex::contains(Mutex* locks, Mutex* lock) {
for (; locks != NULL; locks = locks->next()) {
if (locks == lock) {
return true;
@ -356,7 +356,7 @@ bool Monitor::contains(Monitor* locks, Monitor * lock) {
// might indicate exposure to deadlock.
// Rather like an EventListener for _owner (:>).
void Monitor::set_owner_implementation(Thread *new_owner) {
void Mutex::set_owner_implementation(Thread *new_owner) {
// This function is solely responsible for maintaining
// and checking the invariant that threads and locks
// are in a 1/N relation, with some some locks unowned.
@ -377,7 +377,7 @@ void Monitor::set_owner_implementation(Thread *new_owner) {
// link "this" into the owned locks list
#ifdef ASSERT // Thread::_owned_locks is under the same ifdef
Monitor* locks = get_least_ranked_lock(new_owner->owned_locks());
Mutex* locks = get_least_ranked_lock(new_owner->owned_locks());
// Mutex::set_owner_implementation is a friend of Thread
assert(this->rank() >= 0, "bad lock rank");
@ -415,11 +415,11 @@ void Monitor::set_owner_implementation(Thread *new_owner) {
_owner = NULL; // set the owner
#ifdef ASSERT
Monitor *locks = old_owner->owned_locks();
Mutex* locks = old_owner->owned_locks();
// remove "this" from the owned locks list
Monitor *prev = NULL;
Mutex* prev = NULL;
bool found = false;
for (; locks != NULL; prev = locks, locks = locks->next()) {
if (locks == this) {
@ -440,7 +440,7 @@ void Monitor::set_owner_implementation(Thread *new_owner) {
// Factored out common sanity checks for locking mutex'es. Used by lock() and try_lock()
void Monitor::check_prelock_state(Thread *thread, bool safepoint_check) {
void Mutex::check_prelock_state(Thread *thread, bool safepoint_check) {
if (safepoint_check) {
assert((!thread->is_active_Java_thread() || ((JavaThread *)thread)->thread_state() == _thread_in_vm)
|| rank() == Mutex::special, "wrong thread state for using locks");
@ -454,13 +454,13 @@ void Monitor::check_prelock_state(Thread *thread, bool safepoint_check) {
"locking not allowed when crash protection is set");
}
void Monitor::check_block_state(Thread *thread) {
void Mutex::check_block_state(Thread *thread) {
if (!_allow_vm_block && thread->is_VM_thread()) {
warning("VM thread blocked on lock");
print();
BREAKPOINT;
}
assert(_owner != thread, "deadlock: blocking on monitor owned by current thread");
assert(_owner != thread, "deadlock: blocking on mutex owned by current thread");
}
#endif // PRODUCT

View File

@ -32,12 +32,12 @@
// variable that supports lock ownership tracking, lock ranking for deadlock
// detection and coordinates with the safepoint protocol.
// The default length of monitor name was originally chosen to be 64 to avoid
// false sharing. Now, PaddedMonitor is available for this purpose.
// TODO: Check if _name[MONITOR_NAME_LEN] should better get replaced by const char*.
static const int MONITOR_NAME_LEN = 64;
// The default length of mutex name was originally chosen to be 64 to avoid
// false sharing. Now, PaddedMutex and PaddedMonitor are available for this purpose.
// TODO: Check if _name[MUTEX_NAME_LEN] should better get replaced by const char*.
static const int MUTEX_NAME_LEN = 64;
class Monitor : public CHeapObj<mtSynchronizer> {
class Mutex : public CHeapObj<mtSynchronizer> {
public:
// A special lock: Is a lock where you are guaranteed not to block while you are
@ -78,17 +78,17 @@ class Monitor : public CHeapObj<mtSynchronizer> {
protected: // Monitor-Mutex metadata
Thread * volatile _owner; // The owner of the lock
os::PlatformMonitor _lock; // Native monitor implementation
char _name[MONITOR_NAME_LEN]; // Name of mutex/monitor
char _name[MUTEX_NAME_LEN]; // Name of mutex/monitor
// Debugging fields for naming, deadlock detection, etc. (some only used in debug mode)
#ifndef PRODUCT
bool _allow_vm_block;
DEBUG_ONLY(int _rank;) // rank (to avoid/detect potential deadlocks)
DEBUG_ONLY(Monitor * _next;) // Used by a Thread to link up owned locks
DEBUG_ONLY(Mutex* _next;) // Used by a Thread to link up owned locks
DEBUG_ONLY(Thread* _last_owner;) // the last thread to own the lock
DEBUG_ONLY(static bool contains(Monitor * locks, Monitor * lock);)
DEBUG_ONLY(static Monitor * get_least_ranked_lock(Monitor * locks);)
DEBUG_ONLY(Monitor * get_least_ranked_lock_besides_this(Monitor * locks);)
DEBUG_ONLY(static bool contains(Mutex* locks, Mutex* lock);)
DEBUG_ONLY(static Mutex* get_least_ranked_lock(Mutex* locks);)
DEBUG_ONLY(Mutex* get_least_ranked_lock_besides_this(Mutex* locks);)
#endif
void set_owner_implementation(Thread* owner) PRODUCT_RETURN;
@ -96,7 +96,6 @@ class Monitor : public CHeapObj<mtSynchronizer> {
void check_block_state (Thread* thread) PRODUCT_RETURN;
void check_safepoint_state (Thread* thread, bool safepoint_check) NOT_DEBUG_RETURN;
void assert_owner (Thread* expected) NOT_DEBUG_RETURN;
void assert_wait_lock_state (Thread* self) NOT_DEBUG_RETURN;
public:
enum {
@ -130,32 +129,21 @@ class Monitor : public CHeapObj<mtSynchronizer> {
};
enum SafepointCheckRequired {
_safepoint_check_never, // Monitors with this value will cause errors
_safepoint_check_never, // Mutexes with this value will cause errors
// when acquired by a JavaThread with a safepoint check.
_safepoint_check_sometimes, // A couple of special locks are acquired by JavaThreads sometimes
// with and sometimes without safepoint checks. These
// locks will not produce errors when locked.
_safepoint_check_always // Monitors with this value will cause errors
_safepoint_check_always // Mutexes with this value will cause errors
// when acquired by a JavaThread without a safepoint check.
};
NOT_PRODUCT(SafepointCheckRequired _safepoint_check_required;)
public:
Monitor(int rank, const char *name, bool allow_vm_block = false,
SafepointCheckRequired safepoint_check_required = _safepoint_check_always);
~Monitor();
// Wait until monitor is notified (or times out).
// Defaults are to make safepoint checks, wait time is forever (i.e.,
// zero), and not a suspend-equivalent condition. Returns true if wait
// times out; otherwise returns false.
bool wait(long timeout = 0,
bool as_suspend_equivalent = !_as_suspend_equivalent_flag);
bool wait_without_safepoint_check(long timeout = 0);
void notify();
void notify_all();
Mutex(int rank, const char *name, bool allow_vm_block = false,
SafepointCheckRequired safepoint_check_required = _safepoint_check_always);
~Mutex();
void lock(); // prints out warning if VM thread blocks
void lock(Thread *thread); // overloaded with current thread
@ -186,19 +174,49 @@ class Monitor : public CHeapObj<mtSynchronizer> {
DEBUG_ONLY(int rank() const { return _rank; })
bool allow_vm_block() { return _allow_vm_block; }
DEBUG_ONLY(Monitor *next() const { return _next; })
DEBUG_ONLY(void set_next(Monitor *next) { _next = next; })
DEBUG_ONLY(Mutex *next() const { return _next; })
DEBUG_ONLY(void set_next(Mutex *next) { _next = next; })
#endif
void set_owner(Thread* owner) {
#ifndef PRODUCT
set_owner_implementation(owner);
DEBUG_ONLY(void verify_Monitor(Thread* thr);)
DEBUG_ONLY(void verify_mutex(Thread* thr);)
#else
_owner = owner;
#endif
}
};
class Monitor : public Mutex {
void assert_wait_lock_state (Thread* self) NOT_DEBUG_RETURN;
public:
Monitor(int rank, const char *name, bool allow_vm_block = false,
SafepointCheckRequired safepoint_check_required = _safepoint_check_always);
// default destructor
// Wait until monitor is notified (or times out).
// Defaults are to make safepoint checks, wait time is forever (i.e.,
// zero), and not a suspend-equivalent condition. Returns true if wait
// times out; otherwise returns false.
bool wait(long timeout = 0,
bool as_suspend_equivalent = !_as_suspend_equivalent_flag);
bool wait_without_safepoint_check(long timeout = 0);
void notify();
void notify_all();
};
class PaddedMutex : public Mutex {
enum {
CACHE_LINE_PADDING = (int)DEFAULT_CACHE_LINE_SIZE - (int)sizeof(Mutex),
PADDING_LEN = CACHE_LINE_PADDING > 0 ? CACHE_LINE_PADDING : 1
};
char _padding[PADDING_LEN];
public:
PaddedMutex(int rank, const char *name, bool allow_vm_block = false,
SafepointCheckRequired safepoint_check_required = _safepoint_check_always) :
Mutex(rank, name, allow_vm_block, safepoint_check_required) {};
};
class PaddedMonitor : public Monitor {
@ -213,49 +231,4 @@ class PaddedMonitor : public Monitor {
Monitor(rank, name, allow_vm_block, safepoint_check_required) {};
};
// Normally we'd expect Monitor to extend Mutex in the sense that a monitor
// constructed from pthreads primitives might extend a mutex by adding
// a condvar and some extra metadata. In fact this was the case until J2SE7.
//
// Currently, however, the base object is a monitor. Monitor contains all the
// logic for wait(), notify(), etc. Mutex extends monitor and restricts the
// visibility of wait(), notify(), and notify_all().
//
// Another viable alternative would have been to have Monitor extend Mutex and
// implement all the normal mutex and wait()-notify() logic in Mutex base class.
// The wait()-notify() facility would be exposed via special protected member functions
// (e.g., _Wait() and _Notify()) in Mutex. Monitor would extend Mutex and expose wait()
// as a call to _Wait(). That is, the public wait() would be a wrapper for the protected
// _Wait().
//
// An even better alternative is to simply eliminate Mutex:: and use Monitor:: instead.
// After all, monitors are sufficient for Java-level synchronization. At one point in time
// there may have been some benefit to having distinct mutexes and monitors, but that time
// has passed.
//
class Mutex : public Monitor { // degenerate Monitor
public:
Mutex(int rank, const char *name, bool allow_vm_block = false,
SafepointCheckRequired safepoint_check_required = _safepoint_check_always);
// default destructor
private:
void notify();
void notify_all();
bool wait(long timeout, bool as_suspend_equivalent);
bool wait_without_safepoint_check(long timeout);
};
class PaddedMutex : public Mutex {
enum {
CACHE_LINE_PADDING = (int)DEFAULT_CACHE_LINE_SIZE - (int)sizeof(Mutex),
PADDING_LEN = CACHE_LINE_PADDING > 0 ? CACHE_LINE_PADDING : 1
};
char _padding[PADDING_LEN];
public:
PaddedMutex(int rank, const char *name, bool allow_vm_block = false,
SafepointCheckRequired safepoint_check_required = _safepoint_check_always) :
Mutex(rank, name, allow_vm_block, safepoint_check_required) {};
};
#endif // SHARE_RUNTIME_MUTEX_HPP

View File

@ -130,7 +130,7 @@ Monitor* JfrThreadSampler_lock = NULL;
#ifndef SUPPORTS_NATIVE_CX8
Mutex* UnsafeJlong_lock = NULL;
#endif
Monitor* CodeHeapStateAnalytics_lock = NULL;
Mutex* CodeHeapStateAnalytics_lock = NULL;
Mutex* MetaspaceExpand_lock = NULL;
Mutex* ClassLoaderDataGraph_lock = NULL;
@ -153,11 +153,11 @@ Monitor* JVMCI_lock = NULL;
#define MAX_NUM_MUTEX 128
static Monitor * _mutex_array[MAX_NUM_MUTEX];
static Mutex* _mutex_array[MAX_NUM_MUTEX];
static int _num_mutex;
#ifdef ASSERT
void assert_locked_or_safepoint(const Monitor * lock) {
void assert_locked_or_safepoint(const Mutex* lock) {
// check if this thread owns the lock (common case)
if (IgnoreLockingAssertions) return;
assert(lock != NULL, "Need non-NULL lock");
@ -171,7 +171,7 @@ void assert_locked_or_safepoint(const Monitor * lock) {
}
// a weaker assertion than the above
void assert_locked_or_safepoint_weak(const Monitor * lock) {
void assert_locked_or_safepoint_weak(const Mutex* lock) {
if (IgnoreLockingAssertions) return;
assert(lock != NULL, "Need non-NULL lock");
if (lock->is_locked()) return;
@ -181,7 +181,7 @@ void assert_locked_or_safepoint_weak(const Monitor * lock) {
}
// a stronger assertion than the above
void assert_lock_strong(const Monitor * lock) {
void assert_lock_strong(const Mutex* lock) {
if (IgnoreLockingAssertions) return;
assert(lock != NULL, "Need non-NULL lock");
if (lock->owned_by_self()) return;
@ -225,7 +225,7 @@ void mutex_init() {
}
def(ParGCRareEvent_lock , PaddedMutex , leaf , true, Monitor::_safepoint_check_always);
def(CGCPhaseManager_lock , PaddedMonitor, leaf, false, Monitor::_safepoint_check_always);
def(CodeCache_lock , PaddedMutex , special, true, Monitor::_safepoint_check_never);
def(CodeCache_lock , PaddedMonitor, special, true, Monitor::_safepoint_check_never);
def(RawMonitor_lock , PaddedMutex , special, true, Monitor::_safepoint_check_never);
def(OopMapCacheAlloc_lock , PaddedMutex , leaf, true, Monitor::_safepoint_check_always); // used for oop_map_cache allocation.
@ -334,7 +334,7 @@ void mutex_init() {
#endif // INCLUDE_CDS
}
GCMutexLocker::GCMutexLocker(Monitor * mutex) {
GCMutexLocker::GCMutexLocker(Mutex* mutex) {
if (SafepointSynchronize::is_at_safepoint()) {
_locked = false;
} else {

View File

@ -142,7 +142,7 @@ extern Mutex* MetaspaceExpand_lock; // protects Metaspace virtualsp
extern Mutex* ClassLoaderDataGraph_lock; // protects CLDG list, needed for concurrent unloading
extern Monitor* CodeHeapStateAnalytics_lock; // lock print functions against concurrent analyze functions.
extern Mutex* CodeHeapStateAnalytics_lock; // lock print functions against concurrent analyze functions.
// Only used locally in PrintCodeCacheLayout processing.
#if INCLUDE_JVMCI
@ -171,9 +171,9 @@ char *lock_name(Mutex *mutex);
// for debugging: check that we're already owning this lock (or are at a safepoint)
#ifdef ASSERT
void assert_locked_or_safepoint(const Monitor * lock);
void assert_locked_or_safepoint_weak(const Monitor * lock);
void assert_lock_strong(const Monitor * lock);
void assert_locked_or_safepoint(const Mutex* lock);
void assert_locked_or_safepoint_weak(const Mutex* lock);
void assert_lock_strong(const Mutex* lock);
#else
#define assert_locked_or_safepoint(lock)
#define assert_locked_or_safepoint_weak(lock)
@ -182,10 +182,10 @@ void assert_lock_strong(const Monitor * lock);
class MutexLocker: public StackObj {
protected:
Monitor* _mutex;
Mutex* _mutex;
private:
public:
MutexLocker(Monitor* mutex, Mutex::SafepointCheckFlag flag = Mutex::_safepoint_check_flag) :
MutexLocker(Mutex* mutex, Mutex::SafepointCheckFlag flag = Mutex::_safepoint_check_flag) :
_mutex(mutex) {
bool no_safepoint_check = flag == Mutex::_no_safepoint_check_flag;
if (_mutex != NULL) {
@ -199,7 +199,7 @@ class MutexLocker: public StackObj {
}
}
MutexLocker(Monitor* mutex, Thread* thread, Mutex::SafepointCheckFlag flag = Mutex::_safepoint_check_flag) :
MutexLocker(Mutex* mutex, Thread* thread, Mutex::SafepointCheckFlag flag = Mutex::_safepoint_check_flag) :
_mutex(mutex) {
bool no_safepoint_check = flag == Mutex::_no_safepoint_check_flag;
if (_mutex != NULL) {
@ -227,35 +227,36 @@ class MutexLocker: public StackObj {
class MonitorLocker: public MutexLocker {
Mutex::SafepointCheckFlag _flag;
Monitor* _monitor;
public:
MonitorLocker(Monitor* monitor, Mutex::SafepointCheckFlag flag = Mutex::_safepoint_check_flag) :
MutexLocker(monitor, flag), _flag(flag) {
MutexLocker(monitor, flag), _flag(flag), _monitor(monitor) {
// Superclass constructor did locking
assert(_mutex != NULL, "NULL monitor not allowed");
assert(_monitor != NULL, "NULL monitor not allowed");
}
MonitorLocker(Monitor* monitor, Thread* thread, Mutex::SafepointCheckFlag flag = Mutex::_safepoint_check_flag) :
MutexLocker(monitor, thread, flag), _flag(flag) {
MutexLocker(monitor, thread, flag), _flag(flag), _monitor(monitor) {
// Superclass constructor did locking
assert(_mutex != NULL, "NULL monitor not allowed");
assert(_monitor != NULL, "NULL monitor not allowed");
}
bool wait(long timeout = 0,
bool as_suspend_equivalent = !Mutex::_as_suspend_equivalent_flag) {
if (_flag == Mutex::_safepoint_check_flag) {
return _mutex->wait(timeout, as_suspend_equivalent);
return _monitor->wait(timeout, as_suspend_equivalent);
} else {
return _mutex->wait_without_safepoint_check(timeout);
return _monitor->wait_without_safepoint_check(timeout);
}
return false;
}
void notify_all() {
_mutex->notify_all();
_monitor->notify_all();
}
void notify() {
_mutex->notify();
_monitor->notify();
}
};
@ -268,10 +269,10 @@ class MonitorLocker: public MutexLocker {
class GCMutexLocker: public StackObj {
private:
Monitor* _mutex;
Mutex* _mutex;
bool _locked;
public:
GCMutexLocker(Monitor* mutex);
GCMutexLocker(Mutex* mutex);
~GCMutexLocker() { if (_locked) _mutex->unlock(); }
};
@ -280,11 +281,11 @@ public:
class MutexUnlocker: StackObj {
private:
Monitor* _mutex;
Mutex* _mutex;
bool _no_safepoint_check;
public:
MutexUnlocker(Monitor* mutex, Mutex::SafepointCheckFlag flag = Mutex::_safepoint_check_flag) :
MutexUnlocker(Mutex* mutex, Mutex::SafepointCheckFlag flag = Mutex::_safepoint_check_flag) :
_mutex(mutex),
_no_safepoint_check(flag) {
_mutex->unlock();

View File

@ -971,7 +971,7 @@ void Thread::print_value_on(outputStream* st) const {
#ifdef ASSERT
void Thread::print_owned_locks_on(outputStream* st) const {
Monitor *cur = _owned_locks;
Mutex* cur = _owned_locks;
if (cur == NULL) {
st->print(" (no locks) ");
} else {
@ -1011,7 +1011,7 @@ void Thread::check_for_valid_safepoint_state(bool potential_vm_operation) {
if (potential_vm_operation && !Universe::is_bootstrapping()) {
// Make sure we do not hold any locks that the VM thread also uses.
// This could potentially lead to deadlocks
for (Monitor *cur = _owned_locks; cur; cur = cur->next()) {
for (Mutex* cur = _owned_locks; cur; cur = cur->next()) {
// Threads_lock is special, since the safepoint synchronization will not start before this is
// acquired. Hence, a JavaThread cannot be holding it at a safepoint. So is VMOperationRequest_lock,
// since it is used to transfer control between JavaThreads and the VMThread

View File

@ -736,7 +736,7 @@ protected:
#ifdef ASSERT
private:
// Deadlock detection support for Mutex locks. List of locks own by thread.
Monitor* _owned_locks;
Mutex* _owned_locks;
// Mutex::set_owner_implementation is the only place where _owned_locks is modified,
// thus the friendship
friend class Mutex;
@ -745,7 +745,7 @@ protected:
public:
void print_owned_locks_on(outputStream* st) const;
void print_owned_locks() const { print_owned_locks_on(tty); }
Monitor* owned_locks() const { return _owned_locks; }
Mutex* owned_locks() const { return _owned_locks; }
bool owns_locks() const { return owned_locks() != NULL; }
// Deadlock detection