1218885Sdim//===- RWMutex.h - Reader/Writer Mutual Exclusion Lock ----------*- C++ -*-===//
2218885Sdim//
3218885Sdim//                     The LLVM Compiler Infrastructure
4218885Sdim//
5218885Sdim// This file is distributed under the University of Illinois Open Source
6218885Sdim// License. See LICENSE.TXT for details.
7218885Sdim//
8218885Sdim//===----------------------------------------------------------------------===//
9218885Sdim//
10218885Sdim// This file declares the llvm::sys::RWMutex class.
11218885Sdim//
12218885Sdim//===----------------------------------------------------------------------===//
13218885Sdim
14218885Sdim#ifndef LLVM_SYSTEM_RWMUTEX_H
15218885Sdim#define LLVM_SYSTEM_RWMUTEX_H
16218885Sdim
17245431Sdim#include "llvm/Support/Compiler.h"
18218885Sdim#include "llvm/Support/Threading.h"
19218885Sdim#include <cassert>
20218885Sdim
21218885Sdimnamespace llvm
22218885Sdim{
23218885Sdim  namespace sys
24218885Sdim  {
25218885Sdim    /// @brief Platform agnostic RWMutex class.
26218885Sdim    class RWMutexImpl
27218885Sdim    {
28218885Sdim    /// @name Constructors
29218885Sdim    /// @{
30218885Sdim    public:
31218885Sdim
32218885Sdim      /// Initializes the lock but doesn't acquire it.
33218885Sdim      /// @brief Default Constructor.
34218885Sdim      explicit RWMutexImpl();
35218885Sdim
36218885Sdim      /// Releases and removes the lock
37218885Sdim      /// @brief Destructor
38218885Sdim      ~RWMutexImpl();
39218885Sdim
40218885Sdim    /// @}
41218885Sdim    /// @name Methods
42218885Sdim    /// @{
43218885Sdim    public:
44218885Sdim
45218885Sdim      /// Attempts to unconditionally acquire the lock in reader mode. If the
46218885Sdim      /// lock is held by a writer, this method will wait until it can acquire
47218885Sdim      /// the lock.
48218885Sdim      /// @returns false if any kind of error occurs, true otherwise.
49218885Sdim      /// @brief Unconditionally acquire the lock in reader mode.
50218885Sdim      bool reader_acquire();
51218885Sdim
52218885Sdim      /// Attempts to release the lock in reader mode.
53218885Sdim      /// @returns false if any kind of error occurs, true otherwise.
54218885Sdim      /// @brief Unconditionally release the lock in reader mode.
55218885Sdim      bool reader_release();
56218885Sdim
57218885Sdim      /// Attempts to unconditionally acquire the lock in reader mode. If the
58218885Sdim      /// lock is held by any readers, this method will wait until it can
59218885Sdim      /// acquire the lock.
60218885Sdim      /// @returns false if any kind of error occurs, true otherwise.
61218885Sdim      /// @brief Unconditionally acquire the lock in writer mode.
62218885Sdim      bool writer_acquire();
63218885Sdim
64218885Sdim      /// Attempts to release the lock in writer mode.
65218885Sdim      /// @returns false if any kind of error occurs, true otherwise.
66218885Sdim      /// @brief Unconditionally release the lock in write mode.
67218885Sdim      bool writer_release();
68218885Sdim
69218885Sdim    //@}
70218885Sdim    /// @name Platform Dependent Data
71218885Sdim    /// @{
72218885Sdim    private:
73218885Sdim      void* data_; ///< We don't know what the data will be
74218885Sdim
75218885Sdim    /// @}
76218885Sdim    /// @name Do Not Implement
77218885Sdim    /// @{
78218885Sdim    private:
79245431Sdim      RWMutexImpl(const RWMutexImpl & original) LLVM_DELETED_FUNCTION;
80245431Sdim      void operator=(const RWMutexImpl &) LLVM_DELETED_FUNCTION;
81218885Sdim    /// @}
82218885Sdim    };
83218885Sdim
84218885Sdim    /// SmartMutex - An R/W mutex with a compile time constant parameter that
85218885Sdim    /// indicates whether this mutex should become a no-op when we're not
86218885Sdim    /// running in multithreaded mode.
87218885Sdim    template<bool mt_only>
88218885Sdim    class SmartRWMutex : public RWMutexImpl {
89218885Sdim      unsigned readers, writers;
90218885Sdim    public:
91218885Sdim      explicit SmartRWMutex() : RWMutexImpl(), readers(0), writers(0) { }
92218885Sdim
93218885Sdim      bool reader_acquire() {
94218885Sdim        if (!mt_only || llvm_is_multithreaded())
95218885Sdim          return RWMutexImpl::reader_acquire();
96218885Sdim
97218885Sdim        // Single-threaded debugging code.  This would be racy in multithreaded
98218885Sdim        // mode, but provides not sanity checks in single threaded mode.
99218885Sdim        ++readers;
100218885Sdim        return true;
101218885Sdim      }
102218885Sdim
103218885Sdim      bool reader_release() {
104218885Sdim        if (!mt_only || llvm_is_multithreaded())
105218885Sdim          return RWMutexImpl::reader_release();
106218885Sdim
107218885Sdim        // Single-threaded debugging code.  This would be racy in multithreaded
108218885Sdim        // mode, but provides not sanity checks in single threaded mode.
109218885Sdim        assert(readers > 0 && "Reader lock not acquired before release!");
110218885Sdim        --readers;
111218885Sdim        return true;
112218885Sdim      }
113218885Sdim
114218885Sdim      bool writer_acquire() {
115218885Sdim        if (!mt_only || llvm_is_multithreaded())
116218885Sdim          return RWMutexImpl::writer_acquire();
117218885Sdim
118218885Sdim        // Single-threaded debugging code.  This would be racy in multithreaded
119218885Sdim        // mode, but provides not sanity checks in single threaded mode.
120218885Sdim        assert(writers == 0 && "Writer lock already acquired!");
121218885Sdim        ++writers;
122218885Sdim        return true;
123218885Sdim      }
124218885Sdim
125218885Sdim      bool writer_release() {
126218885Sdim        if (!mt_only || llvm_is_multithreaded())
127218885Sdim          return RWMutexImpl::writer_release();
128218885Sdim
129218885Sdim        // Single-threaded debugging code.  This would be racy in multithreaded
130218885Sdim        // mode, but provides not sanity checks in single threaded mode.
131218885Sdim        assert(writers == 1 && "Writer lock not acquired before release!");
132218885Sdim        --writers;
133218885Sdim        return true;
134218885Sdim      }
135218885Sdim
136218885Sdim    private:
137218885Sdim      SmartRWMutex(const SmartRWMutex<mt_only> & original);
138218885Sdim      void operator=(const SmartRWMutex<mt_only> &);
139218885Sdim    };
140218885Sdim    typedef SmartRWMutex<false> RWMutex;
141218885Sdim
142218885Sdim    /// ScopedReader - RAII acquisition of a reader lock
143218885Sdim    template<bool mt_only>
144218885Sdim    struct SmartScopedReader {
145218885Sdim      SmartRWMutex<mt_only>& mutex;
146218885Sdim
147218885Sdim      explicit SmartScopedReader(SmartRWMutex<mt_only>& m) : mutex(m) {
148218885Sdim        mutex.reader_acquire();
149218885Sdim      }
150218885Sdim
151218885Sdim      ~SmartScopedReader() {
152218885Sdim        mutex.reader_release();
153218885Sdim      }
154218885Sdim    };
155218885Sdim    typedef SmartScopedReader<false> ScopedReader;
156218885Sdim
157218885Sdim    /// ScopedWriter - RAII acquisition of a writer lock
158218885Sdim    template<bool mt_only>
159218885Sdim    struct SmartScopedWriter {
160218885Sdim      SmartRWMutex<mt_only>& mutex;
161218885Sdim
162218885Sdim      explicit SmartScopedWriter(SmartRWMutex<mt_only>& m) : mutex(m) {
163218885Sdim        mutex.writer_acquire();
164218885Sdim      }
165218885Sdim
166218885Sdim      ~SmartScopedWriter() {
167218885Sdim        mutex.writer_release();
168218885Sdim      }
169218885Sdim    };
170218885Sdim    typedef SmartScopedWriter<false> ScopedWriter;
171218885Sdim  }
172218885Sdim}
173218885Sdim
174218885Sdim#endif
175