VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/threads/nsAutoLock.h@ 101916

Last change on this file since 101916 was 101916, checked in by vboxsync, 19 months ago

libs/xpcom: Add the possibility to use IPRT RTSEMFASTMUTEX semaphores in nsAutoLock so we can convert code to IPRT, remove some debug only code which would make it more complicated, bugref:10545 [fixes]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.6 KB
Line 
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
4 *
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/
9 *
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.
14 *
15 * The Original Code is mozilla.org code.
16 *
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.
21 *
22 * Contributor(s):
23 *
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.
35 *
36 * ***** END LICENSE BLOCK ***** */
37
38
39/*
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.
43
44 For example,
45
46 class Foo {
47 private:
48 PRLock* mLock;
49
50 public:
51 Foo(void) {
52 mLock = PR_NewLock();
53 }
54
55 ~Foo(void) {
56 PR_DestroyLock(mLock);
57 }
58
59 void ThreadSafeMethod(void) {
60 // we're don't hold the lock yet...
61
62 nsAutoLock lock(mLock);
63 // ...but now we do.
64
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;
69
70 // otherwise do some other stuff
71 }
72
73 void ThreadSafeBlockScope(void) {
74 // we're not in the lock here...
75
76 {
77 nsAutoLock lock(mLock);
78 // but we are now, at least until the block scope closes
79 }
80
81 // ...now we're not in the lock anymore
82 }
83 };
84
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.
88
89 For example:
90 Foo::Foo() {
91 mMon = nsAutoMonitor::NewMonitor("FooMonitor");
92 }
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();
101 ...
102 // cleanup is automatic
103 }
104 */
105
106#ifndef nsAutoLock_h__
107#define nsAutoLock_h__
108
109#include "nscore.h"
110#include "prlock.h"
111#include "prlog.h"
112
113#include <iprt/assert.h>
114#include <iprt/errcore.h>
115#include <iprt/semaphore.h>
116
117/**
118 * nsAutoLockBase
119 * This is the base class for the stack-based locking objects.
120 * Clients of derived classes need not play with this superclass.
121 **/
122class NS_COM nsAutoLockBase {
123protected:
124 nsAutoLockBase() {}
125 enum nsAutoLockType {eAutoLock, eAutoMonitor, eAutoCMonitor};
126
127 nsAutoLockBase(void* addr, nsAutoLockType type) {}
128 ~nsAutoLockBase() {}
129};
130
131/**
132 * nsAutoLock
133 * Stack-based locking object for PRLock.
134 **/
135class NS_COM nsAutoLock : public nsAutoLockBase {
136private:
137 PRLock* mLock;
138 /** The IPRT fast mutex. */
139 RTSEMFASTMUTEX m_hMtx;
140 PRBool mLocked;
141
142 // Not meant to be implemented. This makes it a compiler error to
143 // construct or assign an nsAutoLock object incorrectly.
144 nsAutoLock(void);
145 nsAutoLock(const nsAutoLock& /*aLock*/);
146 nsAutoLock& operator =(const nsAutoLock& /*aLock*/);
147
148 // Not meant to be implemented. This makes it a compiler error to
149 // attempt to create an nsAutoLock object on the heap.
150 static void* operator new(size_t /*size*/) CPP_THROW_NEW;
151 static void operator delete(void* /*memory*/);
152
153public:
154 /**
155 * Constructor
156 * The constructor aquires the given lock. The destructor
157 * releases the lock.
158 *
159 * @param aLock A valid PRLock* returned from the NSPR's
160 * PR_NewLock() function.
161 **/
162 nsAutoLock(PRLock* aLock)
163 : nsAutoLockBase(aLock, eAutoLock),
164 mLock(aLock),
165 m_hMtx(NIL_RTSEMFASTMUTEX),
166 mLocked(PR_TRUE) {
167 Assert(mLock);
168
169 // This will assert deep in the bowels of NSPR if you attempt
170 // to re-enter the lock.
171 PR_Lock(mLock);
172 }
173
174 nsAutoLock(RTSEMFASTMUTEX hMtx)
175 : nsAutoLockBase(hMtx, eAutoLock),
176 mLock(NULL),
177 m_hMtx(hMtx),
178 mLocked(PR_TRUE) {
179 Assert(hMtx != NIL_RTSEMFASTMUTEX);
180
181 RTSemFastMutexRequest(m_hMtx);
182 }
183
184 ~nsAutoLock(void) {
185 if (mLocked)
186 {
187 if (m_hMtx != NIL_RTSEMFASTMUTEX)
188 RTSemFastMutexRelease(m_hMtx);
189 else
190 PR_Unlock(mLock);
191 }
192 }
193
194 /**
195 * lock
196 * Client may call this to reaquire the given lock. Take special
197 * note that attempting to aquire a locked lock will hang or crash.
198 **/
199 void lock() {
200 PR_ASSERT(!mLocked);
201 if (m_hMtx != NIL_RTSEMFASTMUTEX)
202 RTSemFastMutexRequest(m_hMtx);
203 else
204 PR_Lock(mLock);
205 mLocked = PR_TRUE;
206 }
207
208
209 /**
210 * unlock
211 * Client may call this to release the given lock. Take special
212 * note unlocking an unlocked lock has undefined results.
213 **/
214 void unlock() {
215 PR_ASSERT(mLocked);
216 if (m_hMtx != NIL_RTSEMFASTMUTEX)
217 RTSemFastMutexRelease(m_hMtx);
218 else
219 PR_Unlock(mLock);
220 mLocked = PR_FALSE;
221 }
222};
223
224#include "prmon.h"
225#include "nsError.h"
226
227class NS_COM nsAutoMonitor : public nsAutoLockBase {
228public:
229
230 /**
231 * NewMonitor
232 * Allocates a new PRMonitor for use with nsAutoMonitor.
233 * @param name A (unique /be?) name which can reference this monitor
234 * @returns nsnull if failure
235 * A valid PRMonitor* is successful while must be destroyed
236 * by nsAutoMonitor::DestroyMonitor()
237 **/
238 static PRMonitor* NewMonitor(const char* name);
239 static void DestroyMonitor(PRMonitor* mon);
240
241
242 /**
243 * Constructor
244 * The constructor locks the given monitor. During destruction
245 * the monitor will be unlocked.
246 *
247 * @param mon A valid PRMonitor* returned from
248 * nsAutoMonitor::NewMonitor().
249 **/
250 nsAutoMonitor(PRMonitor* mon)
251 : nsAutoLockBase((void*)mon, eAutoMonitor),
252 mMonitor(mon), mLockCount(0)
253 {
254 AssertMsg(mMonitor, ("null monitor"));
255 if (mMonitor) {
256 PR_EnterMonitor(mMonitor);
257 mLockCount = 1;
258 }
259 }
260
261 ~nsAutoMonitor() {
262 AssertMsg(mMonitor, ("null monitor"));
263 if (mMonitor && mLockCount) {
264 PR_ExitMonitor(mMonitor);
265 }
266 }
267
268 /**
269 * Enter
270 * Client may call this to reenter the given monitor.
271 * @see prmon.h
272 **/
273 void Enter();
274
275 /**
276 * Exit
277 * Client may call this to exit the given monitor.
278 * @see prmon.h
279 **/
280 void Exit();
281
282 /**
283 * Wait
284 * @see prmon.h
285 **/
286 nsresult Wait(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT) {
287 return PR_Wait(mMonitor, interval) == PR_SUCCESS
288 ? NS_OK : NS_ERROR_FAILURE;
289 }
290
291 /**
292 * Notify
293 * @see prmon.h
294 **/
295 nsresult Notify() {
296 return PR_Notify(mMonitor) == PR_SUCCESS
297 ? NS_OK : NS_ERROR_FAILURE;
298 }
299
300 /**
301 * NotifyAll
302 * @see prmon.h
303 **/
304 nsresult NotifyAll() {
305 return PR_NotifyAll(mMonitor) == PR_SUCCESS
306 ? NS_OK : NS_ERROR_FAILURE;
307 }
308
309private:
310 PRMonitor* mMonitor;
311 PRInt32 mLockCount;
312
313 // Not meant to be implemented. This makes it a compiler error to
314 // construct or assign an nsAutoLock object incorrectly.
315 nsAutoMonitor(void);
316 nsAutoMonitor(const nsAutoMonitor& /*aMon*/);
317 nsAutoMonitor& operator =(const nsAutoMonitor& /*aMon*/);
318
319 // Not meant to be implemented. This makes it a compiler error to
320 // attempt to create an nsAutoLock object on the heap.
321 static void* operator new(size_t /*size*/) CPP_THROW_NEW;
322 static void operator delete(void* /*memory*/);
323};
324
325
326/**
327 * Cut down version of the nsAutoMonitor where the passed monitor can be NULL.
328 * Used in exactly one place because the regular nsAutoMonitor would assert in that place
329 * during shutdown (see nsComponentManager::NS_GetServiceManager for an explanation while
330 * the assertion is nothing to orry about actually).
331 */
332class NS_COM nsAutoMonitorCanBeNull : public nsAutoLockBase {
333public:
334
335
336 /**
337 * Constructor
338 * The constructor locks the given monitor. During destruction
339 * the monitor will be unlocked.
340 *
341 * @param mon A valid PRMonitor* returned from
342 * nsAutoMonitor::NewMonitor().
343 **/
344 nsAutoMonitorCanBeNull(PRMonitor* mon)
345 : nsAutoLockBase((void*)mon, eAutoMonitor),
346 mMonitor(mon), mLockCount(0)
347 {
348 if (mMonitor) {
349 PR_EnterMonitor(mMonitor);
350 mLockCount = 1;
351 }
352 }
353
354 ~nsAutoMonitorCanBeNull() {
355 if (mMonitor && mLockCount) {
356 PR_ExitMonitor(mMonitor);
357 }
358 }
359
360private:
361 PRMonitor* mMonitor;
362 PRInt32 mLockCount;
363
364 // Not meant to be implemented. This makes it a compiler error to
365 // construct or assign an nsAutoLock object incorrectly.
366 nsAutoMonitorCanBeNull(void);
367 nsAutoMonitorCanBeNull(const nsAutoMonitorCanBeNull& /*aMon*/);
368 nsAutoMonitorCanBeNull& operator =(const nsAutoMonitorCanBeNull& /*aMon*/);
369
370 // Not meant to be implemented. This makes it a compiler error to
371 // attempt to create an nsAutoLock object on the heap.
372 static void* operator new(size_t /*size*/) CPP_THROW_NEW;
373 static void operator delete(void* /*memory*/);
374};
375
376#endif // nsAutoLock_h__
377
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette