1 //===-- mutex.h -------------------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef SCUDO_MUTEX_H_ 10 #define SCUDO_MUTEX_H_ 11 12 #include "atomic_helpers.h" 13 #include "common.h" 14 15 #include <string.h> 16 17 #if SCUDO_FUCHSIA 18 #include <lib/sync/mutex.h> // for sync_mutex_t 19 #endif 20 21 namespace scudo { 22 23 class HybridMutex { 24 public: 25 bool tryLock(); 26 NOINLINE void lock() { 27 if (LIKELY(tryLock())) 28 return; 29 // The compiler may try to fully unroll the loop, ending up in a 30 // NumberOfTries*NumberOfYields block of pauses mixed with tryLocks. This 31 // is large, ugly and unneeded, a compact loop is better for our purpose 32 // here. Use a pragma to tell the compiler not to unroll the loop. 33 #ifdef __clang__ 34 #pragma nounroll 35 #endif 36 for (u8 I = 0U; I < NumberOfTries; I++) { 37 yieldProcessor(NumberOfYields); 38 if (tryLock()) 39 return; 40 } 41 lockSlow(); 42 } 43 void unlock(); 44 45 private: 46 static constexpr u8 NumberOfTries = 8U; 47 static constexpr u8 NumberOfYields = 8U; 48 49 #if SCUDO_LINUX 50 atomic_u32 M = {}; 51 #elif SCUDO_FUCHSIA 52 sync_mutex_t M = {}; 53 #endif 54 55 void lockSlow(); 56 }; 57 58 class ScopedLock { 59 public: 60 explicit ScopedLock(HybridMutex &M) : Mutex(M) { Mutex.lock(); } 61 ~ScopedLock() { Mutex.unlock(); } 62 63 private: 64 HybridMutex &Mutex; 65 66 ScopedLock(const ScopedLock &) = delete; 67 void operator=(const ScopedLock &) = delete; 68 }; 69 70 } // namespace scudo 71 72 #endif // SCUDO_MUTEX_H_ 73