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_SYSTEM_RWMUTEX_H
15#define LLVM_SYSTEM_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) LLVM_DELETED_FUNCTION;
80      void operator=(const RWMutexImpl &) LLVM_DELETED_FUNCTION;
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 : public RWMutexImpl {
89      unsigned readers, writers;
90    public:
91      explicit SmartRWMutex() : RWMutexImpl(), readers(0), writers(0) { }
92
93      bool reader_acquire() {
94        if (!mt_only || llvm_is_multithreaded())
95          return RWMutexImpl::reader_acquire();
96
97        // Single-threaded debugging code.  This would be racy in multithreaded
98        // mode, but provides not sanity checks in single threaded mode.
99        ++readers;
100        return true;
101      }
102
103      bool reader_release() {
104        if (!mt_only || llvm_is_multithreaded())
105          return RWMutexImpl::reader_release();
106
107        // Single-threaded debugging code.  This would be racy in multithreaded
108        // mode, but provides not sanity checks in single threaded mode.
109        assert(readers > 0 && "Reader lock not acquired before release!");
110        --readers;
111        return true;
112      }
113
114      bool writer_acquire() {
115        if (!mt_only || llvm_is_multithreaded())
116          return RWMutexImpl::writer_acquire();
117
118        // Single-threaded debugging code.  This would be racy in multithreaded
119        // mode, but provides not sanity checks in single threaded mode.
120        assert(writers == 0 && "Writer lock already acquired!");
121        ++writers;
122        return true;
123      }
124
125      bool writer_release() {
126        if (!mt_only || llvm_is_multithreaded())
127          return RWMutexImpl::writer_release();
128
129        // Single-threaded debugging code.  This would be racy in multithreaded
130        // mode, but provides not sanity checks in single threaded mode.
131        assert(writers == 1 && "Writer lock not acquired before release!");
132        --writers;
133        return true;
134      }
135
136    private:
137      SmartRWMutex(const SmartRWMutex<mt_only> & original);
138      void operator=(const SmartRWMutex<mt_only> &);
139    };
140    typedef SmartRWMutex<false> RWMutex;
141
142    /// ScopedReader - RAII acquisition of a reader lock
143    template<bool mt_only>
144    struct SmartScopedReader {
145      SmartRWMutex<mt_only>& mutex;
146
147      explicit SmartScopedReader(SmartRWMutex<mt_only>& m) : mutex(m) {
148        mutex.reader_acquire();
149      }
150
151      ~SmartScopedReader() {
152        mutex.reader_release();
153      }
154    };
155    typedef SmartScopedReader<false> ScopedReader;
156
157    /// ScopedWriter - RAII acquisition of a writer lock
158    template<bool mt_only>
159    struct SmartScopedWriter {
160      SmartRWMutex<mt_only>& mutex;
161
162      explicit SmartScopedWriter(SmartRWMutex<mt_only>& m) : mutex(m) {
163        mutex.writer_acquire();
164      }
165
166      ~SmartScopedWriter() {
167        mutex.writer_release();
168      }
169    };
170    typedef SmartScopedWriter<false> ScopedWriter;
171  }
172}
173
174#endif
175