mutex.h revision 351401
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 21namespace scudo { 22 23class HybridMutex { 24public: 25 void init() { memset(this, 0, sizeof(*this)); } 26 bool tryLock(); 27 NOINLINE void lock() { 28 if (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 46private: 47 static constexpr u8 NumberOfTries = 10U; 48 static constexpr u8 NumberOfYields = 10U; 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 59class ScopedLock { 60public: 61 explicit ScopedLock(HybridMutex &M) : Mutex(M) { Mutex.lock(); } 62 ~ScopedLock() { Mutex.unlock(); } 63 64private: 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