Backout 30bfb150da06 (bug 449315) due to unit test timeouts.
[wine-gecko.git] / xpcom / glue / nsAutoLock.h
blobffbf3e2831c84dd88428a6d60d4c79c25a50cdbf
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"
114 * nsAutoLockBase
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;
121 protected:
122 nsAutoLockBase() {}
123 enum nsAutoLockType {eAutoLock, eAutoMonitor, eAutoCMonitor};
125 #ifdef DEBUG
126 nsAutoLockBase(void* addr, nsAutoLockType type);
127 ~nsAutoLockBase();
129 void Show();
130 void Hide();
132 void* mAddr;
133 nsAutoLockBase* mDown;
134 nsAutoLockType mType;
135 #else
136 nsAutoLockBase(void* addr, nsAutoLockType type) {}
137 ~nsAutoLockBase() {}
139 void Show() {}
140 void Hide() {}
141 #endif
145 * nsAutoUnlockBase
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 {
150 protected:
151 nsAutoUnlockBase() {}
153 #ifdef DEBUG
154 nsAutoUnlockBase(void* addr);
155 ~nsAutoUnlockBase();
157 nsAutoLockBase* mLock;
158 #else
159 nsAutoUnlockBase(void* addr) {}
160 ~nsAutoUnlockBase() {}
161 #endif
164 /**
165 * nsAutoLock
166 * Stack-based locking object for PRLock.
168 class NS_COM_GLUE nsAutoLock : public nsAutoLockBase {
169 private:
170 PRLock* mLock;
171 PRBool mLocked;
173 // Not meant to be implemented. This makes it a compiler error to
174 // construct or assign an nsAutoLock object incorrectly.
175 nsAutoLock(void) {}
176 nsAutoLock(nsAutoLock& /*aLock*/) {}
177 nsAutoLock& operator =(nsAutoLock& /*aLock*/) {
178 return *this;
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 {
184 return nsnull;
186 static void operator delete(void* /*memory*/) {}
188 public:
191 * NewLock
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);
204 * Constructor
205 * The constructor aquires the given lock. The destructor
206 * releases the lock.
208 * @param aLock A valid PRLock* returned from the NSPR's
209 * PR_NewLock() function.
211 nsAutoLock(PRLock* aLock)
212 : nsAutoLockBase(aLock, eAutoLock),
213 mLock(aLock),
214 mLocked(PR_TRUE) {
215 PR_ASSERT(mLock);
217 // This will assert deep in the bowels of NSPR if you attempt
218 // to re-enter the lock.
219 PR_Lock(mLock);
222 ~nsAutoLock(void) {
223 if (mLocked)
224 PR_Unlock(mLock);
227 /**
228 * 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.
231 **/
232 void lock() {
233 Show();
234 PR_ASSERT(!mLocked);
235 PR_Lock(mLock);
236 mLocked = PR_TRUE;
240 /**
241 * unlock
242 * Client may call this to release the given lock. Take special
243 * note unlocking an unlocked lock has undefined results.
244 **/
245 void unlock() {
246 PR_ASSERT(mLocked);
247 PR_Unlock(mLock);
248 mLocked = PR_FALSE;
249 Hide();
253 class nsAutoUnlock : private nsAutoUnlockBase
255 private:
256 PRLock *mLock;
258 public:
259 nsAutoUnlock(PRLock *lock) :
260 nsAutoUnlockBase(lock),
261 mLock(lock)
263 PR_Unlock(mLock);
266 ~nsAutoUnlock() {
267 PR_Lock(mLock);
271 #include "prcmon.h"
272 #include "nsError.h"
273 #include "nsDebug.h"
275 class NS_COM_GLUE nsAutoMonitor : public nsAutoLockBase {
276 public:
279 * NewMonitor
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);
291 * Constructor
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");
303 if (mMonitor) {
304 PR_EnterMonitor(mMonitor);
305 mLockCount = 1;
309 ~nsAutoMonitor() {
310 NS_ASSERTION(mMonitor, "null monitor");
311 if (mMonitor && mLockCount) {
312 #ifdef DEBUG
313 PRStatus status =
314 #endif
315 PR_ExitMonitor(mMonitor);
316 NS_ASSERTION(status == PR_SUCCESS, "PR_ExitMonitor failed");
320 /**
321 * Enter
322 * Client may call this to reenter the given monitor.
323 * @see prmon.h
324 **/
325 void Enter();
327 /**
328 * Exit
329 * Client may call this to exit the given monitor.
330 * @see prmon.h
331 **/
332 void Exit();
334 /**
335 * Wait
336 * @see prmon.h
337 **/
338 nsresult Wait(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT) {
339 return PR_Wait(mMonitor, interval) == PR_SUCCESS
340 ? NS_OK : NS_ERROR_FAILURE;
343 /**
344 * Notify
345 * @see prmon.h
346 **/
347 nsresult Notify() {
348 return PR_Notify(mMonitor) == PR_SUCCESS
349 ? NS_OK : NS_ERROR_FAILURE;
352 /**
353 * NotifyAll
354 * @see prmon.h
355 **/
356 nsresult NotifyAll() {
357 return PR_NotifyAll(mMonitor) == PR_SUCCESS
358 ? NS_OK : NS_ERROR_FAILURE;
361 private:
362 PRMonitor* mMonitor;
363 PRInt32 mLockCount;
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*/) {
370 return *this;
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 {
376 return nsnull;
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.)
386 #include "prcmon.h"
387 #include "nsError.h"
389 class NS_COM_GLUE nsAutoCMonitor : public nsAutoLockBase {
390 public:
391 nsAutoCMonitor(void* lockObject)
392 : nsAutoLockBase(lockObject, eAutoCMonitor),
393 mLockObject(lockObject), mLockCount(0)
395 NS_ASSERTION(lockObject, "null lock object");
396 PR_CEnterMonitor(mLockObject);
397 mLockCount = 1;
400 ~nsAutoCMonitor() {
401 if (mLockCount) {
402 #ifdef DEBUG
403 PRStatus status =
404 #endif
405 PR_CExitMonitor(mLockObject);
406 NS_ASSERTION(status == PR_SUCCESS, "PR_CExitMonitor failed");
410 void Enter();
411 void Exit();
413 nsresult Wait(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT) {
414 return PR_CWait(mLockObject, interval) == PR_SUCCESS
415 ? NS_OK : NS_ERROR_FAILURE;
418 nsresult Notify() {
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;
428 private:
429 void* mLockObject;
430 PRInt32 mLockCount;
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*/) {
437 return *this;
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 {
443 return nsnull;
445 static void operator delete(void* /*memory*/) {}
448 #endif // nsAutoLock_h__