diff options
Diffstat (limited to 'runtime/base/mutex.cc')
| -rw-r--r-- | runtime/base/mutex.cc | 65 |
1 files changed, 60 insertions, 5 deletions
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc index cbcd408b6d..423ea77da9 100644 --- a/runtime/base/mutex.cc +++ b/runtime/base/mutex.cc @@ -19,8 +19,12 @@ #include <errno.h> #include <sys/time.h> +#define ATRACE_TAG ATRACE_TAG_DALVIK +#include "cutils/trace.h" + #include "atomic.h" #include "base/logging.h" +#include "base/value_object.h" #include "mutex-inl.h" #include "runtime.h" #include "scoped_thread_state_change.h" @@ -83,22 +87,59 @@ static bool ComputeRelativeTimeSpec(timespec* result_ts, const timespec& lhs, co } #endif -class ScopedAllMutexesLock { +class ScopedAllMutexesLock FINAL { public: explicit ScopedAllMutexesLock(const BaseMutex* mutex) : mutex_(mutex) { while (!gAllMutexData->all_mutexes_guard.CompareExchangeWeakAcquire(0, mutex)) { NanoSleep(100); } } + ~ScopedAllMutexesLock() { +#if !defined(__clang__) + // TODO: remove this workaround target GCC/libc++/bionic bug "invalid failure memory model". + while (!gAllMutexData->all_mutexes_guard.CompareExchangeWeakSequentiallyConsistent(mutex_, 0)) { +#else while (!gAllMutexData->all_mutexes_guard.CompareExchangeWeakRelease(mutex_, 0)) { +#endif NanoSleep(100); } } + private: const BaseMutex* const mutex_; }; +// Scoped class that generates events at the beginning and end of lock contention. +class ScopedContentionRecorder FINAL : public ValueObject { + public: + ScopedContentionRecorder(BaseMutex* mutex, uint64_t blocked_tid, uint64_t owner_tid) + : mutex_(kLogLockContentions ? mutex : NULL), + blocked_tid_(kLogLockContentions ? blocked_tid : 0), + owner_tid_(kLogLockContentions ? owner_tid : 0), + start_nano_time_(kLogLockContentions ? NanoTime() : 0) { + if (ATRACE_ENABLED()) { + std::string msg = StringPrintf("Lock contention on %s (owner tid: %" PRIu64 ")", + mutex->GetName(), owner_tid); + ATRACE_BEGIN(msg.c_str()); + } + } + + ~ScopedContentionRecorder() { + ATRACE_END(); + if (kLogLockContentions) { + uint64_t end_nano_time = NanoTime(); + mutex_->RecordContention(blocked_tid_, owner_tid_, end_nano_time - start_nano_time_); + } + } + + private: + BaseMutex* const mutex_; + const uint64_t blocked_tid_; + const uint64_t owner_tid_; + const uint64_t start_nano_time_; +}; + BaseMutex::BaseMutex(const char* name, LockLevel level) : level_(level), name_(name) { if (kLogLockContentions) { ScopedAllMutexesLock mu(this); @@ -421,9 +462,9 @@ void Mutex::ExclusiveUnlock(Thread* self) { if (this != Locks::logging_lock_) { LOG(FATAL) << "Unexpected state_ in unlock " << cur_state << " for " << name_; } else { - LogMessageData data(__FILE__, __LINE__, INTERNAL_FATAL, -1); - LogMessage::LogLine(data, StringPrintf("Unexpected state_ %d in unlock for %s", - cur_state, name_).c_str()); + LogMessage::LogLine(__FILE__, __LINE__, INTERNAL_FATAL, + StringPrintf("Unexpected state_ %d in unlock for %s", + cur_state, name_).c_str()); _exit(1); } } @@ -605,6 +646,20 @@ bool ReaderWriterMutex::ExclusiveLockWithTimeout(Thread* self, int64_t ms, int32 } #endif +#if ART_USE_FUTEXES +void ReaderWriterMutex::HandleSharedLockContention(Thread* self, int32_t cur_state) { + // Owner holds it exclusively, hang up. + ScopedContentionRecorder scr(this, GetExclusiveOwnerTid(), SafeGetTid(self)); + ++num_pending_readers_; + if (futex(state_.Address(), FUTEX_WAIT, cur_state, NULL, NULL, 0) != 0) { + if (errno != EAGAIN) { + PLOG(FATAL) << "futex wait failed for " << name_; + } + } + --num_pending_readers_; +} +#endif + bool ReaderWriterMutex::SharedTryLock(Thread* self) { DCHECK(self == NULL || self == Thread::Current()); #if ART_USE_FUTEXES @@ -673,7 +728,7 @@ ConditionVariable::ConditionVariable(const char* name, Mutex& guard) CHECK_MUTEX_CALL(pthread_condattr_init, (&cond_attrs)); #if !defined(__APPLE__) // Apple doesn't have CLOCK_MONOTONIC or pthread_condattr_setclock. - CHECK_MUTEX_CALL(pthread_condattr_setclock(&cond_attrs, CLOCK_MONOTONIC)); + CHECK_MUTEX_CALL(pthread_condattr_setclock, (&cond_attrs, CLOCK_MONOTONIC)); #endif CHECK_MUTEX_CALL(pthread_cond_init, (&cond_, &cond_attrs)); #endif |