mutex.cc revision d9c4fc94fa618617f94e1de9af5f034549100753
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#include "mutex.h" 18 19#include <errno.h> 20#include <sys/time.h> 21 22#include "atomic.h" 23#include "base/logging.h" 24#include "cutils/atomic.h" 25#include "cutils/atomic-inline.h" 26#include "mutex-inl.h" 27#include "runtime.h" 28#include "scoped_thread_state_change.h" 29#include "thread-inl.h" 30#include "utils.h" 31 32namespace art { 33 34#if ART_USE_FUTEXES 35static bool ComputeRelativeTimeSpec(timespec* result_ts, const timespec& lhs, const timespec& rhs) { 36 const int32_t one_sec = 1000 * 1000 * 1000; // one second in nanoseconds. 37 result_ts->tv_sec = lhs.tv_sec - rhs.tv_sec; 38 result_ts->tv_nsec = lhs.tv_nsec - rhs.tv_nsec; 39 if (result_ts->tv_nsec < 0) { 40 result_ts->tv_sec--; 41 result_ts->tv_nsec += one_sec; 42 } else if (result_ts->tv_nsec > one_sec) { 43 result_ts->tv_sec++; 44 result_ts->tv_nsec -= one_sec; 45 } 46 return result_ts->tv_sec < 0; 47} 48#endif 49 50struct AllMutexData { 51 // A guard for all_mutexes_ that's not a mutex (Mutexes must CAS to acquire and busy wait). 52 AtomicInteger all_mutexes_guard; 53 // All created mutexes guarded by all_mutexes_guard_. 54 std::set<BaseMutex*>* all_mutexes; 55 AllMutexData() : all_mutexes(NULL) {} 56}; 57static struct AllMutexData gAllMutexData[kAllMutexDataSize]; 58 59class ScopedAllMutexesLock { 60 public: 61 explicit ScopedAllMutexesLock(const BaseMutex* mutex) : mutex_(mutex) { 62 while (!gAllMutexData->all_mutexes_guard.compare_and_swap(0, reinterpret_cast<int32_t>(mutex))) { 63 NanoSleep(100); 64 } 65 } 66 ~ScopedAllMutexesLock() { 67 while (!gAllMutexData->all_mutexes_guard.compare_and_swap(reinterpret_cast<int32_t>(mutex_), 0)) { 68 NanoSleep(100); 69 } 70 } 71 private: 72 const BaseMutex* const mutex_; 73}; 74 75BaseMutex::BaseMutex(const char* name, LockLevel level) : level_(level), name_(name) { 76 if (kLogLockContentions) { 77 ScopedAllMutexesLock mu(this); 78 std::set<BaseMutex*>** all_mutexes_ptr = &gAllMutexData->all_mutexes; 79 if (*all_mutexes_ptr == NULL) { 80 // We leak the global set of all mutexes to avoid ordering issues in global variable 81 // construction/destruction. 82 *all_mutexes_ptr = new std::set<BaseMutex*>(); 83 } 84 (*all_mutexes_ptr)->insert(this); 85 } 86} 87 88BaseMutex::~BaseMutex() { 89 if (kLogLockContentions) { 90 ScopedAllMutexesLock mu(this); 91 gAllMutexData->all_mutexes->erase(this); 92 } 93} 94 95void BaseMutex::DumpAll(std::ostream& os) { 96 if (kLogLockContentions) { 97 os << "Mutex logging:\n"; 98 ScopedAllMutexesLock mu(reinterpret_cast<const BaseMutex*>(-1)); 99 std::set<BaseMutex*>* all_mutexes = gAllMutexData->all_mutexes; 100 if (all_mutexes == NULL) { 101 // No mutexes have been created yet during at startup. 102 return; 103 } 104 typedef std::set<BaseMutex*>::const_iterator It; 105 os << "(Contended)\n"; 106 for (It it = all_mutexes->begin(); it != all_mutexes->end(); ++it) { 107 BaseMutex* mutex = *it; 108 if (mutex->HasEverContended()) { 109 mutex->Dump(os); 110 os << "\n"; 111 } 112 } 113 os << "(Never contented)\n"; 114 for (It it = all_mutexes->begin(); it != all_mutexes->end(); ++it) { 115 BaseMutex* mutex = *it; 116 if (!mutex->HasEverContended()) { 117 mutex->Dump(os); 118 os << "\n"; 119 } 120 } 121 } 122} 123 124void BaseMutex::CheckSafeToWait(Thread* self) { 125 if (self == NULL) { 126 CheckUnattachedThread(level_); 127 return; 128 } 129 if (kDebugLocking) { 130 CHECK(self->GetHeldMutex(level_) == this || level_ == kMonitorLock) 131 << "Waiting on unacquired mutex: " << name_; 132 bool bad_mutexes_held = false; 133 for (int i = kLockLevelCount - 1; i >= 0; --i) { 134 if (i != level_) { 135 BaseMutex* held_mutex = self->GetHeldMutex(static_cast<LockLevel>(i)); 136 if (held_mutex != NULL) { 137 LOG(ERROR) << "Holding \"" << held_mutex->name_ << "\" " 138 << "(level " << LockLevel(i) << ") while performing wait on " 139 << "\"" << name_ << "\" (level " << level_ << ")"; 140 bad_mutexes_held = true; 141 } 142 } 143 } 144 CHECK(!bad_mutexes_held); 145 } 146} 147 148inline void BaseMutex::ContentionLogData::AddToWaitTime(uint64_t value) { 149 if (kLogLockContentions) { 150 // Atomically add value to wait_time. 151 uint64_t new_val, old_val; 152 volatile int64_t* addr = reinterpret_cast<volatile int64_t*>(&wait_time); 153 volatile const int64_t* caddr = const_cast<volatile const int64_t*>(addr); 154 do { 155 old_val = static_cast<uint64_t>(QuasiAtomic::Read64(caddr)); 156 new_val = old_val + value; 157 } while (!QuasiAtomic::Cas64(static_cast<int64_t>(old_val), static_cast<int64_t>(new_val), addr)); 158 } 159} 160 161void BaseMutex::RecordContention(uint64_t blocked_tid, 162 uint64_t owner_tid, 163 uint64_t nano_time_blocked) { 164 if (kLogLockContentions) { 165 ContentionLogData* data = contetion_log_data_; 166 ++(data->contention_count); 167 data->AddToWaitTime(nano_time_blocked); 168 ContentionLogEntry* log = data->contention_log; 169 // This code is intentionally racy as it is only used for diagnostics. 170 uint32_t slot = data->cur_content_log_entry; 171 if (log[slot].blocked_tid == blocked_tid && 172 log[slot].owner_tid == blocked_tid) { 173 ++log[slot].count; 174 } else { 175 uint32_t new_slot; 176 do { 177 slot = data->cur_content_log_entry; 178 new_slot = (slot + 1) % kContentionLogSize; 179 } while (!data->cur_content_log_entry.compare_and_swap(slot, new_slot)); 180 log[new_slot].blocked_tid = blocked_tid; 181 log[new_slot].owner_tid = owner_tid; 182 log[new_slot].count = 1; 183 } 184 } 185} 186 187void BaseMutex::DumpContention(std::ostream& os) const { 188 if (kLogLockContentions) { 189 const ContentionLogData* data = contetion_log_data_; 190 const ContentionLogEntry* log = data->contention_log; 191 uint64_t wait_time = data->wait_time; 192 uint32_t contention_count = data->contention_count; 193 if (contention_count == 0) { 194 os << "never contended"; 195 } else { 196 os << "contended " << contention_count 197 << " times, average wait of contender " << PrettyDuration(wait_time / contention_count); 198 SafeMap<uint64_t, size_t> most_common_blocker; 199 SafeMap<uint64_t, size_t> most_common_blocked; 200 typedef SafeMap<uint64_t, size_t>::const_iterator It; 201 for (size_t i = 0; i < kContentionLogSize; ++i) { 202 uint64_t blocked_tid = log[i].blocked_tid; 203 uint64_t owner_tid = log[i].owner_tid; 204 uint32_t count = log[i].count; 205 if (count > 0) { 206 It it = most_common_blocked.find(blocked_tid); 207 if (it != most_common_blocked.end()) { 208 most_common_blocked.Overwrite(blocked_tid, it->second + count); 209 } else { 210 most_common_blocked.Put(blocked_tid, count); 211 } 212 it = most_common_blocker.find(owner_tid); 213 if (it != most_common_blocker.end()) { 214 most_common_blocker.Overwrite(owner_tid, it->second + count); 215 } else { 216 most_common_blocker.Put(owner_tid, count); 217 } 218 } 219 } 220 uint64_t max_tid = 0; 221 size_t max_tid_count = 0; 222 for (It it = most_common_blocked.begin(); it != most_common_blocked.end(); ++it) { 223 if (it->second > max_tid_count) { 224 max_tid = it->first; 225 max_tid_count = it->second; 226 } 227 } 228 if (max_tid != 0) { 229 os << " sample shows most blocked tid=" << max_tid; 230 } 231 max_tid = 0; 232 max_tid_count = 0; 233 for (It it = most_common_blocker.begin(); it != most_common_blocker.end(); ++it) { 234 if (it->second > max_tid_count) { 235 max_tid = it->first; 236 max_tid_count = it->second; 237 } 238 } 239 if (max_tid != 0) { 240 os << " sample shows tid=" << max_tid << " owning during this time"; 241 } 242 } 243 } 244} 245 246 247Mutex::Mutex(const char* name, LockLevel level, bool recursive) 248 : BaseMutex(name, level), recursive_(recursive), recursion_count_(0) { 249#if ART_USE_FUTEXES 250 state_ = 0; 251 exclusive_owner_ = 0; 252 num_contenders_ = 0; 253#elif defined(__BIONIC__) || defined(__APPLE__) 254 // Use recursive mutexes for bionic and Apple otherwise the 255 // non-recursive mutexes don't have TIDs to check lock ownership of. 256 pthread_mutexattr_t attributes; 257 CHECK_MUTEX_CALL(pthread_mutexattr_init, (&attributes)); 258 CHECK_MUTEX_CALL(pthread_mutexattr_settype, (&attributes, PTHREAD_MUTEX_RECURSIVE)); 259 CHECK_MUTEX_CALL(pthread_mutex_init, (&mutex_, &attributes)); 260 CHECK_MUTEX_CALL(pthread_mutexattr_destroy, (&attributes)); 261#else 262 CHECK_MUTEX_CALL(pthread_mutex_init, (&mutex_, NULL)); 263#endif 264} 265 266Mutex::~Mutex() { 267#if ART_USE_FUTEXES 268 if (state_ != 0) { 269 MutexLock mu(Thread::Current(), *Locks::runtime_shutdown_lock_); 270 Runtime* runtime = Runtime::Current(); 271 bool shutting_down = (runtime == NULL) || runtime->IsShuttingDown(); 272 LOG(shutting_down ? WARNING : FATAL) << "destroying mutex with owner: " << exclusive_owner_; 273 } else { 274 CHECK_EQ(exclusive_owner_, 0U) << "unexpectedly found an owner on unlocked mutex " << name_; 275 CHECK_EQ(num_contenders_, 0) << "unexpectedly found a contender on mutex " << name_; 276 } 277#else 278 // We can't use CHECK_MUTEX_CALL here because on shutdown a suspended daemon thread 279 // may still be using locks. 280 int rc = pthread_mutex_destroy(&mutex_); 281 if (rc != 0) { 282 errno = rc; 283 // TODO: should we just not log at all if shutting down? this could be the logging mutex! 284 MutexLock mu(Thread::Current(), *Locks::runtime_shutdown_lock_); 285 Runtime* runtime = Runtime::Current(); 286 bool shutting_down = (runtime == NULL) || runtime->IsShuttingDown(); 287 PLOG(shutting_down ? WARNING : FATAL) << "pthread_mutex_destroy failed for " << name_; 288 } 289#endif 290} 291 292void Mutex::ExclusiveLock(Thread* self) { 293 DCHECK(self == NULL || self == Thread::Current()); 294 if (kDebugLocking && !recursive_) { 295 AssertNotHeld(self); 296 } 297 if (!recursive_ || !IsExclusiveHeld(self)) { 298#if ART_USE_FUTEXES 299 bool done = false; 300 do { 301 int32_t cur_state = state_; 302 if (LIKELY(cur_state == 0)) { 303 // Change state from 0 to 1. 304 done = android_atomic_acquire_cas(0, 1, &state_) == 0; 305 } else { 306 // Failed to acquire, hang up. 307 ScopedContentionRecorder scr(this, SafeGetTid(self), GetExclusiveOwnerTid()); 308 android_atomic_inc(&num_contenders_); 309 if (futex(&state_, FUTEX_WAIT, 1, NULL, NULL, 0) != 0) { 310 // EAGAIN and EINTR both indicate a spurious failure, try again from the beginning. 311 // We don't use TEMP_FAILURE_RETRY so we can intentionally retry to acquire the lock. 312 if ((errno != EAGAIN) && (errno != EINTR)) { 313 PLOG(FATAL) << "futex wait failed for " << name_; 314 } 315 } 316 android_atomic_dec(&num_contenders_); 317 } 318 } while (!done); 319 DCHECK_EQ(state_, 1); 320 exclusive_owner_ = SafeGetTid(self); 321#else 322 CHECK_MUTEX_CALL(pthread_mutex_lock, (&mutex_)); 323#endif 324 RegisterAsLocked(self); 325 } 326 recursion_count_++; 327 if (kDebugLocking) { 328 CHECK(recursion_count_ == 1 || recursive_) << "Unexpected recursion count on mutex: " 329 << name_ << " " << recursion_count_; 330 AssertHeld(self); 331 } 332} 333 334bool Mutex::ExclusiveTryLock(Thread* self) { 335 DCHECK(self == NULL || self == Thread::Current()); 336 if (kDebugLocking && !recursive_) { 337 AssertNotHeld(self); 338 } 339 if (!recursive_ || !IsExclusiveHeld(self)) { 340#if ART_USE_FUTEXES 341 bool done = false; 342 do { 343 int32_t cur_state = state_; 344 if (cur_state == 0) { 345 // Change state from 0 to 1. 346 done = android_atomic_acquire_cas(0, 1, &state_) == 0; 347 } else { 348 return false; 349 } 350 } while (!done); 351 DCHECK_EQ(state_, 1); 352 exclusive_owner_ = SafeGetTid(self); 353#else 354 int result = pthread_mutex_trylock(&mutex_); 355 if (result == EBUSY) { 356 return false; 357 } 358 if (result != 0) { 359 errno = result; 360 PLOG(FATAL) << "pthread_mutex_trylock failed for " << name_; 361 } 362#endif 363 RegisterAsLocked(self); 364 } 365 recursion_count_++; 366 if (kDebugLocking) { 367 CHECK(recursion_count_ == 1 || recursive_) << "Unexpected recursion count on mutex: " 368 << name_ << " " << recursion_count_; 369 AssertHeld(self); 370 } 371 return true; 372} 373 374void Mutex::ExclusiveUnlock(Thread* self) { 375 DCHECK(self == NULL || self == Thread::Current()); 376 AssertHeld(self); 377 recursion_count_--; 378 if (!recursive_ || recursion_count_ == 0) { 379 if (kDebugLocking) { 380 CHECK(recursion_count_ == 0 || recursive_) << "Unexpected recursion count on mutex: " 381 << name_ << " " << recursion_count_; 382 } 383 RegisterAsUnlocked(self); 384#if ART_USE_FUTEXES 385 bool done = false; 386 do { 387 int32_t cur_state = state_; 388 if (LIKELY(cur_state == 1)) { 389 // We're no longer the owner. 390 exclusive_owner_ = 0; 391 // Change state to 0. 392 done = android_atomic_release_cas(cur_state, 0, &state_) == 0; 393 if (LIKELY(done)) { // Spurious fail? 394 // Wake a contender 395 if (UNLIKELY(num_contenders_ > 0)) { 396 futex(&state_, FUTEX_WAKE, 1, NULL, NULL, 0); 397 } 398 } 399 } else { 400 // Logging acquires the logging lock, avoid infinite recursion in that case. 401 if (this != Locks::logging_lock_) { 402 LOG(FATAL) << "Unexpected state_ in unlock " << cur_state << " for " << name_; 403 } else { 404 LogMessageData data(__FILE__, __LINE__, INTERNAL_FATAL, -1); 405 LogMessage::LogLine(data, StringPrintf("Unexpected state_ %d in unlock for %s", 406 cur_state, name_).c_str()); 407 _exit(1); 408 } 409 } 410 } while (!done); 411#else 412 CHECK_MUTEX_CALL(pthread_mutex_unlock, (&mutex_)); 413#endif 414 } 415} 416 417void Mutex::Dump(std::ostream& os) const { 418 os << (recursive_ ? "recursive " : "non-recursive ") 419 << name_ 420 << " level=" << static_cast<int>(level_) 421 << " rec=" << recursion_count_ 422 << " owner=" << GetExclusiveOwnerTid() << " "; 423 DumpContention(os); 424} 425 426std::ostream& operator<<(std::ostream& os, const Mutex& mu) { 427 mu.Dump(os); 428 return os; 429} 430 431ReaderWriterMutex::ReaderWriterMutex(const char* name, LockLevel level) 432 : BaseMutex(name, level) 433#if ART_USE_FUTEXES 434 , state_(0), exclusive_owner_(0), num_pending_readers_(0), num_pending_writers_(0) 435#endif 436{ // NOLINT(whitespace/braces) 437#if !ART_USE_FUTEXES 438 CHECK_MUTEX_CALL(pthread_rwlock_init, (&rwlock_, NULL)); 439#endif 440} 441 442ReaderWriterMutex::~ReaderWriterMutex() { 443#if ART_USE_FUTEXES 444 CHECK_EQ(state_, 0); 445 CHECK_EQ(exclusive_owner_, 0U); 446 CHECK_EQ(num_pending_readers_, 0); 447 CHECK_EQ(num_pending_writers_, 0); 448#else 449 // We can't use CHECK_MUTEX_CALL here because on shutdown a suspended daemon thread 450 // may still be using locks. 451 int rc = pthread_rwlock_destroy(&rwlock_); 452 if (rc != 0) { 453 errno = rc; 454 // TODO: should we just not log at all if shutting down? this could be the logging mutex! 455 MutexLock mu(Thread::Current(), *Locks::runtime_shutdown_lock_); 456 Runtime* runtime = Runtime::Current(); 457 bool shutting_down = runtime == NULL || runtime->IsShuttingDown(); 458 PLOG(shutting_down ? WARNING : FATAL) << "pthread_rwlock_destroy failed for " << name_; 459 } 460#endif 461} 462 463void ReaderWriterMutex::ExclusiveLock(Thread* self) { 464 DCHECK(self == NULL || self == Thread::Current()); 465 AssertNotExclusiveHeld(self); 466#if ART_USE_FUTEXES 467 bool done = false; 468 do { 469 int32_t cur_state = state_; 470 if (LIKELY(cur_state == 0)) { 471 // Change state from 0 to -1. 472 done = android_atomic_acquire_cas(0, -1, &state_) == 0; 473 } else { 474 // Failed to acquire, hang up. 475 ScopedContentionRecorder scr(this, SafeGetTid(self), GetExclusiveOwnerTid()); 476 android_atomic_inc(&num_pending_writers_); 477 if (futex(&state_, FUTEX_WAIT, cur_state, NULL, NULL, 0) != 0) { 478 // EAGAIN and EINTR both indicate a spurious failure, try again from the beginning. 479 // We don't use TEMP_FAILURE_RETRY so we can intentionally retry to acquire the lock. 480 if ((errno != EAGAIN) && (errno != EINTR)) { 481 PLOG(FATAL) << "futex wait failed for " << name_; 482 } 483 } 484 android_atomic_dec(&num_pending_writers_); 485 } 486 } while (!done); 487 DCHECK_EQ(state_, -1); 488 exclusive_owner_ = SafeGetTid(self); 489#else 490 CHECK_MUTEX_CALL(pthread_rwlock_wrlock, (&rwlock_)); 491#endif 492 RegisterAsLocked(self); 493 AssertExclusiveHeld(self); 494} 495 496void ReaderWriterMutex::ExclusiveUnlock(Thread* self) { 497 DCHECK(self == NULL || self == Thread::Current()); 498 AssertExclusiveHeld(self); 499 RegisterAsUnlocked(self); 500#if ART_USE_FUTEXES 501 bool done = false; 502 do { 503 int32_t cur_state = state_; 504 if (LIKELY(cur_state == -1)) { 505 // We're no longer the owner. 506 exclusive_owner_ = 0; 507 // Change state from -1 to 0. 508 done = android_atomic_release_cas(-1, 0, &state_) == 0; 509 if (LIKELY(done)) { // cmpxchg may fail due to noise? 510 // Wake any waiters. 511 if (UNLIKELY(num_pending_readers_ > 0 || num_pending_writers_ > 0)) { 512 futex(&state_, FUTEX_WAKE, -1, NULL, NULL, 0); 513 } 514 } 515 } else { 516 LOG(FATAL) << "Unexpected state_:" << cur_state << " for " << name_; 517 } 518 } while (!done); 519#else 520 CHECK_MUTEX_CALL(pthread_rwlock_unlock, (&rwlock_)); 521#endif 522} 523 524#if HAVE_TIMED_RWLOCK 525bool ReaderWriterMutex::ExclusiveLockWithTimeout(Thread* self, int64_t ms, int32_t ns) { 526 DCHECK(self == NULL || self == Thread::Current()); 527#if ART_USE_FUTEXES 528 bool done = false; 529 timespec end_abs_ts; 530 InitTimeSpec(true, CLOCK_REALTIME, ms, ns, &end_abs_ts); 531 do { 532 int32_t cur_state = state_; 533 if (cur_state == 0) { 534 // Change state from 0 to -1. 535 done = android_atomic_acquire_cas(0, -1, &state_) == 0; 536 } else { 537 // Failed to acquire, hang up. 538 timespec now_abs_ts; 539 InitTimeSpec(true, CLOCK_REALTIME, 0, 0, &now_abs_ts); 540 timespec rel_ts; 541 if (ComputeRelativeTimeSpec(&rel_ts, end_abs_ts, now_abs_ts)) { 542 return false; // Timed out. 543 } 544 ScopedContentionRecorder scr(this, SafeGetTid(self), GetExclusiveOwnerTid()); 545 android_atomic_inc(&num_pending_writers_); 546 if (futex(&state_, FUTEX_WAIT, cur_state, &rel_ts, NULL, 0) != 0) { 547 if (errno == ETIMEDOUT) { 548 android_atomic_dec(&num_pending_writers_); 549 return false; // Timed out. 550 } else if ((errno != EAGAIN) && (errno != EINTR)) { 551 // EAGAIN and EINTR both indicate a spurious failure, 552 // recompute the relative time out from now and try again. 553 // We don't use TEMP_FAILURE_RETRY so we can recompute rel_ts; 554 PLOG(FATAL) << "timed futex wait failed for " << name_; 555 } 556 } 557 android_atomic_dec(&num_pending_writers_); 558 } 559 } while (!done); 560 exclusive_owner_ = SafeGetTid(self); 561#else 562 timespec ts; 563 InitTimeSpec(true, CLOCK_REALTIME, ms, ns, &ts); 564 int result = pthread_rwlock_timedwrlock(&rwlock_, &ts); 565 if (result == ETIMEDOUT) { 566 return false; 567 } 568 if (result != 0) { 569 errno = result; 570 PLOG(FATAL) << "pthread_rwlock_timedwrlock failed for " << name_; 571 } 572#endif 573 RegisterAsLocked(self); 574 AssertSharedHeld(self); 575 return true; 576} 577#endif 578 579bool ReaderWriterMutex::SharedTryLock(Thread* self) { 580 DCHECK(self == NULL || self == Thread::Current()); 581#if ART_USE_FUTEXES 582 bool done = false; 583 do { 584 int32_t cur_state = state_; 585 if (cur_state >= 0) { 586 // Add as an extra reader. 587 done = android_atomic_acquire_cas(cur_state, cur_state + 1, &state_) == 0; 588 } else { 589 // Owner holds it exclusively. 590 return false; 591 } 592 } while (!done); 593#else 594 int result = pthread_rwlock_tryrdlock(&rwlock_); 595 if (result == EBUSY) { 596 return false; 597 } 598 if (result != 0) { 599 errno = result; 600 PLOG(FATAL) << "pthread_mutex_trylock failed for " << name_; 601 } 602#endif 603 RegisterAsLocked(self); 604 AssertSharedHeld(self); 605 return true; 606} 607 608bool ReaderWriterMutex::IsSharedHeld(const Thread* self) const { 609 DCHECK(self == NULL || self == Thread::Current()); 610 bool result; 611 if (UNLIKELY(self == NULL)) { // Handle unattached threads. 612 result = IsExclusiveHeld(self); // TODO: a better best effort here. 613 } else { 614 result = (self->GetHeldMutex(level_) == this); 615 } 616 return result; 617} 618 619void ReaderWriterMutex::Dump(std::ostream& os) const { 620 os << name_ 621 << " level=" << static_cast<int>(level_) 622 << " owner=" << GetExclusiveOwnerTid() << " "; 623 DumpContention(os); 624} 625 626std::ostream& operator<<(std::ostream& os, const ReaderWriterMutex& mu) { 627 mu.Dump(os); 628 return os; 629} 630 631ConditionVariable::ConditionVariable(const char* name, Mutex& guard) 632 : name_(name), guard_(guard) { 633#if ART_USE_FUTEXES 634 sequence_ = 0; 635 num_waiters_ = 0; 636#else 637 CHECK_MUTEX_CALL(pthread_cond_init, (&cond_, NULL)); 638#endif 639} 640 641ConditionVariable::~ConditionVariable() { 642#if ART_USE_FUTEXES 643 if (num_waiters_!= 0) { 644 MutexLock mu(Thread::Current(), *Locks::runtime_shutdown_lock_); 645 Runtime* runtime = Runtime::Current(); 646 bool shutting_down = (runtime == NULL) || runtime->IsShuttingDown(); 647 LOG(shutting_down ? WARNING : FATAL) << "ConditionVariable::~ConditionVariable for " << name_ 648 << " called with " << num_waiters_ << " waiters."; 649 } 650#else 651 // We can't use CHECK_MUTEX_CALL here because on shutdown a suspended daemon thread 652 // may still be using condition variables. 653 int rc = pthread_cond_destroy(&cond_); 654 if (rc != 0) { 655 errno = rc; 656 MutexLock mu(Thread::Current(), *Locks::runtime_shutdown_lock_); 657 Runtime* runtime = Runtime::Current(); 658 bool shutting_down = (runtime == NULL) || runtime->IsShuttingDown(); 659 PLOG(shutting_down ? WARNING : FATAL) << "pthread_cond_destroy failed for " << name_; 660 } 661#endif 662} 663 664void ConditionVariable::Broadcast(Thread* self) { 665 DCHECK(self == NULL || self == Thread::Current()); 666 // TODO: enable below, there's a race in thread creation that causes false failures currently. 667 // guard_.AssertExclusiveHeld(self); 668 DCHECK_EQ(guard_.GetExclusiveOwnerTid(), SafeGetTid(self)); 669#if ART_USE_FUTEXES 670 if (num_waiters_ > 0) { 671 android_atomic_inc(&sequence_); // Indicate the broadcast occurred. 672 bool done = false; 673 do { 674 int32_t cur_sequence = sequence_; 675 // Requeue waiters onto mutex. The waiter holds the contender count on the mutex high ensuring 676 // mutex unlocks will awaken the requeued waiter thread. 677 done = futex(&sequence_, FUTEX_CMP_REQUEUE, 0, 678 reinterpret_cast<const timespec*>(std::numeric_limits<int32_t>::max()), 679 &guard_.state_, cur_sequence) != -1; 680 if (!done) { 681 if (errno != EAGAIN) { 682 PLOG(FATAL) << "futex cmp requeue failed for " << name_; 683 } 684 } 685 } while (!done); 686 } 687#else 688 CHECK_MUTEX_CALL(pthread_cond_broadcast, (&cond_)); 689#endif 690} 691 692void ConditionVariable::Signal(Thread* self) { 693 DCHECK(self == NULL || self == Thread::Current()); 694 guard_.AssertExclusiveHeld(self); 695#if ART_USE_FUTEXES 696 if (num_waiters_ > 0) { 697 android_atomic_inc(&sequence_); // Indicate a signal occurred. 698 // Futex wake 1 waiter who will then come and in contend on mutex. It'd be nice to requeue them 699 // to avoid this, however, requeueing can only move all waiters. 700 int num_woken = futex(&sequence_, FUTEX_WAKE, 1, NULL, NULL, 0); 701 // Check something was woken or else we changed sequence_ before they had chance to wait. 702 CHECK((num_woken == 0) || (num_woken == 1)); 703 } 704#else 705 CHECK_MUTEX_CALL(pthread_cond_signal, (&cond_)); 706#endif 707} 708 709void ConditionVariable::Wait(Thread* self) { 710 guard_.CheckSafeToWait(self); 711 WaitHoldingLocks(self); 712} 713 714void ConditionVariable::WaitHoldingLocks(Thread* self) { 715 DCHECK(self == NULL || self == Thread::Current()); 716 guard_.AssertExclusiveHeld(self); 717 unsigned int old_recursion_count = guard_.recursion_count_; 718#if ART_USE_FUTEXES 719 num_waiters_++; 720 // Ensure the Mutex is contended so that requeued threads are awoken. 721 android_atomic_inc(&guard_.num_contenders_); 722 guard_.recursion_count_ = 1; 723 int32_t cur_sequence = sequence_; 724 guard_.ExclusiveUnlock(self); 725 if (futex(&sequence_, FUTEX_WAIT, cur_sequence, NULL, NULL, 0) != 0) { 726 // Futex failed, check it is an expected error. 727 // EAGAIN == EWOULDBLK, so we let the caller try again. 728 // EINTR implies a signal was sent to this thread. 729 if ((errno != EINTR) && (errno != EAGAIN)) { 730 PLOG(FATAL) << "futex wait failed for " << name_; 731 } 732 } 733 guard_.ExclusiveLock(self); 734 CHECK_GE(num_waiters_, 0); 735 num_waiters_--; 736 // We awoke and so no longer require awakes from the guard_'s unlock. 737 CHECK_GE(guard_.num_contenders_, 0); 738 android_atomic_dec(&guard_.num_contenders_); 739#else 740 guard_.recursion_count_ = 0; 741 CHECK_MUTEX_CALL(pthread_cond_wait, (&cond_, &guard_.mutex_)); 742#endif 743 guard_.recursion_count_ = old_recursion_count; 744} 745 746void ConditionVariable::TimedWait(Thread* self, int64_t ms, int32_t ns) { 747 DCHECK(self == NULL || self == Thread::Current()); 748 guard_.AssertExclusiveHeld(self); 749 guard_.CheckSafeToWait(self); 750 unsigned int old_recursion_count = guard_.recursion_count_; 751#if ART_USE_FUTEXES 752 timespec rel_ts; 753 InitTimeSpec(false, CLOCK_REALTIME, ms, ns, &rel_ts); 754 num_waiters_++; 755 // Ensure the Mutex is contended so that requeued threads are awoken. 756 android_atomic_inc(&guard_.num_contenders_); 757 guard_.recursion_count_ = 1; 758 int32_t cur_sequence = sequence_; 759 guard_.ExclusiveUnlock(self); 760 if (futex(&sequence_, FUTEX_WAIT, cur_sequence, &rel_ts, NULL, 0) != 0) { 761 if (errno == ETIMEDOUT) { 762 // Timed out we're done. 763 } else if ((errno == EAGAIN) || (errno == EINTR)) { 764 // A signal or ConditionVariable::Signal/Broadcast has come in. 765 } else { 766 PLOG(FATAL) << "timed futex wait failed for " << name_; 767 } 768 } 769 guard_.ExclusiveLock(self); 770 CHECK_GE(num_waiters_, 0); 771 num_waiters_--; 772 // We awoke and so no longer require awakes from the guard_'s unlock. 773 CHECK_GE(guard_.num_contenders_, 0); 774 android_atomic_dec(&guard_.num_contenders_); 775#else 776#ifdef HAVE_TIMEDWAIT_MONOTONIC 777#define TIMEDWAIT pthread_cond_timedwait_monotonic 778 int clock = CLOCK_MONOTONIC; 779#else 780#define TIMEDWAIT pthread_cond_timedwait 781 int clock = CLOCK_REALTIME; 782#endif 783 guard_.recursion_count_ = 0; 784 timespec ts; 785 InitTimeSpec(true, clock, ms, ns, &ts); 786 int rc = TEMP_FAILURE_RETRY(TIMEDWAIT(&cond_, &guard_.mutex_, &ts)); 787 if (rc != 0 && rc != ETIMEDOUT) { 788 errno = rc; 789 PLOG(FATAL) << "TimedWait failed for " << name_; 790 } 791#endif 792 guard_.recursion_count_ = old_recursion_count; 793} 794 795} // namespace art 796