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