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
21namespace 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:
92      explicit SmartRWMutex() : impl(), readers(0), writers(0) { }
93
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
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
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
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
148      explicit SmartScopedReader(SmartRWMutex<mt_only>& m) : mutex(m) {
149        mutex.lock_shared();
150      }
151
152      ~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
163      explicit SmartScopedWriter(SmartRWMutex<mt_only>& m) : mutex(m) {
164        mutex.lock();
165      }
166
167      ~SmartScopedWriter() {
168        mutex.unlock();
169      }
170    };
171    typedef SmartScopedWriter<false> ScopedWriter;
172  }
173}
174
175#endif
176