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/. */
7 #ifndef mozilla_ReentrantMonitor_h
8 #define mozilla_ReentrantMonitor_h
12 #if defined(MOZILLA_INTERNAL_API) && !defined(DEBUG)
13 # include "mozilla/ProfilerThreadSleep.h"
14 #endif // defined( MOZILLA_INTERNAL_API) && !defined(DEBUG)
16 #include "mozilla/BlockingResourceBase.h"
17 #include "mozilla/ThreadSafety.h"
18 #include "nsISupports.h"
22 // - ReentrantMonitor, a Java-like monitor
23 // - ReentrantMonitorAutoEnter, an RAII class for ensuring that
24 // ReentrantMonitors are properly entered and exited
26 // Using ReentrantMonitorAutoEnter is MUCH preferred to making bare calls to
27 // ReentrantMonitor.Enter and Exit.
34 * When possible, use ReentrantMonitorAutoEnter to hold this monitor within a
35 * scope, instead of calling Enter/Exit directly.
37 class MOZ_CAPABILITY("reentrant monitor") ReentrantMonitor
38 : BlockingResourceBase
{
42 * @param aName A name which can reference this monitor
44 explicit ReentrantMonitor(const char* aName
)
45 : BlockingResourceBase(aName
, eReentrantMonitor
)
51 MOZ_COUNT_CTOR(ReentrantMonitor
);
52 mReentrantMonitor
= PR_NewMonitor();
53 if (!mReentrantMonitor
) {
54 MOZ_CRASH("Can't allocate mozilla::ReentrantMonitor");
62 NS_ASSERTION(mReentrantMonitor
,
63 "improperly constructed ReentrantMonitor or double free");
64 PR_DestroyMonitor(mReentrantMonitor
);
65 mReentrantMonitor
= 0;
66 MOZ_COUNT_DTOR(ReentrantMonitor
);
74 void Enter() MOZ_CAPABILITY_ACQUIRE() { PR_EnterMonitor(mReentrantMonitor
); }
80 void Exit() MOZ_CAPABILITY_RELEASE() { PR_ExitMonitor(mReentrantMonitor
); }
86 nsresult
Wait(PRIntervalTime aInterval
= PR_INTERVAL_NO_TIMEOUT
) {
87 PR_ASSERT_CURRENT_THREAD_IN_MONITOR(mReentrantMonitor
);
88 # ifdef MOZILLA_INTERNAL_API
89 AUTO_PROFILER_THREAD_SLEEP
;
90 # endif // MOZILLA_INTERNAL_API
91 return PR_Wait(mReentrantMonitor
, aInterval
) == PR_SUCCESS
97 void Enter() MOZ_CAPABILITY_ACQUIRE();
98 void Exit() MOZ_CAPABILITY_RELEASE();
99 nsresult
Wait(PRIntervalTime aInterval
= PR_INTERVAL_NO_TIMEOUT
);
101 #endif // ifndef DEBUG
108 return PR_Notify(mReentrantMonitor
) == PR_SUCCESS
? NS_OK
116 nsresult
NotifyAll() {
117 return PR_NotifyAll(mReentrantMonitor
) == PR_SUCCESS
? NS_OK
123 * AssertCurrentThreadIn
126 void AssertCurrentThreadIn() MOZ_ASSERT_CAPABILITY(this) {
127 PR_ASSERT_CURRENT_THREAD_IN_MONITOR(mReentrantMonitor
);
131 * AssertNotCurrentThreadIn
134 void AssertNotCurrentThreadIn() MOZ_ASSERT_CAPABILITY(!this) {
139 void AssertCurrentThreadIn() MOZ_ASSERT_CAPABILITY(this) {}
140 void AssertNotCurrentThreadIn() MOZ_ASSERT_CAPABILITY(!this) {}
142 #endif // ifdef DEBUG
146 ReentrantMonitor(const ReentrantMonitor
&);
147 ReentrantMonitor
& operator=(const ReentrantMonitor
&);
149 PRMonitor
* mReentrantMonitor
;
156 * ReentrantMonitorAutoEnter
157 * Enters the ReentrantMonitor when it enters scope, and exits it when
160 * MUCH PREFERRED to bare calls to ReentrantMonitor.Enter and Exit.
162 class MOZ_SCOPED_CAPABILITY MOZ_STACK_CLASS ReentrantMonitorAutoEnter
{
166 * The constructor aquires the given lock. The destructor
169 * @param aReentrantMonitor A valid mozilla::ReentrantMonitor*.
171 explicit ReentrantMonitorAutoEnter(
172 mozilla::ReentrantMonitor
& aReentrantMonitor
)
173 MOZ_CAPABILITY_ACQUIRE(aReentrantMonitor
)
174 : mReentrantMonitor(&aReentrantMonitor
) {
175 NS_ASSERTION(mReentrantMonitor
, "null monitor");
176 mReentrantMonitor
->Enter();
179 ~ReentrantMonitorAutoEnter(void) MOZ_CAPABILITY_RELEASE() {
180 mReentrantMonitor
->Exit();
183 nsresult
Wait(PRIntervalTime aInterval
= PR_INTERVAL_NO_TIMEOUT
) {
184 return mReentrantMonitor
->Wait(aInterval
);
187 nsresult
Notify() { return mReentrantMonitor
->Notify(); }
188 nsresult
NotifyAll() { return mReentrantMonitor
->NotifyAll(); }
191 ReentrantMonitorAutoEnter();
192 ReentrantMonitorAutoEnter(const ReentrantMonitorAutoEnter
&);
193 ReentrantMonitorAutoEnter
& operator=(const ReentrantMonitorAutoEnter
&);
194 static void* operator new(size_t) noexcept(true);
196 friend class ReentrantMonitorAutoExit
;
198 mozilla::ReentrantMonitor
* mReentrantMonitor
;
202 * ReentrantMonitorAutoExit
203 * Exit the ReentrantMonitor when it enters scope, and enters it when it leaves
206 * MUCH PREFERRED to bare calls to ReentrantMonitor.Exit and Enter.
208 class MOZ_SCOPED_CAPABILITY MOZ_STACK_CLASS ReentrantMonitorAutoExit
{
212 * The constructor releases the given lock. The destructor
213 * acquires the lock. The lock must be held before constructing
216 * @param aReentrantMonitor A valid mozilla::ReentrantMonitor*. It
217 * must be already locked.
219 explicit ReentrantMonitorAutoExit(ReentrantMonitor
& aReentrantMonitor
)
220 MOZ_EXCLUSIVE_RELEASE(aReentrantMonitor
)
221 : mReentrantMonitor(&aReentrantMonitor
) {
222 NS_ASSERTION(mReentrantMonitor
, "null monitor");
223 mReentrantMonitor
->AssertCurrentThreadIn();
224 mReentrantMonitor
->Exit();
227 explicit ReentrantMonitorAutoExit(
228 ReentrantMonitorAutoEnter
& aReentrantMonitorAutoEnter
)
229 MOZ_EXCLUSIVE_RELEASE(aReentrantMonitorAutoEnter
.mReentrantMonitor
)
230 : mReentrantMonitor(aReentrantMonitorAutoEnter
.mReentrantMonitor
) {
231 NS_ASSERTION(mReentrantMonitor
, "null monitor");
232 mReentrantMonitor
->AssertCurrentThreadIn();
233 mReentrantMonitor
->Exit();
236 ~ReentrantMonitorAutoExit(void) MOZ_EXCLUSIVE_RELEASE() {
237 mReentrantMonitor
->Enter();
241 ReentrantMonitorAutoExit();
242 ReentrantMonitorAutoExit(const ReentrantMonitorAutoExit
&);
243 ReentrantMonitorAutoExit
& operator=(const ReentrantMonitorAutoExit
&);
244 static void* operator new(size_t) noexcept(true);
246 ReentrantMonitor
* mReentrantMonitor
;
249 } // namespace mozilla
251 #endif // ifndef mozilla_ReentrantMonitor_h