blob: 122fad507ee27e5279f825ea231731dcafa16f80 [file] [log] [blame]
Ian Rogers693ff612013-02-01 10:56:12 -08001/*
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_SRC_BASE_MUTEX_INL_H_
18#define ART_SRC_BASE_MUTEX_INL_H_
19
20#include "mutex.h"
21
22#include "cutils/atomic-inline.h"
23#include "runtime.h"
24#include "thread.h"
25
26namespace art {
27
28#define CHECK_MUTEX_CALL(call, args) CHECK_PTHREAD_CALL(call, args, name_)
29
30#if ART_USE_FUTEXES
31#include "linux/futex.h"
32#include "sys/syscall.h"
33#ifndef SYS_futex
34#define SYS_futex __NR_futex
35#endif
36static inline int futex(volatile int *uaddr, int op, int val, const struct timespec *timeout, volatile int *uaddr2, int val3) {
37 return syscall(SYS_futex, uaddr, op, val, timeout, uaddr2, val3);
38}
39#endif // ART_USE_FUTEXES
40
41class ScopedContentionRecorder {
42 public:
43 ScopedContentionRecorder(BaseMutex* mutex, uint64_t blocked_tid, uint64_t owner_tid) :
44 mutex_(mutex), blocked_tid_(blocked_tid), owner_tid_(owner_tid),
45 start_milli_time_(MilliTime()) {
46 }
47
48 ~ScopedContentionRecorder() {
49 uint64_t end_milli_time = MilliTime();
50 mutex_->RecordContention(blocked_tid_, owner_tid_, end_milli_time - start_milli_time_);
51 }
52
53 private:
54 BaseMutex* const mutex_;
55 uint64_t blocked_tid_;
56 uint64_t owner_tid_;
57 const uint64_t start_milli_time_;
58};
59
60static inline uint64_t SafeGetTid(const Thread* self) {
61 if (self != NULL) {
62 return static_cast<uint64_t>(self->GetTid());
63 } else {
64 return static_cast<uint64_t>(GetTid());
65 }
66}
67
68static inline void CheckUnattachedThread(LockLevel level) NO_THREAD_SAFETY_ANALYSIS {
69 // The check below enumerates the cases where we expect not to be able to sanity check locks
70 // on a thread. Lock checking is disabled to avoid deadlock when checking shutdown lock.
71 // TODO: tighten this check.
72 if (kDebugLocking) {
73 Runtime* runtime = Runtime::Current();
74 CHECK(runtime == NULL || !runtime->IsStarted() || runtime->IsShuttingDown() ||
75 level == kDefaultMutexLevel || level == kRuntimeShutdownLock ||
76 level == kThreadListLock || level == kLoggingLock || level == kAbortLock);
77 }
78}
79
Ian Rogersb6c31ea2013-02-04 18:11:33 -080080inline void BaseMutex::RegisterAsLocked(Thread* self) {
81 if (UNLIKELY(self == NULL)) {
82 CheckUnattachedThread(level_);
83 return;
84 }
85 if (kDebugLocking) {
86 // Check if a bad Mutex of this level or lower is held.
87 bool bad_mutexes_held = false;
88 for (int i = level_; i >= 0; --i) {
89 BaseMutex* held_mutex = self->GetHeldMutex(static_cast<LockLevel>(i));
90 if (UNLIKELY(held_mutex != NULL)) {
91 LOG(ERROR) << "Lock level violation: holding \"" << held_mutex->name_ << "\" (level " << i
92 << ") while locking \"" << name_ << "\" (level " << static_cast<int>(level_) << ")";
93 if (i > kAbortLock) {
94 // Only abort in the check below if this is more than abort level lock.
95 bad_mutexes_held = true;
96 }
97 }
98 }
99 CHECK(!bad_mutexes_held);
100 }
101 // Don't record monitors as they are outside the scope of analysis. They may be inspected off of
102 // the monitor list.
103 if (level_ != kMonitorLock) {
104 self->SetHeldMutex(level_, this);
105 }
106}
107
Ian Rogers693ff612013-02-01 10:56:12 -0800108inline void BaseMutex::RegisterAsUnlocked(Thread* self) {
109 if (UNLIKELY(self == NULL)) {
110 CheckUnattachedThread(level_);
111 return;
112 }
113 if (level_ != kMonitorLock) {
114 if (kDebugLocking && !gAborting) {
115 CHECK(self->GetHeldMutex(level_) == this) << "Unlocking on unacquired mutex: " << name_;
116 }
117 self->SetHeldMutex(level_, NULL);
118 }
119}
120
121inline void ReaderWriterMutex::SharedLock(Thread* self) {
122 DCHECK(self == NULL || self == Thread::Current());
123#if ART_USE_FUTEXES
124 bool done = false;
125 do {
126 int32_t cur_state = state_;
127 if (cur_state >= 0) {
128 // Add as an extra reader.
129 done = android_atomic_acquire_cas(cur_state, cur_state + 1, &state_) == 0;
130 } else {
131 // Owner holds it exclusively, hang up.
132 ScopedContentionRecorder scr(this, GetExclusiveOwnerTid(), SafeGetTid(self));
133 android_atomic_inc(&num_pending_readers_);
134 if (futex(&state_, FUTEX_WAIT, cur_state, NULL, NULL, 0) != 0) {
135 if (errno != EAGAIN) {
136 PLOG(FATAL) << "futex wait failed for " << name_;
137 }
138 }
139 android_atomic_dec(&num_pending_readers_);
140 }
141 } while(!done);
142#else
143 CHECK_MUTEX_CALL(pthread_rwlock_rdlock, (&rwlock_));
144#endif
145 RegisterAsLocked(self);
146 AssertSharedHeld(self);
147}
148
149inline void ReaderWriterMutex::SharedUnlock(Thread* self) {
150 DCHECK(self == NULL || self == Thread::Current());
151 AssertSharedHeld(self);
152 RegisterAsUnlocked(self);
153#if ART_USE_FUTEXES
154 bool done = false;
155 do {
156 int32_t cur_state = state_;
157 if (LIKELY(cur_state > 0)) {
158 // Reduce state by 1.
159 done = android_atomic_release_cas(cur_state, cur_state - 1, &state_) == 0;
160 if (done && (cur_state - 1) == 0) { // cas may fail due to noise?
161 if (num_pending_writers_ > 0 || num_pending_readers_ > 0) {
162 // Wake any exclusive waiters as there are now no readers.
163 futex(&state_, FUTEX_WAKE, -1, NULL, NULL, 0);
164 }
165 }
166 } else {
167 LOG(FATAL) << "Unexpected state_:" << cur_state << " for " << name_;
168 }
169 } while(!done);
170#else
171 CHECK_MUTEX_CALL(pthread_rwlock_unlock, (&rwlock_));
172#endif
173}
174
175} // namespace art
176
177#endif // ART_SRC_BASE_MUTEX_INL_H_