Home | History | Annotate | Download | only in base
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef ART_RUNTIME_BASE_MUTEX_INL_H_
     18 #define ART_RUNTIME_BASE_MUTEX_INL_H_
     19 
     20 #include "mutex.h"
     21 
     22 #define ATRACE_TAG ATRACE_TAG_DALVIK
     23 
     24 #include "cutils/atomic-inline.h"
     25 #include "cutils/trace.h"
     26 #include "runtime.h"
     27 #include "thread.h"
     28 
     29 namespace art {
     30 
     31 #define CHECK_MUTEX_CALL(call, args) CHECK_PTHREAD_CALL(call, args, name_)
     32 
     33 #if ART_USE_FUTEXES
     34 #include "linux/futex.h"
     35 #include "sys/syscall.h"
     36 #ifndef SYS_futex
     37 #define SYS_futex __NR_futex
     38 #endif
     39 static inline int futex(volatile int *uaddr, int op, int val, const struct timespec *timeout, volatile int *uaddr2, int val3) {
     40   return syscall(SYS_futex, uaddr, op, val, timeout, uaddr2, val3);
     41 }
     42 #endif  // ART_USE_FUTEXES
     43 
     44 class ScopedContentionRecorder {
     45  public:
     46   ScopedContentionRecorder(BaseMutex* mutex, uint64_t blocked_tid, uint64_t owner_tid)
     47       : mutex_(kLogLockContentions ? mutex : NULL),
     48         blocked_tid_(kLogLockContentions ? blocked_tid : 0),
     49         owner_tid_(kLogLockContentions ? owner_tid : 0),
     50         start_nano_time_(kLogLockContentions ? NanoTime() : 0) {
     51     std::string msg = StringPrintf("Lock contention on %s (owner tid: %llu)",
     52                                    mutex->GetName(), owner_tid);
     53     ATRACE_BEGIN(msg.c_str());
     54   }
     55 
     56   ~ScopedContentionRecorder() {
     57     ATRACE_END();
     58     if (kLogLockContentions) {
     59       uint64_t end_nano_time = NanoTime();
     60       mutex_->RecordContention(blocked_tid_, owner_tid_, end_nano_time - start_nano_time_);
     61     }
     62   }
     63 
     64  private:
     65   BaseMutex* const mutex_;
     66   const uint64_t blocked_tid_;
     67   const uint64_t owner_tid_;
     68   const uint64_t start_nano_time_;
     69 };
     70 
     71 static inline uint64_t SafeGetTid(const Thread* self) {
     72   if (self != NULL) {
     73     return static_cast<uint64_t>(self->GetTid());
     74   } else {
     75     return static_cast<uint64_t>(GetTid());
     76   }
     77 }
     78 
     79 static inline void CheckUnattachedThread(LockLevel level) NO_THREAD_SAFETY_ANALYSIS {
     80   // The check below enumerates the cases where we expect not to be able to sanity check locks
     81   // on a thread. Lock checking is disabled to avoid deadlock when checking shutdown lock.
     82   // TODO: tighten this check.
     83   if (kDebugLocking) {
     84     Runtime* runtime = Runtime::Current();
     85     CHECK(runtime == NULL || !runtime->IsStarted() || runtime->IsShuttingDown() ||
     86           level == kDefaultMutexLevel  || level == kRuntimeShutdownLock ||
     87           level == kThreadListLock || level == kLoggingLock || level == kAbortLock);
     88   }
     89 }
     90 
     91 inline void BaseMutex::RegisterAsLocked(Thread* self) {
     92   if (UNLIKELY(self == NULL)) {
     93     CheckUnattachedThread(level_);
     94     return;
     95   }
     96   if (kDebugLocking) {
     97     // Check if a bad Mutex of this level or lower is held.
     98     bool bad_mutexes_held = false;
     99     for (int i = level_; i >= 0; --i) {
    100       BaseMutex* held_mutex = self->GetHeldMutex(static_cast<LockLevel>(i));
    101       if (UNLIKELY(held_mutex != NULL)) {
    102         LOG(ERROR) << "Lock level violation: holding \"" << held_mutex->name_ << "\" "
    103                    << "(level " << LockLevel(i) << " - " << i
    104                    << ") while locking \"" << name_ << "\" "
    105                    << "(level " << level_ << " - " << static_cast<int>(level_) << ")";
    106         if (i > kAbortLock) {
    107           // Only abort in the check below if this is more than abort level lock.
    108           bad_mutexes_held = true;
    109         }
    110       }
    111     }
    112     CHECK(!bad_mutexes_held);
    113   }
    114   // Don't record monitors as they are outside the scope of analysis. They may be inspected off of
    115   // the monitor list.
    116   if (level_ != kMonitorLock) {
    117     self->SetHeldMutex(level_, this);
    118   }
    119 }
    120 
    121 inline void BaseMutex::RegisterAsUnlocked(Thread* self) {
    122   if (UNLIKELY(self == NULL)) {
    123     CheckUnattachedThread(level_);
    124     return;
    125   }
    126   if (level_ != kMonitorLock) {
    127     if (kDebugLocking && !gAborting) {
    128       CHECK(self->GetHeldMutex(level_) == this) << "Unlocking on unacquired mutex: " << name_;
    129     }
    130     self->SetHeldMutex(level_, NULL);
    131   }
    132 }
    133 
    134 inline void ReaderWriterMutex::SharedLock(Thread* self) {
    135   DCHECK(self == NULL || self == Thread::Current());
    136 #if ART_USE_FUTEXES
    137   bool done = false;
    138   do {
    139     int32_t cur_state = state_;
    140     if (LIKELY(cur_state >= 0)) {
    141       // Add as an extra reader.
    142       done = android_atomic_acquire_cas(cur_state, cur_state + 1, &state_) == 0;
    143     } else {
    144       // Owner holds it exclusively, hang up.
    145       ScopedContentionRecorder scr(this, GetExclusiveOwnerTid(), SafeGetTid(self));
    146       android_atomic_inc(&num_pending_readers_);
    147       if (futex(&state_, FUTEX_WAIT, cur_state, NULL, NULL, 0) != 0) {
    148         if (errno != EAGAIN) {
    149           PLOG(FATAL) << "futex wait failed for " << name_;
    150         }
    151       }
    152       android_atomic_dec(&num_pending_readers_);
    153     }
    154   } while (!done);
    155 #else
    156   CHECK_MUTEX_CALL(pthread_rwlock_rdlock, (&rwlock_));
    157 #endif
    158   RegisterAsLocked(self);
    159   AssertSharedHeld(self);
    160 }
    161 
    162 inline void ReaderWriterMutex::SharedUnlock(Thread* self) {
    163   DCHECK(self == NULL || self == Thread::Current());
    164   AssertSharedHeld(self);
    165   RegisterAsUnlocked(self);
    166 #if ART_USE_FUTEXES
    167   bool done = false;
    168   do {
    169     int32_t cur_state = state_;
    170     if (LIKELY(cur_state > 0)) {
    171       // Reduce state by 1.
    172       done = android_atomic_release_cas(cur_state, cur_state - 1, &state_) == 0;
    173       if (done && (cur_state - 1) == 0) {  // cas may fail due to noise?
    174         if (num_pending_writers_ > 0 || num_pending_readers_ > 0) {
    175           // Wake any exclusive waiters as there are now no readers.
    176           futex(&state_, FUTEX_WAKE, -1, NULL, NULL, 0);
    177         }
    178       }
    179     } else {
    180       LOG(FATAL) << "Unexpected state_:" << cur_state << " for " << name_;
    181     }
    182   } while (!done);
    183 #else
    184   CHECK_MUTEX_CALL(pthread_rwlock_unlock, (&rwlock_));
    185 #endif
    186 }
    187 
    188 }  // namespace art
    189 
    190 #endif  // ART_RUNTIME_BASE_MUTEX_INL_H_
    191