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
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.
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.
56 PR_DestroyLock(mLock);
59 void ThreadSafeMethod(void) {
60 // we're don't hold the lock yet...
62 nsAutoLock lock(mLock);
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)
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.
91 mMon = nsAutoMonitor::NewMonitor("FooMonitor");
93 nsresult Foo::MyMethod(...) {
94 nsAutoMonitor mon(mMon);
96 // go ahead and do deeply nested returns...
97 return NS_ERROR_FAILURE;
99 // or call Wait or Notify...
102 // cleanup is automatic
106 #ifndef nsAutoLock_h__
107 #define nsAutoLock_h__
115 * This is the base class for the stack-based locking objects.
116 * Clients of derived classes need not play with this superclass.
118 class NS_COM_GLUE nsAutoLockBase
{
119 friend class nsAutoUnlockBase
;
123 enum nsAutoLockType
{eAutoLock
, eAutoMonitor
, eAutoCMonitor
};
126 nsAutoLockBase(void* addr
, nsAutoLockType type
);
133 nsAutoLockBase
* mDown
;
134 nsAutoLockType mType
;
136 nsAutoLockBase(void* addr
, nsAutoLockType type
) {}
146 * This is the base class for stack-based unlocking objects.
147 * It unlocks locking objects based on nsAutoLockBase.
149 class NS_COM_GLUE nsAutoUnlockBase
{
151 nsAutoUnlockBase() {}
154 nsAutoUnlockBase(void* addr
);
157 nsAutoLockBase
* mLock
;
159 nsAutoUnlockBase(void* addr
) {}
160 ~nsAutoUnlockBase() {}
166 * Stack-based locking object for PRLock.
168 class NS_COM_GLUE nsAutoLock
: public nsAutoLockBase
{
173 // Not meant to be implemented. This makes it a compiler error to
174 // construct or assign an nsAutoLock object incorrectly.
176 nsAutoLock(nsAutoLock
& /*aLock*/) {}
177 nsAutoLock
& operator =(nsAutoLock
& /*aLock*/) {
181 // Not meant to be implemented. This makes it a compiler error to
182 // attempt to create an nsAutoLock object on the heap.
183 static void* operator new(size_t /*size*/) CPP_THROW_NEW
{
186 static void operator delete(void* /*memory*/) {}
192 * Allocates a new PRLock for use with nsAutoLock. name is
193 * not checked for uniqueness.
194 * @param name A name which can reference this lock
195 * @param lock A valid PRLock* that was created by nsAutoLock::NewLock()
196 * @returns nsnull if failure
197 * A valid PRLock* if successful, which must be destroyed
198 * by nsAutoLock::DestroyLock()
200 static PRLock
* NewLock(const char* name
);
201 static void DestroyLock(PRLock
* lock
);
205 * The constructor aquires the given lock. The destructor
208 * @param aLock A valid PRLock* returned from the NSPR's
209 * PR_NewLock() function.
211 nsAutoLock(PRLock
* aLock
)
212 : nsAutoLockBase(aLock
, eAutoLock
),
217 // This will assert deep in the bowels of NSPR if you attempt
218 // to re-enter the lock.
229 * Client may call this to reaquire the given lock. Take special
230 * note that attempting to aquire a locked lock will hang or crash.
242 * Client may call this to release the given lock. Take special
243 * note unlocking an unlocked lock has undefined results.
253 class nsAutoUnlock
: private nsAutoUnlockBase
259 nsAutoUnlock(PRLock
*lock
) :
260 nsAutoUnlockBase(lock
),
275 class NS_COM_GLUE nsAutoMonitor
: public nsAutoLockBase
{
280 * Allocates a new PRMonitor for use with nsAutoMonitor.
281 * @param name A (unique /be?) name which can reference this monitor
282 * @returns nsnull if failure
283 * A valid PRMonitor* is successful while must be destroyed
284 * by nsAutoMonitor::DestroyMonitor()
286 static PRMonitor
* NewMonitor(const char* name
);
287 static void DestroyMonitor(PRMonitor
* mon
);
292 * The constructor locks the given monitor. During destruction
293 * the monitor will be unlocked.
295 * @param mon A valid PRMonitor* returned from
296 * nsAutoMonitor::NewMonitor().
298 nsAutoMonitor(PRMonitor
* mon
)
299 : nsAutoLockBase((void*)mon
, eAutoMonitor
),
300 mMonitor(mon
), mLockCount(0)
302 NS_ASSERTION(mMonitor
, "null monitor");
304 PR_EnterMonitor(mMonitor
);
310 NS_ASSERTION(mMonitor
, "null monitor");
311 if (mMonitor
&& mLockCount
) {
315 PR_ExitMonitor(mMonitor
);
316 NS_ASSERTION(status
== PR_SUCCESS
, "PR_ExitMonitor failed");
322 * Client may call this to reenter the given monitor.
329 * Client may call this to exit the given monitor.
338 nsresult
Wait(PRIntervalTime interval
= PR_INTERVAL_NO_TIMEOUT
) {
339 return PR_Wait(mMonitor
, interval
) == PR_SUCCESS
340 ? NS_OK
: NS_ERROR_FAILURE
;
348 return PR_Notify(mMonitor
) == PR_SUCCESS
349 ? NS_OK
: NS_ERROR_FAILURE
;
356 nsresult
NotifyAll() {
357 return PR_NotifyAll(mMonitor
) == PR_SUCCESS
358 ? NS_OK
: NS_ERROR_FAILURE
;
365 // Not meant to be implemented. This makes it a compiler error to
366 // construct or assign an nsAutoLock object incorrectly.
367 nsAutoMonitor(void) {}
368 nsAutoMonitor(nsAutoMonitor
& /*aMon*/) {}
369 nsAutoMonitor
& operator =(nsAutoMonitor
& /*aMon*/) {
373 // Not meant to be implemented. This makes it a compiler error to
374 // attempt to create an nsAutoLock object on the heap.
375 static void* operator new(size_t /*size*/) CPP_THROW_NEW
{
378 static void operator delete(void* /*memory*/) {}
381 ////////////////////////////////////////////////////////////////////////////////
382 // Once again, this time with a cache...
383 // (Using this avoids the need to allocate a PRMonitor, which may be useful when
384 // a large number of objects of the same class need associated monitors.)
389 class NS_COM_GLUE nsAutoCMonitor
: public nsAutoLockBase
{
391 nsAutoCMonitor(void* lockObject
)
392 : nsAutoLockBase(lockObject
, eAutoCMonitor
),
393 mLockObject(lockObject
), mLockCount(0)
395 NS_ASSERTION(lockObject
, "null lock object");
396 PR_CEnterMonitor(mLockObject
);
405 PR_CExitMonitor(mLockObject
);
406 NS_ASSERTION(status
== PR_SUCCESS
, "PR_CExitMonitor failed");
413 nsresult
Wait(PRIntervalTime interval
= PR_INTERVAL_NO_TIMEOUT
) {
414 return PR_CWait(mLockObject
, interval
) == PR_SUCCESS
415 ? NS_OK
: NS_ERROR_FAILURE
;
419 return PR_CNotify(mLockObject
) == PR_SUCCESS
420 ? NS_OK
: NS_ERROR_FAILURE
;
423 nsresult
NotifyAll() {
424 return PR_CNotifyAll(mLockObject
) == PR_SUCCESS
425 ? NS_OK
: NS_ERROR_FAILURE
;
432 // Not meant to be implemented. This makes it a compiler error to
433 // construct or assign an nsAutoLock object incorrectly.
434 nsAutoCMonitor(void) {}
435 nsAutoCMonitor(nsAutoCMonitor
& /*aMon*/) {}
436 nsAutoCMonitor
& operator =(nsAutoCMonitor
& /*aMon*/) {
440 // Not meant to be implemented. This makes it a compiler error to
441 // attempt to create an nsAutoLock object on the heap.
442 static void* operator new(size_t /*size*/) CPP_THROW_NEW
{
445 static void operator delete(void* /*memory*/) {}
448 #endif // nsAutoLock_h__