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