1351282Sdim//===-- mutex.h -------------------------------------------------*- C++ -*-===// 2351282Sdim// 3351282Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4351282Sdim// See https://llvm.org/LICENSE.txt for license information. 5351282Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6351282Sdim// 7351282Sdim//===----------------------------------------------------------------------===// 8351282Sdim 9351282Sdim#ifndef SCUDO_MUTEX_H_ 10351282Sdim#define SCUDO_MUTEX_H_ 11351282Sdim 12351282Sdim#include "atomic_helpers.h" 13351282Sdim#include "common.h" 14351282Sdim 15351282Sdim#include <string.h> 16351282Sdim 17351282Sdim#if SCUDO_FUCHSIA 18351282Sdim#include <lib/sync/mutex.h> // for sync_mutex_t 19351282Sdim#endif 20351282Sdim 21351282Sdimnamespace scudo { 22351282Sdim 23351282Sdimclass HybridMutex { 24351282Sdimpublic: 25351282Sdim void init() { memset(this, 0, sizeof(*this)); } 26351282Sdim bool tryLock(); 27351282Sdim NOINLINE void lock() { 28360784Sdim if (LIKELY(tryLock())) 29351282Sdim return; 30351282Sdim // The compiler may try to fully unroll the loop, ending up in a 31351282Sdim // NumberOfTries*NumberOfYields block of pauses mixed with tryLocks. This 32351282Sdim // is large, ugly and unneeded, a compact loop is better for our purpose 33351282Sdim // here. Use a pragma to tell the compiler not to unroll the loop. 34351282Sdim#ifdef __clang__ 35351282Sdim#pragma nounroll 36351282Sdim#endif 37351282Sdim for (u8 I = 0U; I < NumberOfTries; I++) { 38351282Sdim yieldProcessor(NumberOfYields); 39351282Sdim if (tryLock()) 40351282Sdim return; 41351282Sdim } 42351282Sdim lockSlow(); 43351282Sdim } 44351282Sdim void unlock(); 45351282Sdim 46351282Sdimprivate: 47360784Sdim static constexpr u8 NumberOfTries = 8U; 48360784Sdim static constexpr u8 NumberOfYields = 8U; 49351282Sdim 50351282Sdim#if SCUDO_LINUX 51351282Sdim atomic_u32 M; 52351282Sdim#elif SCUDO_FUCHSIA 53351282Sdim sync_mutex_t M; 54351282Sdim#endif 55351282Sdim 56351282Sdim void lockSlow(); 57351282Sdim}; 58351282Sdim 59351282Sdimclass ScopedLock { 60351282Sdimpublic: 61351282Sdim explicit ScopedLock(HybridMutex &M) : Mutex(M) { Mutex.lock(); } 62351282Sdim ~ScopedLock() { Mutex.unlock(); } 63351282Sdim 64351282Sdimprivate: 65351282Sdim HybridMutex &Mutex; 66351282Sdim 67351282Sdim ScopedLock(const ScopedLock &) = delete; 68351282Sdim void operator=(const ScopedLock &) = delete; 69351282Sdim}; 70351282Sdim 71351282Sdim} // namespace scudo 72351282Sdim 73351282Sdim#endif // SCUDO_MUTEX_H_ 74