RWMutex.h revision 360784
1//===- RWMutex.h - Reader/Writer Mutual Exclusion Lock ----------*- 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// This file declares the llvm::sys::RWMutex class.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_SUPPORT_RWMUTEX_H
14#define LLVM_SUPPORT_RWMUTEX_H
15
16#include "llvm/Config/llvm-config.h"
17#include "llvm/Support/Threading.h"
18#include <cassert>
19#include <mutex>
20#include <shared_mutex>
21
22// std::shared_timed_mutex is only availble on macOS 10.12 and later.
23#if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
24#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101200
25#define LLVM_USE_RW_MUTEX_IMPL
26#endif
27#endif
28
29namespace llvm {
30namespace sys {
31
32#if defined(LLVM_USE_RW_MUTEX_IMPL)
33/// Platform agnostic RWMutex class.
34class RWMutexImpl {
35  /// @name Constructors
36  /// @{
37public:
38  /// Initializes the lock but doesn't acquire it.
39  /// Default Constructor.
40  explicit RWMutexImpl();
41
42  /// @}
43  /// @name Do Not Implement
44  /// @{
45  RWMutexImpl(const RWMutexImpl &original) = delete;
46  RWMutexImpl &operator=(const RWMutexImpl &) = delete;
47  /// @}
48
49  /// Releases and removes the lock
50  /// Destructor
51  ~RWMutexImpl();
52
53  /// @}
54  /// @name Methods
55  /// @{
56public:
57  /// Attempts to unconditionally acquire the lock in reader mode. If the
58  /// lock is held by a writer, this method will wait until it can acquire
59  /// the lock.
60  /// @returns false if any kind of error occurs, true otherwise.
61  /// Unconditionally acquire the lock in reader mode.
62  bool lock_shared();
63
64  /// Attempts to release the lock in reader mode.
65  /// @returns false if any kind of error occurs, true otherwise.
66  /// Unconditionally release the lock in reader mode.
67  bool unlock_shared();
68
69  /// Attempts to unconditionally acquire the lock in reader mode. If the
70  /// lock is held by any readers, this method will wait until it can
71  /// acquire the lock.
72  /// @returns false if any kind of error occurs, true otherwise.
73  /// Unconditionally acquire the lock in writer mode.
74  bool lock();
75
76  /// Attempts to release the lock in writer mode.
77  /// @returns false if any kind of error occurs, true otherwise.
78  /// Unconditionally release the lock in write mode.
79  bool unlock();
80
81  //@}
82  /// @name Platform Dependent Data
83  /// @{
84private:
85#if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0
86  void *data_ = nullptr; ///< We don't know what the data will be
87#endif
88};
89#endif
90
91/// SmartMutex - An R/W mutex with a compile time constant parameter that
92/// indicates whether this mutex should become a no-op when we're not
93/// running in multithreaded mode.
94template <bool mt_only> class SmartRWMutex {
95  // shared_mutex (C++17) is more efficient than shared_timed_mutex (C++14)
96  // on Windows and always available on MSVC.
97#if defined(_MSC_VER) || __cplusplus > 201402L
98  std::shared_mutex impl;
99#else
100#if !defined(LLVM_USE_RW_MUTEX_IMPL)
101  std::shared_timed_mutex impl;
102#else
103  RWMutexImpl impl;
104#endif
105#endif
106  unsigned readers = 0;
107  unsigned writers = 0;
108
109public:
110  bool lock_shared() {
111    if (!mt_only || llvm_is_multithreaded()) {
112      impl.lock_shared();
113      return true;
114    }
115
116    // Single-threaded debugging code.  This would be racy in multithreaded
117    // mode, but provides not sanity checks in single threaded mode.
118    ++readers;
119    return true;
120  }
121
122  bool unlock_shared() {
123    if (!mt_only || llvm_is_multithreaded()) {
124      impl.unlock_shared();
125      return true;
126    }
127
128    // Single-threaded debugging code.  This would be racy in multithreaded
129    // mode, but provides not sanity checks in single threaded mode.
130    assert(readers > 0 && "Reader lock not acquired before release!");
131    --readers;
132    return true;
133  }
134
135  bool lock() {
136    if (!mt_only || llvm_is_multithreaded()) {
137      impl.lock();
138      return true;
139    }
140
141    // Single-threaded debugging code.  This would be racy in multithreaded
142    // mode, but provides not sanity checks in single threaded mode.
143    assert(writers == 0 && "Writer lock already acquired!");
144    ++writers;
145    return true;
146  }
147
148  bool unlock() {
149    if (!mt_only || llvm_is_multithreaded()) {
150      impl.unlock();
151      return true;
152    }
153
154    // Single-threaded debugging code.  This would be racy in multithreaded
155    // mode, but provides not sanity checks in single threaded mode.
156    assert(writers == 1 && "Writer lock not acquired before release!");
157    --writers;
158    return true;
159  }
160};
161
162typedef SmartRWMutex<false> RWMutex;
163
164/// ScopedReader - RAII acquisition of a reader lock
165#if !defined(LLVM_USE_RW_MUTEX_IMPL)
166template <bool mt_only>
167using SmartScopedReader = const std::shared_lock<SmartRWMutex<mt_only>>;
168#else
169template <bool mt_only> struct SmartScopedReader {
170  SmartRWMutex<mt_only> &mutex;
171
172  explicit SmartScopedReader(SmartRWMutex<mt_only> &m) : mutex(m) {
173    mutex.lock_shared();
174  }
175
176  ~SmartScopedReader() { mutex.unlock_shared(); }
177};
178#endif
179typedef SmartScopedReader<false> ScopedReader;
180
181/// ScopedWriter - RAII acquisition of a writer lock
182#if !defined(LLVM_USE_RW_MUTEX_IMPL)
183template <bool mt_only>
184using SmartScopedWriter = std::lock_guard<SmartRWMutex<mt_only>>;
185#else
186template <bool mt_only> struct SmartScopedWriter {
187  SmartRWMutex<mt_only> &mutex;
188
189  explicit SmartScopedWriter(SmartRWMutex<mt_only> &m) : mutex(m) {
190    mutex.lock();
191  }
192
193  ~SmartScopedWriter() { mutex.unlock(); }
194};
195#endif
196typedef SmartScopedWriter<false> ScopedWriter;
197
198} // end namespace sys
199} // end namespace llvm
200
201#endif // LLVM_SUPPORT_RWMUTEX_H
202