/* * Copyright (c) 1998, 2022, 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. *
*/
#ifdefined(LINUX) || defined(AIX) || defined(BSD) # include "mutex_posix.hpp" #else # include OS_HEADER(mutex) #endif
// A Mutex/Monitor is a simple wrapper around a native lock plus condition // variable that supports lock ownership tracking, lock ranking for deadlock // detection and coordinates with the safepoint protocol.
// Locking is non-recursive: if you try to lock a mutex you already own then you // will get an assertion failure in a debug build (which should suffice to expose // usage bugs). If you call try_lock on a mutex you already own it will return false. // The underlying PlatformMutex may support recursive locking but this is not exposed // and we account for that possibility in try_lock.
// A thread is not allowed to safepoint while holding a mutex whose rank // is nosafepoint or lower.
class Mutex : public CHeapObj<mtSynchronizer> {
public: // Special low level locks are given names and ranges avoid overlap. enumclass Rank {
event,
service = event + 6,
stackwatermark = service + 3,
tty = stackwatermark + 3,
oopstorage = tty + 3,
nosafepoint = oopstorage + 6,
safepoint = nosafepoint + 20
};
private: // The _owner field is only set by the current thread, either to itself after it has acquired // the low-level _lock, or to NULL before it has released the _lock. Accesses by any thread other // than the lock owner are inherently racy.
Thread* volatile _owner; void raw_set_owner(Thread* new_owner) { Atomic::store(&_owner, new_owner); }
protected: // Monitor-Mutex metadata
PlatformMonitor _lock; // Native monitor implementation constchar* _name; // Name of mutex/monitor
// 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
static Mutex* get_least_ranked_lock(Mutex* locks);
Mutex* get_least_ranked_lock_besides_this(Mutex* locks); bool skip_rank_check() {
assert(owned_by_self(), "only the owner should call this"); return _skip_rank_check;
}
// Locks can be acquired with or without a safepoint check. NonJavaThreads do not follow // the safepoint protocol when acquiring locks.
// Each lock can be acquired by only JavaThreads, only NonJavaThreads, or shared between // Java and NonJavaThreads. When the lock is initialized with rank > nosafepoint, // that means that whenever the lock is acquired by a JavaThread, it will verify that // it is done with a safepoint check. In corollary, when the lock is initialized with // rank <= nosafepoint, that means that whenever the lock is acquired by a JavaThread // it will verify that it is done without a safepoint check.
// TODO: Locks that are shared between JavaThreads and NonJavaThreads // should never encounter a safepoint check while they are held, or else a // deadlock can occur. We should check this by noting which // locks are shared, and walk held locks during safepoint checking.
enumclass SafepointCheckFlag {
_safepoint_check_flag,
_no_safepoint_check_flag
}; // Bring the enumerator names into class scope. staticconst SafepointCheckFlag _safepoint_check_flag =
SafepointCheckFlag::_safepoint_check_flag; staticconst SafepointCheckFlag _no_safepoint_check_flag =
SafepointCheckFlag::_no_safepoint_check_flag;
void lock(); // prints out warning if VM thread blocks void lock(Thread *thread); // overloaded with current thread void unlock(); bool is_locked() const { return owner() != NULL; }
bool try_lock(); // Like lock(), but unblocking. It returns false instead private: void lock_contended(Thread *thread); // contended slow-path bool try_lock_inner(bool do_rank_checks); public:
void release_for_safepoint();
// Lock without safepoint check. Should ONLY be used by safepoint code and other code // that is guaranteed not to block while running inside the VM. void lock_without_safepoint_check(); void lock_without_safepoint_check(Thread* self); // A thread should not call this if failure to acquire ownership will blocks its progress bool try_lock_without_rank_check();
// 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); } bool owned_by_self() const;
// Wait until monitor is notified (or times out). // Defaults are to make safepoint checks, wait time is forever (i.e., // zero). Returns true if wait times out; otherwise returns false. bool wait(int64_t timeout = 0); bool wait_without_safepoint_check(int64_t timeout = 0); void notify(); void notify_all();
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.