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 <inttypes.h>
     21 
     22 #include "mutex.h"
     23 
     24 #include "base/value_object.h"
     25 #include "thread.h"
     26 #include "utils.h"
     27 
     28 #if ART_USE_FUTEXES
     29 #include "linux/futex.h"
     30 #include "sys/syscall.h"
     31 #ifndef SYS_futex
     32 #define SYS_futex __NR_futex
     33 #endif
     34 #endif  // ART_USE_FUTEXES
     35 
     36 #define CHECK_MUTEX_CALL(call, args) CHECK_PTHREAD_CALL(call, args, name_)
     37 
     38 namespace art {
     39 
     40 #if ART_USE_FUTEXES
     41 static inline int futex(volatile int *uaddr, int op, int val, const struct timespec *timeout,
     42                         volatile int *uaddr2, int val3) {
     43   return syscall(SYS_futex, uaddr, op, val, timeout, uaddr2, val3);
     44 }
     45 #endif  // ART_USE_FUTEXES
     46 
     47 static inline uint64_t SafeGetTid(const Thread* self) {
     48   if (self != nullptr) {
     49     return static_cast<uint64_t>(self->GetTid());
     50   } else {
     51     return static_cast<uint64_t>(GetTid());
     52   }
     53 }
     54 
     55 static inline void CheckUnattachedThread(LockLevel level) NO_THREAD_SAFETY_ANALYSIS {
     56   // The check below enumerates the cases where we expect not to be able to sanity check locks
     57   // on a thread. Lock checking is disabled to avoid deadlock when checking shutdown lock.
     58   // TODO: tighten this check.
     59   if (kDebugLocking) {
     60     CHECK(!Locks::IsSafeToCallAbortRacy() ||
     61           // Used during thread creation to avoid races with runtime shutdown. Thread::Current not
     62           // yet established.
     63           level == kRuntimeShutdownLock ||
     64           // Thread Ids are allocated/released before threads are established.
     65           level == kAllocatedThreadIdsLock ||
     66           // Thread LDT's are initialized without Thread::Current established.
     67           level == kModifyLdtLock ||
     68           // Threads are unregistered while holding the thread list lock, during this process they
     69           // no longer exist and so we expect an unlock with no self.
     70           level == kThreadListLock ||
     71           // Ignore logging which may or may not have set up thread data structures.
     72           level == kLoggingLock ||
     73           // When transitioning from suspended to runnable, a daemon thread might be in
     74           // a situation where the runtime is shutting down. To not crash our debug locking
     75           // mechanism we just pass null Thread* to the MutexLock during that transition
     76           // (see Thread::TransitionFromSuspendedToRunnable).
     77           level == kThreadSuspendCountLock ||
     78           // Avoid recursive death.
     79           level == kAbortLock) << level;
     80   }
     81 }
     82 
     83 inline void BaseMutex::RegisterAsLocked(Thread* self) {
     84   if (UNLIKELY(self == nullptr)) {
     85     CheckUnattachedThread(level_);
     86     return;
     87   }
     88   if (kDebugLocking) {
     89     // Check if a bad Mutex of this level or lower is held.
     90     bool bad_mutexes_held = false;
     91     for (int i = level_; i >= 0; --i) {
     92       LockLevel lock_level_i = static_cast<LockLevel>(i);
     93       BaseMutex* held_mutex = self->GetHeldMutex(lock_level_i);
     94       if (UNLIKELY(held_mutex != nullptr) && lock_level_i != kAbortLock) {
     95         LOG(ERROR) << "Lock level violation: holding \"" << held_mutex->name_ << "\" "
     96                    << "(level " << lock_level_i << " - " << i
     97                    << ") while locking \"" << name_ << "\" "
     98                    << "(level " << level_ << " - " << static_cast<int>(level_) << ")";
     99         if (lock_level_i > kAbortLock) {
    100           // Only abort in the check below if this is more than abort level lock.
    101           bad_mutexes_held = true;
    102         }
    103       }
    104     }
    105     if (gAborting == 0) {  // Avoid recursive aborts.
    106       CHECK(!bad_mutexes_held);
    107     }
    108   }
    109   // Don't record monitors as they are outside the scope of analysis. They may be inspected off of
    110   // the monitor list.
    111   if (level_ != kMonitorLock) {
    112     self->SetHeldMutex(level_, this);
    113   }
    114 }
    115 
    116 inline void BaseMutex::RegisterAsUnlocked(Thread* self) {
    117   if (UNLIKELY(self == nullptr)) {
    118     CheckUnattachedThread(level_);
    119     return;
    120   }
    121   if (level_ != kMonitorLock) {
    122     if (kDebugLocking && gAborting == 0) {  // Avoid recursive aborts.
    123       CHECK(self->GetHeldMutex(level_) == this) << "Unlocking on unacquired mutex: " << name_;
    124     }
    125     self->SetHeldMutex(level_, nullptr);
    126   }
    127 }
    128 
    129 inline void ReaderWriterMutex::SharedLock(Thread* self) {
    130   DCHECK(self == nullptr || self == Thread::Current());
    131 #if ART_USE_FUTEXES
    132   bool done = false;
    133   do {
    134     int32_t cur_state = state_.LoadRelaxed();
    135     if (LIKELY(cur_state >= 0)) {
    136       // Add as an extra reader.
    137       done = state_.CompareExchangeWeakAcquire(cur_state, cur_state + 1);
    138     } else {
    139       HandleSharedLockContention(self, cur_state);
    140     }
    141   } while (!done);
    142 #else
    143   CHECK_MUTEX_CALL(pthread_rwlock_rdlock, (&rwlock_));
    144 #endif
    145   DCHECK(exclusive_owner_ == 0U || exclusive_owner_ == -1U);
    146   RegisterAsLocked(self);
    147   AssertSharedHeld(self);
    148 }
    149 
    150 inline void ReaderWriterMutex::SharedUnlock(Thread* self) {
    151   DCHECK(self == nullptr || self == Thread::Current());
    152   DCHECK(exclusive_owner_ == 0U || exclusive_owner_ == -1U);
    153   AssertSharedHeld(self);
    154   RegisterAsUnlocked(self);
    155 #if ART_USE_FUTEXES
    156   bool done = false;
    157   do {
    158     int32_t cur_state = state_.LoadRelaxed();
    159     if (LIKELY(cur_state > 0)) {
    160       // Reduce state by 1 and impose lock release load/store ordering.
    161       // Note, the relaxed loads below musn't reorder before the CompareExchange.
    162       // TODO: the ordering here is non-trivial as state is split across 3 fields, fix by placing
    163       // a status bit into the state on contention.
    164       done = state_.CompareExchangeWeakSequentiallyConsistent(cur_state, cur_state - 1);
    165       if (done && (cur_state - 1) == 0) {  // Weak CAS may fail spuriously.
    166         if (num_pending_writers_.LoadRelaxed() > 0 ||
    167             num_pending_readers_.LoadRelaxed() > 0) {
    168           // Wake any exclusive waiters as there are now no readers.
    169           futex(state_.Address(), FUTEX_WAKE, -1, nullptr, nullptr, 0);
    170         }
    171       }
    172     } else {
    173       LOG(FATAL) << "Unexpected state_:" << cur_state << " for " << name_;
    174     }
    175   } while (!done);
    176 #else
    177   CHECK_MUTEX_CALL(pthread_rwlock_unlock, (&rwlock_));
    178 #endif
    179 }
    180 
    181 inline bool Mutex::IsExclusiveHeld(const Thread* self) const {
    182   DCHECK(self == nullptr || self == Thread::Current());
    183   bool result = (GetExclusiveOwnerTid() == SafeGetTid(self));
    184   if (kDebugLocking) {
    185     // Sanity debug check that if we think it is locked we have it in our held mutexes.
    186     if (result && self != nullptr && level_ != kMonitorLock && !gAborting) {
    187       CHECK_EQ(self->GetHeldMutex(level_), this);
    188     }
    189   }
    190   return result;
    191 }
    192 
    193 inline uint64_t Mutex::GetExclusiveOwnerTid() const {
    194   return exclusive_owner_;
    195 }
    196 
    197 inline bool ReaderWriterMutex::IsExclusiveHeld(const Thread* self) const {
    198   DCHECK(self == nullptr || self == Thread::Current());
    199   bool result = (GetExclusiveOwnerTid() == SafeGetTid(self));
    200   if (kDebugLocking) {
    201     // Sanity that if the pthread thinks we own the lock the Thread agrees.
    202     if (self != nullptr && result)  {
    203       CHECK_EQ(self->GetHeldMutex(level_), this);
    204     }
    205   }
    206   return result;
    207 }
    208 
    209 inline uint64_t ReaderWriterMutex::GetExclusiveOwnerTid() const {
    210 #if ART_USE_FUTEXES
    211   int32_t state = state_.LoadRelaxed();
    212   if (state == 0) {
    213     return 0;  // No owner.
    214   } else if (state > 0) {
    215     return -1;  // Shared.
    216   } else {
    217     return exclusive_owner_;
    218   }
    219 #else
    220   return exclusive_owner_;
    221 #endif
    222 }
    223 
    224 inline void MutatorMutex::TransitionFromRunnableToSuspended(Thread* self) {
    225   AssertSharedHeld(self);
    226   RegisterAsUnlocked(self);
    227 }
    228 
    229 inline void MutatorMutex::TransitionFromSuspendedToRunnable(Thread* self) {
    230   RegisterAsLocked(self);
    231   AssertSharedHeld(self);
    232 }
    233 
    234 }  // namespace art
    235 
    236 #endif  // ART_RUNTIME_BASE_MUTEX_INL_H_
    237