1 //===- RWMutex.h - Reader/Writer Mutual Exclusion Lock ----------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file declares the llvm::sys::RWMutex class.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_SUPPORT_RWMUTEX_H
15 #define LLVM_SUPPORT_RWMUTEX_H
16 
17 #include "llvm/Support/Compiler.h"
18 #include "llvm/Support/Threading.h"
19 #include <cassert>
20 
21 namespace llvm
22 {
23   namespace sys
24   {
25     /// @brief Platform agnostic RWMutex class.
26     class RWMutexImpl
27     {
28     /// @name Constructors
29     /// @{
30     public:
31 
32       /// Initializes the lock but doesn't acquire it.
33       /// @brief Default Constructor.
34       explicit RWMutexImpl();
35 
36       /// Releases and removes the lock
37       /// @brief Destructor
38       ~RWMutexImpl();
39 
40     /// @}
41     /// @name Methods
42     /// @{
43     public:
44 
45       /// Attempts to unconditionally acquire the lock in reader mode. If the
46       /// lock is held by a writer, this method will wait until it can acquire
47       /// the lock.
48       /// @returns false if any kind of error occurs, true otherwise.
49       /// @brief Unconditionally acquire the lock in reader mode.
50       bool reader_acquire();
51 
52       /// Attempts to release the lock in reader mode.
53       /// @returns false if any kind of error occurs, true otherwise.
54       /// @brief Unconditionally release the lock in reader mode.
55       bool reader_release();
56 
57       /// Attempts to unconditionally acquire the lock in reader mode. If the
58       /// lock is held by any readers, this method will wait until it can
59       /// acquire the lock.
60       /// @returns false if any kind of error occurs, true otherwise.
61       /// @brief Unconditionally acquire the lock in writer mode.
62       bool writer_acquire();
63 
64       /// Attempts to release the lock in writer mode.
65       /// @returns false if any kind of error occurs, true otherwise.
66       /// @brief Unconditionally release the lock in write mode.
67       bool writer_release();
68 
69     //@}
70     /// @name Platform Dependent Data
71     /// @{
72     private:
73       void* data_; ///< We don't know what the data will be
74 
75     /// @}
76     /// @name Do Not Implement
77     /// @{
78     private:
79       RWMutexImpl(const RWMutexImpl & original) = delete;
80       void operator=(const RWMutexImpl &) = delete;
81     /// @}
82     };
83 
84     /// SmartMutex - An R/W mutex with a compile time constant parameter that
85     /// indicates whether this mutex should become a no-op when we're not
86     /// running in multithreaded mode.
87     template<bool mt_only>
88     class SmartRWMutex {
89       RWMutexImpl impl;
90       unsigned readers, writers;
91     public:
SmartRWMutex()92       explicit SmartRWMutex() : impl(), readers(0), writers(0) { }
93 
lock_shared()94       bool lock_shared() {
95         if (!mt_only || llvm_is_multithreaded())
96           return impl.reader_acquire();
97 
98         // Single-threaded debugging code.  This would be racy in multithreaded
99         // mode, but provides not sanity checks in single threaded mode.
100         ++readers;
101         return true;
102       }
103 
unlock_shared()104       bool unlock_shared() {
105         if (!mt_only || llvm_is_multithreaded())
106           return impl.reader_release();
107 
108         // Single-threaded debugging code.  This would be racy in multithreaded
109         // mode, but provides not sanity checks in single threaded mode.
110         assert(readers > 0 && "Reader lock not acquired before release!");
111         --readers;
112         return true;
113       }
114 
lock()115       bool lock() {
116         if (!mt_only || llvm_is_multithreaded())
117           return impl.writer_acquire();
118 
119         // Single-threaded debugging code.  This would be racy in multithreaded
120         // mode, but provides not sanity checks in single threaded mode.
121         assert(writers == 0 && "Writer lock already acquired!");
122         ++writers;
123         return true;
124       }
125 
unlock()126       bool unlock() {
127         if (!mt_only || llvm_is_multithreaded())
128           return impl.writer_release();
129 
130         // Single-threaded debugging code.  This would be racy in multithreaded
131         // mode, but provides not sanity checks in single threaded mode.
132         assert(writers == 1 && "Writer lock not acquired before release!");
133         --writers;
134         return true;
135       }
136 
137     private:
138       SmartRWMutex(const SmartRWMutex<mt_only> & original);
139       void operator=(const SmartRWMutex<mt_only> &);
140     };
141     typedef SmartRWMutex<false> RWMutex;
142 
143     /// ScopedReader - RAII acquisition of a reader lock
144     template<bool mt_only>
145     struct SmartScopedReader {
146       SmartRWMutex<mt_only>& mutex;
147 
SmartScopedReaderSmartScopedReader148       explicit SmartScopedReader(SmartRWMutex<mt_only>& m) : mutex(m) {
149         mutex.lock_shared();
150       }
151 
~SmartScopedReaderSmartScopedReader152       ~SmartScopedReader() {
153         mutex.unlock_shared();
154       }
155     };
156     typedef SmartScopedReader<false> ScopedReader;
157 
158     /// ScopedWriter - RAII acquisition of a writer lock
159     template<bool mt_only>
160     struct SmartScopedWriter {
161       SmartRWMutex<mt_only>& mutex;
162 
SmartScopedWriterSmartScopedWriter163       explicit SmartScopedWriter(SmartRWMutex<mt_only>& m) : mutex(m) {
164         mutex.lock();
165       }
166 
~SmartScopedWriterSmartScopedWriter167       ~SmartScopedWriter() {
168         mutex.unlock();
169       }
170     };
171     typedef SmartScopedWriter<false> ScopedWriter;
172   }
173 }
174 
175 #endif
176