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