1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef mozilla_Monitor_h
8 #define mozilla_Monitor_h
9 
10 #include "mozilla/CondVar.h"
11 #include "mozilla/Mutex.h"
12 
13 namespace mozilla {
14 
15 /**
16  * Monitor provides a *non*-reentrant monitor: *not* a Java-style
17  * monitor.  If your code needs support for reentrancy, use
18  * ReentrantMonitor instead.  (Rarely should reentrancy be needed.)
19  *
20  * Instead of directly calling Monitor methods, it's safer and simpler
21  * to instead use the RAII wrappers MonitorAutoLock and
22  * MonitorAutoUnlock.
23  */
24 class Monitor
25 {
26 public:
27   explicit Monitor(const char* aName)
28     : mMutex(aName)
29     , mCondVar(mMutex, "[Monitor.mCondVar]")
30   {
31   }
32 
33   ~Monitor() {}
34 
35   void Lock() { mMutex.Lock(); }
36   void Unlock() { mMutex.Unlock(); }
37 
38   nsresult Wait(PRIntervalTime aInterval = PR_INTERVAL_NO_TIMEOUT)
39   {
40     return mCondVar.Wait(aInterval);
41   }
42 
43   nsresult Notify() { return mCondVar.Notify(); }
44   nsresult NotifyAll() { return mCondVar.NotifyAll(); }
45 
46   void AssertCurrentThreadOwns() const
47   {
48     mMutex.AssertCurrentThreadOwns();
49   }
50 
51   void AssertNotCurrentThreadOwns() const
52   {
53     mMutex.AssertNotCurrentThreadOwns();
54   }
55 
56 private:
57   Monitor();
58   Monitor(const Monitor&);
59   Monitor& operator=(const Monitor&);
60 
61   Mutex mMutex;
62   CondVar mCondVar;
63 };
64 
65 /**
66  * Lock the monitor for the lexical scope instances of this class are
67  * bound to (except for MonitorAutoUnlock in nested scopes).
68  *
69  * The monitor must be unlocked when instances of this class are
70  * created.
71  */
72 class MOZ_STACK_CLASS MonitorAutoLock
73 {
74 public:
75   explicit MonitorAutoLock(Monitor& aMonitor)
76     : mMonitor(&aMonitor)
77   {
78     mMonitor->Lock();
79   }
80 
81   ~MonitorAutoLock()
82   {
83     mMonitor->Unlock();
84   }
85 
86   nsresult Wait(PRIntervalTime aInterval = PR_INTERVAL_NO_TIMEOUT)
87   {
88     return mMonitor->Wait(aInterval);
89   }
90 
91   nsresult Notify() { return mMonitor->Notify(); }
92   nsresult NotifyAll() { return mMonitor->NotifyAll(); }
93 
94 private:
95   MonitorAutoLock();
96   MonitorAutoLock(const MonitorAutoLock&);
97   MonitorAutoLock& operator=(const MonitorAutoLock&);
98   static void* operator new(size_t) CPP_THROW_NEW;
99 
100   Monitor* mMonitor;
101 };
102 
103 /**
104  * Unlock the monitor for the lexical scope instances of this class
105  * are bound to (except for MonitorAutoLock in nested scopes).
106  *
107  * The monitor must be locked by the current thread when instances of
108  * this class are created.
109  */
110 class MOZ_STACK_CLASS MonitorAutoUnlock
111 {
112 public:
113   explicit MonitorAutoUnlock(Monitor& aMonitor)
114     : mMonitor(&aMonitor)
115   {
116     mMonitor->Unlock();
117   }
118 
119   ~MonitorAutoUnlock()
120   {
121     mMonitor->Lock();
122   }
123 
124 private:
125   MonitorAutoUnlock();
126   MonitorAutoUnlock(const MonitorAutoUnlock&);
127   MonitorAutoUnlock& operator=(const MonitorAutoUnlock&);
128   static void* operator new(size_t) CPP_THROW_NEW;
129 
130   Monitor* mMonitor;
131 };
132 
133 } // namespace mozilla
134 
135 #endif // mozilla_Monitor_h
136