// Copyright (c) 2011-present, Facebook, Inc. All rights reserved. // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). #include "monitoring/instrumented_mutex.h" #include "monitoring/perf_context_imp.h" #include "monitoring/thread_status_util.h" #include "rocksdb/system_clock.h" #include "test_util/sync_point.h" namespace ROCKSDB_NAMESPACE { namespace { #ifndef NPERF_CONTEXT Statistics* stats_for_report(SystemClock* clock, Statistics* stats) { if (clock != nullptr && stats != nullptr && stats->get_stats_level() > kExceptTimeForMutex) { return stats; } else { return nullptr; } } #endif // NPERF_CONTEXT } // namespace void InstrumentedMutex::Lock() { PERF_CONDITIONAL_TIMER_FOR_MUTEX_GUARD( db_mutex_lock_nanos, stats_code_ == DB_MUTEX_WAIT_MICROS, stats_for_report(clock_, stats_), stats_code_); LockInternal(); } void InstrumentedMutex::LockInternal() { #ifndef NDEBUG ThreadStatusUtil::TEST_StateDelay(ThreadStatus::STATE_MUTEX_WAIT); #endif #ifdef COERCE_CONTEXT_SWITCH if (stats_code_ == DB_MUTEX_WAIT_MICROS) { thread_local Random rnd(301); if (rnd.OneIn(2)) { if (bg_cv_) { bg_cv_->SignalAll(); } sched_yield(); } else { uint32_t sleep_us = rnd.Uniform(11) * 1000; if (bg_cv_) { bg_cv_->SignalAll(); } SystemClock::Default()->SleepForMicroseconds(sleep_us); } } #endif mutex_.Lock(); } void InstrumentedCondVar::Wait() { PERF_CONDITIONAL_TIMER_FOR_MUTEX_GUARD( db_condition_wait_nanos, stats_code_ == DB_MUTEX_WAIT_MICROS, stats_for_report(clock_, stats_), stats_code_); WaitInternal(); } void InstrumentedCondVar::WaitInternal() { #ifndef NDEBUG ThreadStatusUtil::TEST_StateDelay(ThreadStatus::STATE_MUTEX_WAIT); #endif cond_.Wait(); } bool InstrumentedCondVar::TimedWait(uint64_t abs_time_us) { PERF_CONDITIONAL_TIMER_FOR_MUTEX_GUARD( db_condition_wait_nanos, stats_code_ == DB_MUTEX_WAIT_MICROS, stats_for_report(clock_, stats_), stats_code_); return TimedWaitInternal(abs_time_us); } bool InstrumentedCondVar::TimedWaitInternal(uint64_t abs_time_us) { #ifndef NDEBUG ThreadStatusUtil::TEST_StateDelay(ThreadStatus::STATE_MUTEX_WAIT); #endif TEST_SYNC_POINT_CALLBACK("InstrumentedCondVar::TimedWaitInternal", &abs_time_us); return cond_.TimedWait(abs_time_us); } } // namespace ROCKSDB_NAMESPACE