Merge tracemonkey and mozilla-central. (a=blockers)
[mozilla-central.git] / xpcom / glue / nsAutoLock.h
blob9be70895dca4b869a09de8a857c1320ebd3c57e9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
40 A stack-based lock object that makes using PRLock a bit more
41 convenient. It acquires the monitor when constructed, and releases
42 it when it goes out of scope.
44 For example,
46 class Foo {
47 private:
48 PRLock* mLock;
50 public:
51 Foo(void) {
52 mLock = PR_NewLock();
55 ~Foo(void) {
56 PR_DestroyLock(mLock);
59 void ThreadSafeMethod(void) {
60 // we're don't hold the lock yet...
62 nsAutoLock lock(mLock);
63 // ...but now we do.
65 // we even can do wacky stuff like return from arbitrary places w/o
66 // worrying about forgetting to release the lock
67 if (some_weird_condition)
68 return;
70 // otherwise do some other stuff
73 void ThreadSafeBlockScope(void) {
74 // we're not in the lock here...
77 nsAutoLock lock(mLock);
78 // but we are now, at least until the block scope closes
81 // ...now we're not in the lock anymore
85 A similar stack-based locking object is available for PRMonitor. The
86 major difference is that the PRMonitor must be created and destroyed
87 via the static methods on nsAutoMonitor.
89 For example:
90 Foo::Foo() {
91 mMon = nsAutoMonitor::NewMonitor("FooMonitor");
93 nsresult Foo::MyMethod(...) {
94 nsAutoMonitor mon(mMon);
95 ...
96 // go ahead and do deeply nested returns...
97 return NS_ERROR_FAILURE;
98 ...
99 // or call Wait or Notify...
100 mon.Wait();
102 // cleanup is automatic
106 #ifndef nsAutoLock_h__
107 #define nsAutoLock_h__
109 #include "nscore.h"
110 #include "prlock.h"
111 #include "prlog.h"
112 #include "mozilla/AutoRestore.h"
115 * nsAutoLockBase
116 * This is the base class for the stack-based locking objects.
117 * Clients of derived classes need not play with this superclass.
119 class NS_COM_GLUE NS_STACK_CLASS nsAutoLockBase {
120 friend class nsAutoUnlockBase;
122 protected:
123 nsAutoLockBase() {}
124 enum nsAutoLockType {eAutoLock, eAutoMonitor, eAutoCMonitor};
126 #ifdef DEBUG
127 nsAutoLockBase(void* addr, nsAutoLockType type);
128 ~nsAutoLockBase();
130 void Show();
131 void Hide();
133 void* mAddr;
134 nsAutoLockBase* mDown;
135 nsAutoLockType mType;
136 #else
137 nsAutoLockBase(void* addr, nsAutoLockType type) {}
138 ~nsAutoLockBase() {}
140 void Show() {}
141 void Hide() {}
142 #endif
146 * nsAutoUnlockBase
147 * This is the base class for stack-based unlocking objects.
148 * It unlocks locking objects based on nsAutoLockBase.
150 class NS_COM_GLUE NS_STACK_CLASS nsAutoUnlockBase {
151 protected:
152 nsAutoUnlockBase() {}
154 #ifdef DEBUG
155 nsAutoUnlockBase(void* addr);
156 ~nsAutoUnlockBase();
158 nsAutoLockBase* mLock;
159 #else
160 nsAutoUnlockBase(void* addr) {}
161 ~nsAutoUnlockBase() {}
162 #endif
165 /**
166 * nsAutoLock
167 * Stack-based locking object for PRLock.
169 class NS_COM_GLUE NS_STACK_CLASS nsAutoLock : public nsAutoLockBase {
170 private:
171 PRLock* mLock;
172 PRBool mLocked;
173 MOZILLA_DECL_USE_GUARD_OBJECT_NOTIFIER
175 // Not meant to be implemented. This makes it a compiler error to
176 // construct or assign an nsAutoLock object incorrectly.
177 nsAutoLock(void) {}
178 nsAutoLock(nsAutoLock& /*aLock*/) {}
179 nsAutoLock& operator =(nsAutoLock& /*aLock*/) {
180 return *this;
183 // Not meant to be implemented. This makes it a compiler error to
184 // attempt to create an nsAutoLock object on the heap.
185 static void* operator new(size_t /*size*/) CPP_THROW_NEW {
186 return nsnull;
188 static void operator delete(void* /*memory*/) {}
190 public:
193 * NewLock
194 * Allocates a new PRLock for use with nsAutoLock. name is
195 * not checked for uniqueness.
196 * @param name A name which can reference this lock
197 * @param lock A valid PRLock* that was created by nsAutoLock::NewLock()
198 * @returns nsnull if failure
199 * A valid PRLock* if successful, which must be destroyed
200 * by nsAutoLock::DestroyLock()
202 static PRLock* NewLock(const char* name);
203 static void DestroyLock(PRLock* lock);
206 * Constructor
207 * The constructor aquires the given lock. The destructor
208 * releases the lock.
210 * @param aLock A valid PRLock* returned from the NSPR's
211 * PR_NewLock() function.
213 nsAutoLock(PRLock* aLock MOZILLA_GUARD_OBJECT_NOTIFIER_PARAM)
214 : nsAutoLockBase(aLock, eAutoLock),
215 mLock(aLock),
216 mLocked(PR_TRUE) {
217 MOZILLA_GUARD_OBJECT_NOTIFIER_INIT;
218 PR_ASSERT(mLock);
220 // This will assert deep in the bowels of NSPR if you attempt
221 // to re-enter the lock.
222 PR_Lock(mLock);
225 ~nsAutoLock(void) {
226 if (mLocked)
227 PR_Unlock(mLock);
230 /**
231 * lock
232 * Client may call this to reaquire the given lock. Take special
233 * note that attempting to aquire a locked lock will hang or crash.
234 **/
235 void lock() {
236 Show();
237 PR_ASSERT(!mLocked);
238 PR_Lock(mLock);
239 mLocked = PR_TRUE;
243 /**
244 * unlock
245 * Client may call this to release the given lock. Take special
246 * note unlocking an unlocked lock has undefined results.
247 **/
248 void unlock() {
249 PR_ASSERT(mLocked);
250 PR_Unlock(mLock);
251 mLocked = PR_FALSE;
252 Hide();
256 class NS_STACK_CLASS nsAutoUnlock : private nsAutoUnlockBase
258 private:
259 PRLock *mLock;
260 MOZILLA_DECL_USE_GUARD_OBJECT_NOTIFIER
262 public:
263 nsAutoUnlock(PRLock *lock MOZILLA_GUARD_OBJECT_NOTIFIER_PARAM) :
264 nsAutoUnlockBase(lock),
265 mLock(lock)
267 MOZILLA_GUARD_OBJECT_NOTIFIER_INIT;
268 PR_Unlock(mLock);
271 ~nsAutoUnlock() {
272 PR_Lock(mLock);
276 #include "prcmon.h"
277 #include "nsError.h"
278 #include "nsDebug.h"
280 class NS_COM_GLUE NS_STACK_CLASS nsAutoMonitor : public nsAutoLockBase {
281 public:
284 * NewMonitor
285 * Allocates a new PRMonitor for use with nsAutoMonitor.
286 * @param name A (unique /be?) name which can reference this monitor
287 * @returns nsnull if failure
288 * A valid PRMonitor* is successful while must be destroyed
289 * by nsAutoMonitor::DestroyMonitor()
291 static PRMonitor* NewMonitor(const char* name);
292 static void DestroyMonitor(PRMonitor* mon);
296 * Constructor
297 * The constructor locks the given monitor. During destruction
298 * the monitor will be unlocked.
300 * @param mon A valid PRMonitor* returned from
301 * nsAutoMonitor::NewMonitor().
303 nsAutoMonitor(PRMonitor* mon MOZILLA_GUARD_OBJECT_NOTIFIER_PARAM)
304 : nsAutoLockBase((void*)mon, eAutoMonitor),
305 mMonitor(mon), mLockCount(0)
307 MOZILLA_GUARD_OBJECT_NOTIFIER_INIT;
308 NS_ASSERTION(mMonitor, "null monitor");
309 if (mMonitor) {
310 PR_EnterMonitor(mMonitor);
311 mLockCount = 1;
315 ~nsAutoMonitor() {
316 NS_ASSERTION(mMonitor, "null monitor");
317 if (mMonitor && mLockCount) {
318 #ifdef DEBUG
319 PRStatus status =
320 #endif
321 PR_ExitMonitor(mMonitor);
322 NS_ASSERTION(status == PR_SUCCESS, "PR_ExitMonitor failed");
326 /**
327 * Enter
328 * Client may call this to reenter the given monitor.
329 * @see prmon.h
330 **/
331 void Enter();
333 /**
334 * Exit
335 * Client may call this to exit the given monitor.
336 * @see prmon.h
337 **/
338 void Exit();
340 /**
341 * Wait
342 * @see prmon.h
343 **/
344 nsresult Wait(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT) {
345 return PR_Wait(mMonitor, interval) == PR_SUCCESS
346 ? NS_OK : NS_ERROR_FAILURE;
349 /**
350 * Notify
351 * @see prmon.h
352 **/
353 nsresult Notify() {
354 return PR_Notify(mMonitor) == PR_SUCCESS
355 ? NS_OK : NS_ERROR_FAILURE;
358 /**
359 * NotifyAll
360 * @see prmon.h
361 **/
362 nsresult NotifyAll() {
363 return PR_NotifyAll(mMonitor) == PR_SUCCESS
364 ? NS_OK : NS_ERROR_FAILURE;
367 private:
368 PRMonitor* mMonitor;
369 PRInt32 mLockCount;
370 MOZILLA_DECL_USE_GUARD_OBJECT_NOTIFIER
372 // Not meant to be implemented. This makes it a compiler error to
373 // construct or assign an nsAutoLock object incorrectly.
374 nsAutoMonitor(void) {}
375 nsAutoMonitor(nsAutoMonitor& /*aMon*/) {}
376 nsAutoMonitor& operator =(nsAutoMonitor& /*aMon*/) {
377 return *this;
380 // Not meant to be implemented. This makes it a compiler error to
381 // attempt to create an nsAutoLock object on the heap.
382 static void* operator new(size_t /*size*/) CPP_THROW_NEW {
383 return nsnull;
385 static void operator delete(void* /*memory*/) {}
388 ////////////////////////////////////////////////////////////////////////////////
389 // Once again, this time with a cache...
390 // (Using this avoids the need to allocate a PRMonitor, which may be useful when
391 // a large number of objects of the same class need associated monitors.)
393 #include "prcmon.h"
394 #include "nsError.h"
396 class NS_COM_GLUE NS_STACK_CLASS nsAutoCMonitor : public nsAutoLockBase {
397 public:
398 nsAutoCMonitor(void* lockObject MOZILLA_GUARD_OBJECT_NOTIFIER_PARAM)
399 : nsAutoLockBase(lockObject, eAutoCMonitor),
400 mLockObject(lockObject), mLockCount(0)
402 MOZILLA_GUARD_OBJECT_NOTIFIER_INIT;
403 NS_ASSERTION(lockObject, "null lock object");
404 PR_CEnterMonitor(mLockObject);
405 mLockCount = 1;
408 ~nsAutoCMonitor() {
409 if (mLockCount) {
410 #ifdef DEBUG
411 PRStatus status =
412 #endif
413 PR_CExitMonitor(mLockObject);
414 NS_ASSERTION(status == PR_SUCCESS, "PR_CExitMonitor failed");
418 void Enter();
419 void Exit();
421 nsresult Wait(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT) {
422 return PR_CWait(mLockObject, interval) == PR_SUCCESS
423 ? NS_OK : NS_ERROR_FAILURE;
426 nsresult Notify() {
427 return PR_CNotify(mLockObject) == PR_SUCCESS
428 ? NS_OK : NS_ERROR_FAILURE;
431 nsresult NotifyAll() {
432 return PR_CNotifyAll(mLockObject) == PR_SUCCESS
433 ? NS_OK : NS_ERROR_FAILURE;
436 private:
437 void* mLockObject;
438 PRInt32 mLockCount;
439 MOZILLA_DECL_USE_GUARD_OBJECT_NOTIFIER
441 // Not meant to be implemented. This makes it a compiler error to
442 // construct or assign an nsAutoLock object incorrectly.
443 nsAutoCMonitor(void) {}
444 nsAutoCMonitor(nsAutoCMonitor& /*aMon*/) {}
445 nsAutoCMonitor& operator =(nsAutoCMonitor& /*aMon*/) {
446 return *this;
449 // Not meant to be implemented. This makes it a compiler error to
450 // attempt to create an nsAutoLock object on the heap.
451 static void* operator new(size_t /*size*/) CPP_THROW_NEW {
452 return nsnull;
454 static void operator delete(void* /*memory*/) {}
457 #endif // nsAutoLock_h__