//===-- mutex.h -------------------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef SCUDO_MUTEX_H_ #define SCUDO_MUTEX_H_ #include "atomic_helpers.h" #include "common.h" #include #if SCUDO_FUCHSIA #include // for sync_mutex_t #endif namespace scudo { class HybridMutex { public: bool tryLock(); NOINLINE void lock() { if (LIKELY(tryLock())) return; // The compiler may try to fully unroll the loop, ending up in a // NumberOfTries*NumberOfYields block of pauses mixed with tryLocks. This // is large, ugly and unneeded, a compact loop is better for our purpose // here. Use a pragma to tell the compiler not to unroll the loop. #ifdef __clang__ #pragma nounroll #endif for (u8 I = 0U; I < NumberOfTries; I++) { yieldProcessor(NumberOfYields); if (tryLock()) return; } lockSlow(); } void unlock(); private: static constexpr u8 NumberOfTries = 8U; static constexpr u8 NumberOfYields = 8U; #if SCUDO_LINUX atomic_u32 M = {}; #elif SCUDO_FUCHSIA sync_mutex_t M = {}; #endif void lockSlow(); }; class ScopedLock { public: explicit ScopedLock(HybridMutex &M) : Mutex(M) { Mutex.lock(); } ~ScopedLock() { Mutex.unlock(); } private: HybridMutex &Mutex; ScopedLock(const ScopedLock &) = delete; void operator=(const ScopedLock &) = delete; }; } // namespace scudo #endif // SCUDO_MUTEX_H_