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_ReentrantMonitor_h
8 #define mozilla_ReentrantMonitor_h
9 
10 #include "prmon.h"
11 
12 #ifdef MOZILLA_INTERNAL_API
13 #include "GeckoProfiler.h"
14 #endif //MOZILLA_INTERNAL_API
15 
16 #include "mozilla/BlockingResourceBase.h"
17 
18 //
19 // Provides:
20 //
21 //  - ReentrantMonitor, a Java-like monitor
22 //  - ReentrantMonitorAutoEnter, an RAII class for ensuring that
23 //    ReentrantMonitors are properly entered and exited
24 //
25 // Using ReentrantMonitorAutoEnter is MUCH preferred to making bare calls to
26 // ReentrantMonitor.Enter and Exit.
27 //
28 namespace mozilla {
29 
30 
31 /**
32  * ReentrantMonitor
33  * Java-like monitor.
34  * When possible, use ReentrantMonitorAutoEnter to hold this monitor within a
35  * scope, instead of calling Enter/Exit directly.
36  **/
37 class ReentrantMonitor : BlockingResourceBase
38 {
39 public:
40   /**
41    * ReentrantMonitor
42    * @param aName A name which can reference this monitor
43    */
ReentrantMonitor(const char * aName)44   explicit ReentrantMonitor(const char* aName)
45     : BlockingResourceBase(aName, eReentrantMonitor)
46 #ifdef DEBUG
47     , mEntryCount(0)
48 #endif
49   {
50     MOZ_COUNT_CTOR(ReentrantMonitor);
51     mReentrantMonitor = PR_NewMonitor();
52     if (!mReentrantMonitor) {
53       NS_RUNTIMEABORT("Can't allocate mozilla::ReentrantMonitor");
54     }
55   }
56 
57   /**
58    * ~ReentrantMonitor
59    **/
~ReentrantMonitor()60   ~ReentrantMonitor()
61   {
62     NS_ASSERTION(mReentrantMonitor,
63                  "improperly constructed ReentrantMonitor or double free");
64     PR_DestroyMonitor(mReentrantMonitor);
65     mReentrantMonitor = 0;
66     MOZ_COUNT_DTOR(ReentrantMonitor);
67   }
68 
69 #ifndef DEBUG
70   /**
71    * Enter
72    * @see prmon.h
73    **/
Enter()74   void Enter() { PR_EnterMonitor(mReentrantMonitor); }
75 
76   /**
77    * Exit
78    * @see prmon.h
79    **/
Exit()80   void Exit() { PR_ExitMonitor(mReentrantMonitor); }
81 
82   /**
83    * Wait
84    * @see prmon.h
85    **/
86   nsresult Wait(PRIntervalTime aInterval = PR_INTERVAL_NO_TIMEOUT)
87   {
88 #ifdef MOZILLA_INTERNAL_API
89     GeckoProfilerSleepRAII profiler_sleep;
90 #endif //MOZILLA_INTERNAL_API
91     return PR_Wait(mReentrantMonitor, aInterval) == PR_SUCCESS ?
92       NS_OK : NS_ERROR_FAILURE;
93   }
94 
95 #else // ifndef DEBUG
96   void Enter();
97   void Exit();
98   nsresult Wait(PRIntervalTime aInterval = PR_INTERVAL_NO_TIMEOUT);
99 
100 #endif  // ifndef DEBUG
101 
102   /**
103    * Notify
104    * @see prmon.h
105    **/
Notify()106   nsresult Notify()
107   {
108     return PR_Notify(mReentrantMonitor) == PR_SUCCESS ? NS_OK :
109                                                         NS_ERROR_FAILURE;
110   }
111 
112   /**
113    * NotifyAll
114    * @see prmon.h
115    **/
NotifyAll()116   nsresult NotifyAll()
117   {
118     return PR_NotifyAll(mReentrantMonitor) == PR_SUCCESS ? NS_OK :
119                                                            NS_ERROR_FAILURE;
120   }
121 
122 #ifdef DEBUG
123   /**
124    * AssertCurrentThreadIn
125    * @see prmon.h
126    **/
AssertCurrentThreadIn()127   void AssertCurrentThreadIn()
128   {
129     PR_ASSERT_CURRENT_THREAD_IN_MONITOR(mReentrantMonitor);
130   }
131 
132   /**
133    * AssertNotCurrentThreadIn
134    * @see prmon.h
135    **/
AssertNotCurrentThreadIn()136   void AssertNotCurrentThreadIn()
137   {
138     // FIXME bug 476536
139   }
140 
141 #else
AssertCurrentThreadIn()142   void AssertCurrentThreadIn() {}
AssertNotCurrentThreadIn()143   void AssertNotCurrentThreadIn() {}
144 
145 #endif  // ifdef DEBUG
146 
147 private:
148   ReentrantMonitor();
149   ReentrantMonitor(const ReentrantMonitor&);
150   ReentrantMonitor& operator=(const ReentrantMonitor&);
151 
152   PRMonitor* mReentrantMonitor;
153 #ifdef DEBUG
154   int32_t mEntryCount;
155 #endif
156 };
157 
158 
159 /**
160  * ReentrantMonitorAutoEnter
161  * Enters the ReentrantMonitor when it enters scope, and exits it when
162  * it leaves scope.
163  *
164  * MUCH PREFERRED to bare calls to ReentrantMonitor.Enter and Exit.
165  */
166 class MOZ_STACK_CLASS ReentrantMonitorAutoEnter
167 {
168 public:
169   /**
170    * Constructor
171    * The constructor aquires the given lock.  The destructor
172    * releases the lock.
173    *
174    * @param aReentrantMonitor A valid mozilla::ReentrantMonitor*.
175    **/
ReentrantMonitorAutoEnter(mozilla::ReentrantMonitor & aReentrantMonitor)176   explicit ReentrantMonitorAutoEnter(mozilla::ReentrantMonitor& aReentrantMonitor)
177     : mReentrantMonitor(&aReentrantMonitor)
178   {
179     NS_ASSERTION(mReentrantMonitor, "null monitor");
180     mReentrantMonitor->Enter();
181   }
182 
~ReentrantMonitorAutoEnter(void)183   ~ReentrantMonitorAutoEnter(void)
184   {
185     mReentrantMonitor->Exit();
186   }
187 
188   nsresult Wait(PRIntervalTime aInterval = PR_INTERVAL_NO_TIMEOUT)
189   {
190     return mReentrantMonitor->Wait(aInterval);
191   }
192 
Notify()193   nsresult Notify() { return mReentrantMonitor->Notify(); }
NotifyAll()194   nsresult NotifyAll() { return mReentrantMonitor->NotifyAll(); }
195 
196 private:
197   ReentrantMonitorAutoEnter();
198   ReentrantMonitorAutoEnter(const ReentrantMonitorAutoEnter&);
199   ReentrantMonitorAutoEnter& operator=(const ReentrantMonitorAutoEnter&);
200   static void* operator new(size_t) CPP_THROW_NEW;
201 
202   mozilla::ReentrantMonitor* mReentrantMonitor;
203 };
204 
205 /**
206  * ReentrantMonitorAutoExit
207  * Exit the ReentrantMonitor when it enters scope, and enters it when it leaves
208  * scope.
209  *
210  * MUCH PREFERRED to bare calls to ReentrantMonitor.Exit and Enter.
211  */
212 class MOZ_STACK_CLASS ReentrantMonitorAutoExit
213 {
214 public:
215   /**
216    * Constructor
217    * The constructor releases the given lock.  The destructor
218    * acquires the lock. The lock must be held before constructing
219    * this object!
220    *
221    * @param aReentrantMonitor A valid mozilla::ReentrantMonitor*. It
222    *                 must be already locked.
223    **/
ReentrantMonitorAutoExit(ReentrantMonitor & aReentrantMonitor)224   explicit ReentrantMonitorAutoExit(ReentrantMonitor& aReentrantMonitor)
225     : mReentrantMonitor(&aReentrantMonitor)
226   {
227     NS_ASSERTION(mReentrantMonitor, "null monitor");
228     mReentrantMonitor->AssertCurrentThreadIn();
229     mReentrantMonitor->Exit();
230   }
231 
~ReentrantMonitorAutoExit(void)232   ~ReentrantMonitorAutoExit(void)
233   {
234     mReentrantMonitor->Enter();
235   }
236 
237 private:
238   ReentrantMonitorAutoExit();
239   ReentrantMonitorAutoExit(const ReentrantMonitorAutoExit&);
240   ReentrantMonitorAutoExit& operator=(const ReentrantMonitorAutoExit&);
241   static void* operator new(size_t) CPP_THROW_NEW;
242 
243   ReentrantMonitor* mReentrantMonitor;
244 };
245 
246 } // namespace mozilla
247 
248 
249 #endif // ifndef mozilla_ReentrantMonitor_h
250