blob: a654d35c5a78c2a22e5b4b24866576e275ef2f90 [file] [log] [blame]
Dynamic Tools Team517193e2019-09-11 14:48:41 +00001//===-- 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:
Dynamic Tools Team08b690a2020-04-10 13:41:12 -070025 void init() { M = {}; }
Dynamic Tools Team517193e2019-09-11 14:48:41 +000026 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
46private:
47 static constexpr u8 NumberOfTries = 8U;
48 static constexpr u8 NumberOfYields = 8U;
49
50#if SCUDO_LINUX
Vitaly Buka5d3d7272021-04-29 01:19:51 -070051 atomic_u32 M = {};
Dynamic Tools Team517193e2019-09-11 14:48:41 +000052#elif SCUDO_FUCHSIA
Vitaly Buka5d3d7272021-04-29 01:19:51 -070053 sync_mutex_t M = {};
Dynamic Tools Team517193e2019-09-11 14:48:41 +000054#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_