Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8274794: Make Thread::_owned_locks available in product #5896

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -303,6 +303,21 @@ void Mutex::print_on_error(outputStream* st) const {
// ----------------------------------------------------------------------------------
// Non-product code
//

#ifndef PRODUCT
void Mutex::print_on(outputStream* st) const {
st->print("Mutex: [" PTR_FORMAT "] %s - owner: " PTR_FORMAT,
p2i(this), _name, p2i(owner()));
#ifdef ASSERT
if (_allow_vm_block) {
st->print("%s", " allow_vm_block");
}
st->print(" %s", rank_name());
#endif
st->cr();
}
#endif // PRODUCT

#ifdef ASSERT
static Mutex::Rank _ranks[] = { Mutex::event, Mutex::service, Mutex::stackwatermark, Mutex::tty, Mutex::oopstorage,
Mutex::nosafepoint, Mutex::safepoint };
@@ -331,7 +346,6 @@ const char* Mutex::rank_name() const {
return rank_name_internal(_rank);
}


void Mutex::assert_no_overlap(Rank orig, Rank adjusted, int adjust) {
int i = 0;
while (_ranks[i] < orig) i++;
@@ -343,21 +357,7 @@ void Mutex::assert_no_overlap(Rank orig, Rank adjusted, int adjust) {
rank_name_internal(orig), adjust, rank_name_internal(adjusted));
}
}
#endif // ASSERT

#ifndef PRODUCT
void Mutex::print_on(outputStream* st) const {
st->print("Mutex: [" PTR_FORMAT "] %s - owner: " PTR_FORMAT,
p2i(this), _name, p2i(owner()));
if (_allow_vm_block) {
st->print("%s", " allow_vm_block");
}
DEBUG_ONLY(st->print(" %s", rank_name()));
st->cr();
}
#endif // PRODUCT

#ifdef ASSERT
void Mutex::assert_owner(Thread * expected) {
const char* msg = "invalid owner";
if (expected == NULL) {
@@ -455,12 +455,13 @@ bool Mutex::contains(Mutex* locks, Mutex* lock) {
}
return false;
}
#endif // ASSERT

// Called immediately after lock acquisition or release as a diagnostic
// to track the lock-set of the thread.
// Rather like an EventListener for _owner (:>).

void Mutex::set_owner_implementation(Thread *new_owner) {
void Mutex::set_owner(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.
@@ -482,19 +483,21 @@ void Mutex::set_owner_implementation(Thread *new_owner) {
this->_next = new_owner->_owned_locks;
new_owner->_owned_locks = this;

#ifdef ASSERT
// NSV implied with locking allow_vm_block flag.
// The tty_lock is special because it is released for the safepoint by
// the safepoint mechanism.
if (new_owner->is_Java_thread() && _allow_vm_block && this != tty_lock) {
JavaThread::cast(new_owner)->inc_no_safepoint_count();
}
#endif

} else {
// the thread is releasing this lock

Thread* old_owner = owner();
_last_owner = old_owner;
_skip_rank_check = false;
DEBUG_ONLY(_last_owner = old_owner;)
DEBUG_ONLY(_skip_rank_check = false;)

assert(old_owner != NULL, "removing the owner thread of an unowned mutex");
assert(old_owner == Thread::current(), "removing the owner thread of an unowned mutex");
@@ -521,10 +524,11 @@ void Mutex::set_owner_implementation(Thread *new_owner) {
}
_next = NULL;

#ifdef ASSERT
// ~NSV implied with locking allow_vm_block flag.
if (old_owner->is_Java_thread() && _allow_vm_block && this != tty_lock) {
JavaThread::cast(old_owner)->dec_no_safepoint_count();
}
#endif // ASSERT
}
}
#endif // ASSERT
@@ -87,20 +87,19 @@ class Mutex : public CHeapObj<mtSynchronizer> {
// than the lock owner are inherently racy.
Thread* volatile _owner;
void raw_set_owner(Thread* new_owner) { Atomic::store(&_owner, new_owner); }
void link_locks(Thread* new_owner);

protected: // Monitor-Mutex metadata
os::PlatformMonitor _lock; // Native monitor implementation
const char* _name; // Name of mutex/monitor
Mutex* _next; // Used by a Thread to link up owned locks

// Debugging fields for naming, deadlock detection, etc. (some only used in debug mode)
#ifndef PRODUCT
bool _allow_vm_block;
#endif
#ifdef ASSERT
Rank _rank; // rank (to avoid/detect potential deadlocks)
Mutex* _next; // Used by a Thread to link up owned locks
Thread* _last_owner; // the last thread to own the lock
bool _skip_rank_check; // read only by owner when doing rank checks
bool _skip_rank_check; // read only by owner when doing rank checks
bool _allow_vm_block;

static bool contains(Mutex* locks, Mutex* lock);
static Mutex* get_least_ranked_lock(Mutex* locks);
@@ -113,12 +112,11 @@ class Mutex : public CHeapObj<mtSynchronizer> {
public:
Rank rank() const { return _rank; }
const char* rank_name() const;
Mutex* next() const { return _next; }
void set_next(Mutex *next) { _next = next; }
#endif // ASSERT

protected:
void set_owner_implementation(Thread* owner) NOT_DEBUG({ raw_set_owner(owner);});
void set_next(Mutex *next) { _next = next; }

void check_block_state (Thread* thread) NOT_DEBUG_RETURN;
void check_safepoint_state (Thread* thread) NOT_DEBUG_RETURN;
void check_no_safepoint_state(Thread* thread) NOT_DEBUG_RETURN;
@@ -184,10 +182,11 @@ class Mutex : public CHeapObj<mtSynchronizer> {
// Current owner - note not MT-safe. Can only be used to guarantee that
// the current running thread owns the lock
Thread* owner() const { return Atomic::load(&_owner); }
void set_owner(Thread* owner) { set_owner_implementation(owner); }
void set_owner(Thread* owner);
bool owned_by_self() const;

const char *name() const { return _name; }
const char *name() const { return _name; }
Mutex* next() const { return _next; }

void print_on_error(outputStream* st) const;
#ifndef PRODUCT
@@ -157,11 +157,6 @@ Mutex* Bootclasspath_lock = NULL;
Monitor* JVMCI_lock = NULL;
#endif


#define MAX_NUM_MUTEX 128
static Mutex* _mutex_array[MAX_NUM_MUTEX];
static int _num_mutex;

#ifdef ASSERT
void assert_locked_or_safepoint(const Mutex* lock) {
// check if this thread owns the lock (common case)
@@ -194,26 +189,18 @@ void assert_locked_or_safepoint_or_handshake(const Mutex* lock, const JavaThread
}
#endif

static void add_mutex(Mutex* var) {
assert(_num_mutex < MAX_NUM_MUTEX, "increase MAX_NUM_MUTEX");
_mutex_array[_num_mutex++] = var;
}

#define def(var, type, pri, vm_block) { \
var = new type(Mutex::pri, #var, vm_block); \
add_mutex(var); \
}

// Specify relative ranked lock
#ifdef ASSERT
#define defl(var, type, held_lock, vm_block) { \
var = new type(held_lock->rank()-1, #var, vm_block); \
add_mutex(var); \
}
#else
#define defl(var, type, held_lock, vm_block) { \
var = new type(Mutex::safepoint, #var, vm_block); \
add_mutex(var); \
}
#endif

@@ -380,23 +367,3 @@ GCMutexLocker::GCMutexLocker(Mutex* mutex) {
_mutex->lock();
}
}

// Print all mutexes/monitors that are currently owned by a thread; called
// by fatal error handler.
void print_owned_locks_on_error(outputStream* st) {
st->print("VM Mutex/Monitor currently owned by a thread: ");
bool none = true;
for (int i = 0; i < _num_mutex; i++) {
// see if it has an owner
if (_mutex_array[i]->owner() != NULL) {
if (none) {
// print format used by Mutex::print_on_error()
st->print_cr(" ([mutex/lock_event])");
none = false;
}
_mutex_array[i]->print_on_error(st);
st->cr();
}
}
if (none) st->print_cr("None");
}
@@ -169,12 +169,6 @@ extern Mutex* tty_lock; // lock to synchronize output.
// order. If their implementations change such that these assumptions
// are violated, a whole lot of code will break.

// Print all mutexes/monitors that are currently owned by a thread; called
// by fatal error handler.
void print_owned_locks_on_error(outputStream* st);

char *lock_name(Mutex *mutex);

// for debugging: check that we're already owning this lock (or are at a safepoint / handshake)
#ifdef ASSERT
void assert_locked_or_safepoint(const Mutex* lock);
@@ -236,7 +236,7 @@ Thread::Thread() {
new HandleMark(this);

// plain initialization
debug_only(_owned_locks = NULL;)
_owned_locks = NULL;
NOT_PRODUCT(_skip_gcalot = false;)
_jvmti_env_iteration_count = 0;
set_allocated_bytes(0);
@@ -604,8 +604,6 @@ void Thread::print_on(outputStream* st, bool print_extended_info) const {
osthread()->print_on(st);
}
ThreadsSMRSupport::print_info_on(this, st);
st->print(" ");
debug_only(if (WizardMode) print_owned_locks_on(st);)
}

void Thread::print() const { print_on(tty); }
@@ -639,20 +637,18 @@ void Thread::print_value_on(outputStream* st) const {
st->print(INTPTR_FORMAT, p2i(this)); // print address
}

#ifdef ASSERT
void Thread::print_owned_locks_on(outputStream* st) const {
Mutex* cur = _owned_locks;
if (cur == NULL) {
st->print(" (no locks) ");
st->print_cr(" (no locks) ");
} else {
st->print_cr(" Locks owned:");
while (cur) {
cur->print_on(st);
cur->print_on_error(st);
st->cr();
cur = cur->next();
}
}
}
#endif // ASSERT

// We had to move these methods here, because vm threads get into ObjectSynchronizer::enter
// However, there is a note in JavaThread::is_lock_owned() about the VM threads not being
@@ -3847,6 +3843,34 @@ void Threads::print_threads_compiling(outputStream* st, char* buf, int buflen, b
}
}

// Print all mutexes/monitors that are currently owned by a thread; called
// by fatal error handler.
void Threads::print_owned_locks_on_error(outputStream* st) {
class PrintLocksClosure : public ThreadClosure {
outputStream* _st;
bool* _printed;
public:
PrintLocksClosure(outputStream* st, bool* none) : _st(st), _printed(none) {}
void do_thread(Thread* t) {
if (t->owns_locks()) {
t->print_owned_locks_on(_st);
}
}
};

st->print_cr("VM Mutex/Monitor currently owned by a thread: ");
bool none = true;
ALL_JAVA_THREADS(jt) {
if (jt->owns_locks()) {
jt->print_owned_locks_on(st);
none = false;
}
}

PrintLocksClosure tc(st, &none);
non_java_threads_do(&tc);
if (none) st->print_cr("None");
}

// Ad-hoc mutual exclusion primitives: SpinLock
//
@@ -574,23 +574,21 @@ class Thread: public ThreadShadow {
// Basic, non-virtual, printing support that is simple and always safe.
void print_value_on(outputStream* st) const;

// Debug-only code
#ifdef ASSERT
private:
// Deadlock detection support for Mutex locks. List of locks own by thread.
Mutex* _owned_locks;
// Mutex::set_owner_implementation is the only place where _owned_locks is modified,
// thus the friendship
// Deadlock detection support for Mutex locks, and help with crash handling.
// List of locks own by thread.
friend class Mutex;
friend class Monitor;
Mutex* _owned_locks;

public:
void print_owned_locks() const { print_owned_locks_on(tty); }
void print_owned_locks_on(outputStream* st) const;
void print_owned_locks() const { print_owned_locks_on(tty); }
Mutex* owned_locks() const { return _owned_locks; }
bool owns_locks() const { return owned_locks() != NULL; }

// Deadlock detection
// Debug-only code
Mutex* owned_locks() const { return _owned_locks; }
bool owns_locks() const { return _owned_locks != NULL; }

#ifdef ASSERT
ResourceMark* current_resource_mark() { return _current_resource_mark; }
void set_current_resource_mark(ResourceMark* rm) { _current_resource_mark = rm; }
#endif // ASSERT
@@ -1727,6 +1725,8 @@ class Threads: AllStatic {
int buflen, bool* found_current);
static void print_threads_compiling(outputStream* st, char* buf, int buflen, bool short_form = false);

static void print_owned_locks_on_error(outputStream* st);

// Get Java threads that are waiting to enter a monitor.
static GrowableArray<JavaThread*>* get_pending_threads(ThreadsList * t_list,
int count, address monitor);
@@ -995,7 +995,7 @@ void VMError::report(outputStream* st, bool _verbose) {

// mutexes/monitors that currently have an owner
if (_verbose) {
print_owned_locks_on_error(st);
Threads::print_owned_locks_on_error(st);
st->cr();
}

@@ -1893,6 +1893,12 @@ void VMError::controlled_crash(int how) {
switch (how) {
case 1: assert(how == 0, "test assert"); break;
case 2: guarantee(how == 0, "test guarantee"); break;
case 3: {
Mutex* ErrorTest_lock = new Mutex(Mutex::nosafepoint, "ErrorTest_lock");
MutexLocker ml(ErrorTest_lock, Mutex::_no_safepoint_check_flag);
assert(how == 0, "test assert with lock");
break;
}

// The other cases are unused.
case 14: crash_with_segfault(); break;