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 void init() { memset(this, 0, sizeof(*this)); } 26 bool tryLock(); 27 NOINLINE void lock() { 28 if (LIKELY(tryLock())) 29 return; 30 // The compiler may try to fully unroll the loop, ending up in a 31 // NumberOfTries*NumberOfYields block of pauses mixed with tryLocks. This 32 // is large, ugly and unneeded, a compact loop is better for our purpose 33 // here. Use a pragma to tell the compiler not to unroll the loop. 34 #ifdef __clang__ 35 #pragma nounroll 36 #endif 37 for (u8 I = 0U; I < NumberOfTries; I++) { 38 yieldProcessor(NumberOfYields); 39 if (tryLock()) 40 return; 41 } 42 lockSlow(); 43 } 44 void unlock(); 45 46 private: 47 static constexpr u8 NumberOfTries = 8U; 48 static constexpr u8 NumberOfYields = 8U; 49 50 #if SCUDO_LINUX 51 atomic_u32 M; 52 #elif SCUDO_FUCHSIA 53 sync_mutex_t M; 54 #endif 55 56 void lockSlow(); 57 }; 58 59 class ScopedLock { 60 public: 61 explicit ScopedLock(HybridMutex &M) : Mutex(M) { Mutex.lock(); } 62 ~ScopedLock() { Mutex.unlock(); } 63 64 private: 65 HybridMutex &Mutex; 66 67 ScopedLock(const ScopedLock &) = delete; 68 void operator=(const ScopedLock &) = delete; 69 }; 70 71 } // namespace scudo 72 73 #endif // SCUDO_MUTEX_H_ 74