Pass self to lock methods.
This avoids frequent recomputation of
Thread::Current/pthread_getspecific.
Also add a futex based reader/writer mutex that is disabled.
Change-Id: I118fdb99ef1d1c4bfda6446ba3a0d8b6ab31eaee
diff --git a/src/mutex.h b/src/mutex.h
index 85d75ab..af2b352 100644
--- a/src/mutex.h
+++ b/src/mutex.h
@@ -24,8 +24,11 @@
#include <string>
#include "globals.h"
-#include "logging.h"
+#include "locks.h"
#include "macros.h"
+#include "thread.h"
+
+#define ART_USE_FUTEXES 0
// Currently Darwin doesn't support locks with timeouts.
#if !defined(__APPLE__)
@@ -38,126 +41,6 @@
const bool kDebugLocking = kIsDebugBuild;
-class LOCKABLE Mutex;
-class LOCKABLE ReaderWriterMutex;
-
-// MutexLevel is used to impose a lock hierarchy [1] where acquisition of a Mutex at a higher or
-// equal level to a lock a thread holds is invalid. The lock hierarchy achieves a cycle free
-// partial ordering and thereby cause deadlock situations to fail checks.
-//
-// [1] http://www.drdobbs.com/parallel/use-lock-hierarchies-to-avoid-deadlock/204801163
-enum MutexLevel {
- kLoggingLock = 0,
- kUnexpectedSignalLock = 1,
- kThreadSuspendCountLock = 2,
- kAbortLock = 3,
- kDefaultMutexLevel = 4,
- kJdwpSerialLock = 5,
- kAllocSpaceLock = 6,
- kLoadLibraryLock = 7,
- kClassLinkerClassesLock = 8,
- kThreadListLock = 9,
- kHeapBitmapLock = 10,
- kMonitorLock = 11,
- kMutatorLock = 12,
- kZygoteCreationLock = 13,
- kMaxMutexLevel = kMutatorLock,
-};
-std::ostream& operator<<(std::ostream& os, const MutexLevel& rhs);
-
-// Global mutexes corresponding to the levels above.
-class Locks {
- public:
- static void Init();
-
- // The mutator_lock_ is used to allow mutators to execute in a shared (reader) mode or to block
- // mutators by having an exclusive (writer) owner. In normal execution each mutator thread holds
- // a share on the mutator_lock_. The garbage collector may also execute with shared access but
- // at times requires exclusive access to the heap (not to be confused with the heap meta-data
- // guarded by the heap_lock_ below). When the garbage collector requires exclusive access it asks
- // the mutators to suspend themselves which also involves usage of the thread_suspend_count_lock_
- // to cover weaknesses in using ReaderWriterMutexes with ConditionVariables. We use a condition
- // variable to wait upon in the suspension logic as releasing and then re-acquiring a share on
- // the mutator lock doesn't necessarily allow the exclusive user (e.g the garbage collector)
- // chance to acquire the lock.
- //
- // Thread suspension:
- // Shared users | Exclusive user
- // (holding mutator lock and in kRunnable state) | .. running ..
- // .. running .. | Request thread suspension by:
- // .. running .. | - acquiring thread_suspend_count_lock_
- // .. running .. | - incrementing Thread::suspend_count_ on
- // .. running .. | all mutator threads
- // .. running .. | - releasing thread_suspend_count_lock_
- // .. running .. | Block trying to acquire exclusive mutator lock
- // Poll Thread::suspend_count_ and enter full | .. blocked ..
- // suspend code. | .. blocked ..
- // Change state to kSuspended | .. blocked ..
- // x: Release share on mutator_lock_ | Carry out exclusive access
- // Acquire thread_suspend_count_lock_ | .. exclusive ..
- // while Thread::suspend_count_ > 0 | .. exclusive ..
- // - wait on Thread::resume_cond_ | .. exclusive ..
- // (releases thread_suspend_count_lock_) | .. exclusive ..
- // .. waiting .. | Release mutator_lock_
- // .. waiting .. | Request thread resumption by:
- // .. waiting .. | - acquiring thread_suspend_count_lock_
- // .. waiting .. | - decrementing Thread::suspend_count_ on
- // .. waiting .. | all mutator threads
- // .. waiting .. | - notifying on Thread::resume_cond_
- // - re-acquire thread_suspend_count_lock_ | - releasing thread_suspend_count_lock_
- // Release thread_suspend_count_lock_ | .. running ..
- // Acquire share on mutator_lock_ | .. running ..
- // - This could block but the thread still | .. running ..
- // has a state of kSuspended and so this | .. running ..
- // isn't an issue. | .. running ..
- // Acquire thread_suspend_count_lock_ | .. running ..
- // - we poll here as we're transitioning into | .. running ..
- // kRunnable and an individual thread suspend | .. running ..
- // request (e.g for debugging) won't try | .. running ..
- // to acquire the mutator lock (which would | .. running ..
- // block as we hold the mutator lock). This | .. running ..
- // poll ensures that if the suspender thought | .. running ..
- // we were suspended by incrementing our | .. running ..
- // Thread::suspend_count_ and then reading | .. running ..
- // our state we go back to waiting on | .. running ..
- // Thread::resume_cond_. | .. running ..
- // can_go_runnable = Thread::suspend_count_ == 0 | .. running ..
- // Release thread_suspend_count_lock_ | .. running ..
- // if can_go_runnable | .. running ..
- // Change state to kRunnable | .. running ..
- // else | .. running ..
- // Goto x | .. running ..
- // .. running .. | .. running ..
- static ReaderWriterMutex* mutator_lock_;
-
- // Allow reader-writer mutual exclusion on the mark and live bitmaps of the heap.
- static ReaderWriterMutex* heap_bitmap_lock_ ACQUIRED_AFTER(mutator_lock_);
-
- // The thread_list_lock_ guards ThreadList::list_. It is also commonly held to stop threads
- // attaching and detaching.
- static Mutex* thread_list_lock_ ACQUIRED_AFTER(heap_bitmap_lock_);
-
- // Guards lists of classes within the class linker.
- static Mutex* classlinker_classes_lock_ ACQUIRED_AFTER(thread_list_lock_);
-
- // When declaring any Mutex add DEFAULT_MUTEX_ACQUIRED_AFTER to use annotalysis to check the code
- // doesn't try to hold a higher level Mutex.
- #define DEFAULT_MUTEX_ACQUIRED_AFTER ACQUIRED_AFTER(classlinker_classes_lock_)
-
- // Have an exclusive aborting thread.
- static Mutex* abort_lock_ ACQUIRED_AFTER(classlinker_classes_lock_);
-
- // Allow mutual exclusion when manipulating Thread::suspend_count_.
- // TODO: Does the trade-off of a per-thread lock make sense?
- static Mutex* thread_suspend_count_lock_ ACQUIRED_AFTER(abort_lock_);
-
- // One unexpected signal at a time lock.
- static Mutex* unexpected_signal_lock_ ACQUIRED_AFTER(thread_suspend_count_lock_);
-
- // Have an exclusive logging thread.
- static Mutex* logging_lock_ ACQUIRED_AFTER(unexpected_signal_lock_);
-};
-
// Base class for all Mutex implementations
class BaseMutex {
public:
@@ -171,13 +54,13 @@
protected:
friend class ConditionVariable;
- BaseMutex(const char* name, MutexLevel level);
+ BaseMutex(const char* name, LockLevel level);
virtual ~BaseMutex() {}
- void RegisterAsLockedWithCurrentThread();
- void RegisterAsUnlockedWithCurrentThread();
- void CheckSafeToWait();
+ void RegisterAsLocked(Thread* self);
+ void RegisterAsUnlocked(Thread* self);
+ void CheckSafeToWait(Thread* self);
- const MutexLevel level_; // Support for lock hierarchy.
+ const LockLevel level_; // Support for lock hierarchy.
const std::string name_;
};
@@ -195,41 +78,42 @@
// an error. Being non-reentrant simplifies Waiting on ConditionVariables.
class LOCKABLE Mutex : public BaseMutex {
public:
- explicit Mutex(const char* name, MutexLevel level = kDefaultMutexLevel, bool recursive = false);
+ explicit Mutex(const char* name, LockLevel level = kDefaultMutexLevel, bool recursive = false);
~Mutex();
virtual bool IsMutex() const { return true; }
// Block until mutex is free then acquire exclusive access.
- void ExclusiveLock() EXCLUSIVE_LOCK_FUNCTION();
- void Lock() EXCLUSIVE_LOCK_FUNCTION() { ExclusiveLock(); }
+ void ExclusiveLock(Thread* self) EXCLUSIVE_LOCK_FUNCTION();
+ void Lock(Thread* self) EXCLUSIVE_LOCK_FUNCTION() { ExclusiveLock(self); }
// Returns true if acquires exclusive access, false otherwise.
- bool ExclusiveTryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true);
- bool TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true) { return ExclusiveTryLock(); }
+ bool ExclusiveTryLock(Thread* self) EXCLUSIVE_TRYLOCK_FUNCTION(true);
+ bool TryLock(Thread* self) EXCLUSIVE_TRYLOCK_FUNCTION(true) { return ExclusiveTryLock(self); }
// Release exclusive access.
- void ExclusiveUnlock() UNLOCK_FUNCTION();
- void Unlock() UNLOCK_FUNCTION() { ExclusiveUnlock(); }
+ void ExclusiveUnlock(Thread* self) UNLOCK_FUNCTION();
+ void Unlock(Thread* self) UNLOCK_FUNCTION() { ExclusiveUnlock(self); }
// Is the current thread the exclusive holder of the Mutex.
- bool IsExclusiveHeld() const;
+ bool IsExclusiveHeld(const Thread* self) const;
// Assert that the Mutex is exclusively held by the current thread.
- void AssertExclusiveHeld() {
+ void AssertExclusiveHeld(const Thread* self) {
if (kDebugLocking) {
- CHECK(IsExclusiveHeld());
+ CHECK(IsExclusiveHeld(self));
}
}
- void AssertHeld() { AssertExclusiveHeld(); }
+ void AssertHeld(const Thread* self) { AssertExclusiveHeld(self); }
+ void AssertHeld() { AssertExclusiveHeld(Thread::Current()); }
// Assert that the Mutex is not held by the current thread.
- void AssertNotHeldExclusive() {
+ void AssertNotHeldExclusive(const Thread* self) {
if (kDebugLocking) {
- CHECK(!IsExclusiveHeld());
+ CHECK(!IsExclusiveHeld(self));
}
}
- void AssertNotHeld() { AssertNotHeldExclusive(); }
+ void AssertNotHeld(const Thread* self) { AssertNotHeldExclusive(self); }
// Id associated with exclusive owner.
uint64_t GetExclusiveOwnerTid() const;
@@ -266,79 +150,91 @@
// * for large values of n the SharedLock may block.
class LOCKABLE ReaderWriterMutex : public BaseMutex {
public:
- explicit ReaderWriterMutex(const char* name, MutexLevel level = kDefaultMutexLevel);
+ explicit ReaderWriterMutex(const char* name, LockLevel level = kDefaultMutexLevel);
~ReaderWriterMutex();
virtual bool IsReaderWriterMutex() const { return true; }
// Block until ReaderWriterMutex is free then acquire exclusive access.
- void ExclusiveLock() EXCLUSIVE_LOCK_FUNCTION();
- void WriterLock() EXCLUSIVE_LOCK_FUNCTION() { ExclusiveLock(); }
+ void ExclusiveLock(Thread* self) EXCLUSIVE_LOCK_FUNCTION();
+ void WriterLock(Thread* self) EXCLUSIVE_LOCK_FUNCTION() { ExclusiveLock(self); }
// Release exclusive access.
- void ExclusiveUnlock() UNLOCK_FUNCTION();
- void WriterUnlock() UNLOCK_FUNCTION() { ExclusiveUnlock(); }
+ void ExclusiveUnlock(Thread* self) UNLOCK_FUNCTION();
+ void WriterUnlock(Thread* self) UNLOCK_FUNCTION() { ExclusiveUnlock(self); }
// Block until ReaderWriterMutex is free and acquire exclusive access. Returns true on success
// or false if timeout is reached.
#if HAVE_TIMED_RWLOCK
- bool ExclusiveLockWithTimeout(const timespec& abs_timeout) EXCLUSIVE_TRYLOCK_FUNCTION(true);
+ bool ExclusiveLockWithTimeout(Thread* self, const timespec& abs_timeout)
+ EXCLUSIVE_TRYLOCK_FUNCTION(true);
#endif
// Block until ReaderWriterMutex is shared or free then acquire a share on the access.
- void SharedLock() SHARED_LOCK_FUNCTION();
- void ReaderLock() SHARED_LOCK_FUNCTION() { SharedLock(); }
+ void SharedLock(Thread* self) SHARED_LOCK_FUNCTION();
+ void ReaderLock(Thread* self) SHARED_LOCK_FUNCTION() { SharedLock(self); }
// Try to acquire share of ReaderWriterMutex.
- bool SharedTryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true);
+ bool SharedTryLock(Thread* self) EXCLUSIVE_TRYLOCK_FUNCTION(true);
// Release a share of the access.
- void SharedUnlock() UNLOCK_FUNCTION();
- void ReaderUnlock() UNLOCK_FUNCTION() { SharedUnlock(); }
+ void SharedUnlock(Thread* self) UNLOCK_FUNCTION();
+ void ReaderUnlock(Thread* self) UNLOCK_FUNCTION() { SharedUnlock(self); }
// Is the current thread the exclusive holder of the ReaderWriterMutex.
- bool IsExclusiveHeld() const;
+ bool IsExclusiveHeld(const Thread* self) const;
// Assert the current thread has exclusive access to the ReaderWriterMutex.
- void AssertExclusiveHeld() {
+ void AssertExclusiveHeld(const Thread* self) {
if (kDebugLocking) {
- CHECK(IsExclusiveHeld());
+ CHECK(IsExclusiveHeld(self));
}
}
- void AssertWriterHeld() { AssertExclusiveHeld(); }
+ void AssertWriterHeld(const Thread* self) { AssertExclusiveHeld(self); }
// Assert the current thread doesn't have exclusive access to the ReaderWriterMutex.
- void AssertNotExclusiveHeld() {
+ void AssertNotExclusiveHeld(const Thread* self) {
if (kDebugLocking) {
- CHECK(!IsExclusiveHeld());
+ CHECK(!IsExclusiveHeld(self));
}
}
- void AssertNotWriterHeld() { AssertNotExclusiveHeld(); }
+ void AssertNotWriterHeld(const Thread* self) { AssertNotExclusiveHeld(self); }
// Is the current thread a shared holder of the ReaderWriterMutex.
- bool IsSharedHeld() const;
+ bool IsSharedHeld(const Thread* self) const;
// Assert the current thread has shared access to the ReaderWriterMutex.
- void AssertSharedHeld() {
+ void AssertSharedHeld(const Thread* self) {
if (kDebugLocking) {
- CHECK(IsSharedHeld());
+ CHECK(IsSharedHeld(self));
}
}
- void AssertReaderHeld() { AssertSharedHeld(); }
+ void AssertReaderHeld(const Thread* self) { AssertSharedHeld(self); }
// Assert the current thread doesn't hold this ReaderWriterMutex either in shared or exclusive
// mode.
- void AssertNotHeld() {
+ void AssertNotHeld(const Thread* self) {
if (kDebugLocking) {
- CHECK(!IsSharedHeld());
+ CHECK(!IsSharedHeld(self));
}
}
// Id associated with exclusive owner.
uint64_t GetExclusiveOwnerTid() const;
- private:
- pthread_rwlock_t rwlock_;
+ private:
+#if ART_USE_FUTEXES
+ // -1 implies held exclusive, +ve shared held by state_ many owners.
+ volatile int32_t state_;
+ // Exclusive owner.
+ volatile uint64_t exclusive_owner_;
+ // Pending readers.
+ volatile int32_t num_pending_readers_;
+ // Pending writers.
+ volatile int32_t num_pending_writers_;
+#else
+ pthread_rwlock_t rwlock_;
+#endif
friend class MutexTester;
DISALLOW_COPY_AND_ASSIGN(ReaderWriterMutex);
};
@@ -352,8 +248,8 @@
void Broadcast();
void Signal();
- void Wait(Mutex& mutex);
- void TimedWait(Mutex& mutex, const timespec& ts);
+ void Wait(Thread* self, Mutex& mutex);
+ void TimedWait(Thread* self, Mutex& mutex, const timespec& ts);
private:
pthread_cond_t cond_;
@@ -365,15 +261,20 @@
// upon destruction.
class SCOPED_LOCKABLE MutexLock {
public:
- explicit MutexLock(Mutex& mu) EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
- mu_.ExclusiveLock();
+ explicit MutexLock(Thread* self, Mutex& mu) EXCLUSIVE_LOCK_FUNCTION(mu) : self_(self), mu_(mu) {
+ mu_.ExclusiveLock(self_);
+ }
+
+ explicit MutexLock(Mutex& mu) EXCLUSIVE_LOCK_FUNCTION(mu) : self_(Thread::Current()), mu_(mu) {
+ mu_.ExclusiveLock(self_);
}
~MutexLock() UNLOCK_FUNCTION() {
- mu_.ExclusiveUnlock();
+ mu_.ExclusiveUnlock(self_);
}
private:
+ Thread* const self_;
Mutex& mu_;
DISALLOW_COPY_AND_ASSIGN(MutexLock);
};
@@ -384,15 +285,22 @@
// construction and releases it upon destruction.
class SCOPED_LOCKABLE ReaderMutexLock {
public:
- explicit ReaderMutexLock(ReaderWriterMutex& mu) EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
- mu_.SharedLock();
+ explicit ReaderMutexLock(Thread* self, ReaderWriterMutex& mu) EXCLUSIVE_LOCK_FUNCTION(mu) :
+ self_(self), mu_(mu) {
+ mu_.SharedLock(self_);
+ }
+
+ explicit ReaderMutexLock(ReaderWriterMutex& mu) EXCLUSIVE_LOCK_FUNCTION(mu) :
+ self_(Thread::Current()), mu_(mu) {
+ mu_.SharedLock(self_);
}
~ReaderMutexLock() UNLOCK_FUNCTION() {
- mu_.SharedUnlock();
+ mu_.SharedUnlock(self_);
}
private:
+ Thread* const self_;
ReaderWriterMutex& mu_;
DISALLOW_COPY_AND_ASSIGN(ReaderMutexLock);
};
@@ -404,15 +312,22 @@
// construction and releases it upon destruction.
class SCOPED_LOCKABLE WriterMutexLock {
public:
- explicit WriterMutexLock(ReaderWriterMutex& mu) EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
- mu_.ExclusiveLock();
+ explicit WriterMutexLock(Thread* self, ReaderWriterMutex& mu) EXCLUSIVE_LOCK_FUNCTION(mu) :
+ self_(self), mu_(mu) {
+ mu_.ExclusiveLock(self_);
+ }
+
+ explicit WriterMutexLock(ReaderWriterMutex& mu) EXCLUSIVE_LOCK_FUNCTION(mu) :
+ self_(Thread::Current()), mu_(mu) {
+ mu_.ExclusiveLock(self_);
}
~WriterMutexLock() UNLOCK_FUNCTION() {
- mu_.ExclusiveUnlock();
+ mu_.ExclusiveUnlock(self_);
}
private:
+ Thread* self_;
ReaderWriterMutex& mu_;
DISALLOW_COPY_AND_ASSIGN(WriterMutexLock);
};
@@ -420,27 +335,6 @@
// "WriterMutexLock mu(lock)".
#define WriterMutexLock(x) COMPILE_ASSERT(0, writer_mutex_lock_declaration_missing_variable_name)
-// Scoped unlocker/locker for a ReaderWriterMutex that releases read access to mu upon
-// construction and acquires it again upon destruction.
-class ReaderMutexUnlock {
- public:
- explicit ReaderMutexUnlock(ReaderWriterMutex& mu) UNLOCK_FUNCTION(mu) : mu_(mu) {
- mu_.SharedUnlock();
- }
-
- ~ReaderMutexUnlock() SHARED_LOCK_FUNCTION(mu_) {
- mu_.SharedLock();
- }
-
- private:
- ReaderWriterMutex& mu_;
- DISALLOW_COPY_AND_ASSIGN(ReaderMutexUnlock);
-};
-// Catch bug where variable name is omitted. "ReaderMutexUnlock (lock);" instead of
-// "ReaderMutexUnlock mu(lock)".
-#define ReaderMutexUnlock(x) \
- COMPILE_ASSERT(0, reader_mutex_unlock_declaration_missing_variable_name)
-
} // namespace art
#endif // ART_SRC_MUTEX_H_