VirtualBox

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

Last change on this file since 101914 was 101914, checked in by vboxsync, 17 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

  • 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/semaphore.h>
115
116/**
117 * nsAutoLockBase
118 * This is the base class for the stack-based locking objects.
119 * Clients of derived classes need not play with this superclass.
120 **/
121class NS_COM nsAutoLockBase {
122protected:
123 nsAutoLockBase() {}
124 enum nsAutoLockType {eAutoLock, eAutoMonitor, eAutoCMonitor};
125
126 nsAutoLockBase(void* addr, nsAutoLockType type) {}
127 ~nsAutoLockBase() {}
128};
129
130/**
131 * nsAutoLock
132 * Stack-based locking object for PRLock.
133 **/
134class NS_COM nsAutoLock : public nsAutoLockBase {
135private:
136 PRLock* mLock;
137 /** The IPRT fast mutex. */
138 RTSEMFASTMUTEX m_hMtx;
139 PRBool mLocked;
140
141 // Not meant to be implemented. This makes it a compiler error to
142 // construct or assign an nsAutoLock object incorrectly.
143 nsAutoLock(void);
144 nsAutoLock(const nsAutoLock& /*aLock*/);
145 nsAutoLock& operator =(const nsAutoLock& /*aLock*/);
146
147 // Not meant to be implemented. This makes it a compiler error to
148 // attempt to create an nsAutoLock object on the heap.
149 static void* operator new(size_t /*size*/) CPP_THROW_NEW;
150 static void operator delete(void* /*memory*/);
151
152public:
153 /**
154 * Constructor
155 * The constructor aquires the given lock. The destructor
156 * releases the lock.
157 *
158 * @param aLock A valid PRLock* returned from the NSPR's
159 * PR_NewLock() function.
160 **/
161 nsAutoLock(PRLock* aLock)
162 : nsAutoLockBase(aLock, eAutoLock),
163 mLock(aLock),
164 m_hMtx(NIL_RTSEMFASTMUTEX),
165 mLocked(PR_TRUE) {
166 PR_ASSERT(mLock);
167
168 // This will assert deep in the bowels of NSPR if you attempt
169 // to re-enter the lock.
170 PR_Lock(mLock);
171 }
172
173 nsAutoLock(RTSEMFASTMUTEX hMtx)
174 : nsAutoLockBase(hMtx, eAutoLock),
175 mLock(NULL),
176 m_hMtx(hMtx),
177 mLocked(PR_TRUE) {
178 PR_ASSERT(mLock);
179
180 RTSemFastMutexRequest(m_hMtx);
181 }
182
183 ~nsAutoLock(void) {
184 if (mLocked)
185 {
186 if (m_hMtx != NIL_RTSEMFASTMUTEX)
187 RTSemFastMutexRelease(m_hMtx);
188 else
189 PR_Unlock(mLock);
190 }
191 }
192
193 /**
194 * lock
195 * Client may call this to reaquire the given lock. Take special
196 * note that attempting to aquire a locked lock will hang or crash.
197 **/
198 void lock() {
199 PR_ASSERT(!mLocked);
200 if (m_hMtx != NIL_RTSEMFASTMUTEX)
201 RTSemFastMutexRequest(m_hMtx);
202 else
203 PR_Lock(mLock);
204 mLocked = PR_TRUE;
205 }
206
207
208 /**
209 * unlock
210 * Client may call this to release the given lock. Take special
211 * note unlocking an unlocked lock has undefined results.
212 **/
213 void unlock() {
214 PR_ASSERT(mLocked);
215 if (m_hMtx != NIL_RTSEMFASTMUTEX)
216 RTSemFastMutexRelease(m_hMtx);
217 else
218 PR_Unlock(mLock);
219 mLocked = PR_FALSE;
220 }
221};
222
223#include "prmon.h"
224#include "nsError.h"
225
226class NS_COM nsAutoMonitor : public nsAutoLockBase {
227public:
228
229 /**
230 * NewMonitor
231 * Allocates a new PRMonitor for use with nsAutoMonitor.
232 * @param name A (unique /be?) name which can reference this monitor
233 * @returns nsnull if failure
234 * A valid PRMonitor* is successful while must be destroyed
235 * by nsAutoMonitor::DestroyMonitor()
236 **/
237 static PRMonitor* NewMonitor(const char* name);
238 static void DestroyMonitor(PRMonitor* mon);
239
240
241 /**
242 * Constructor
243 * The constructor locks the given monitor. During destruction
244 * the monitor will be unlocked.
245 *
246 * @param mon A valid PRMonitor* returned from
247 * nsAutoMonitor::NewMonitor().
248 **/
249 nsAutoMonitor(PRMonitor* mon)
250 : nsAutoLockBase((void*)mon, eAutoMonitor),
251 mMonitor(mon), mLockCount(0)
252 {
253 AssertMsg(mMonitor, ("null monitor"));
254 if (mMonitor) {
255 PR_EnterMonitor(mMonitor);
256 mLockCount = 1;
257 }
258 }
259
260 ~nsAutoMonitor() {
261 AssertMsg(mMonitor, ("null monitor"));
262 if (mMonitor && mLockCount) {
263 PR_ExitMonitor(mMonitor);
264 }
265 }
266
267 /**
268 * Enter
269 * Client may call this to reenter the given monitor.
270 * @see prmon.h
271 **/
272 void Enter();
273
274 /**
275 * Exit
276 * Client may call this to exit the given monitor.
277 * @see prmon.h
278 **/
279 void Exit();
280
281 /**
282 * Wait
283 * @see prmon.h
284 **/
285 nsresult Wait(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT) {
286 return PR_Wait(mMonitor, interval) == PR_SUCCESS
287 ? NS_OK : NS_ERROR_FAILURE;
288 }
289
290 /**
291 * Notify
292 * @see prmon.h
293 **/
294 nsresult Notify() {
295 return PR_Notify(mMonitor) == PR_SUCCESS
296 ? NS_OK : NS_ERROR_FAILURE;
297 }
298
299 /**
300 * NotifyAll
301 * @see prmon.h
302 **/
303 nsresult NotifyAll() {
304 return PR_NotifyAll(mMonitor) == PR_SUCCESS
305 ? NS_OK : NS_ERROR_FAILURE;
306 }
307
308private:
309 PRMonitor* mMonitor;
310 PRInt32 mLockCount;
311
312 // Not meant to be implemented. This makes it a compiler error to
313 // construct or assign an nsAutoLock object incorrectly.
314 nsAutoMonitor(void);
315 nsAutoMonitor(const nsAutoMonitor& /*aMon*/);
316 nsAutoMonitor& operator =(const nsAutoMonitor& /*aMon*/);
317
318 // Not meant to be implemented. This makes it a compiler error to
319 // attempt to create an nsAutoLock object on the heap.
320 static void* operator new(size_t /*size*/) CPP_THROW_NEW;
321 static void operator delete(void* /*memory*/);
322};
323
324
325/**
326 * Cut down version of the nsAutoMonitor where the passed monitor can be NULL.
327 * Used in exactly one place because the regular nsAutoMonitor would assert in that place
328 * during shutdown (see nsComponentManager::NS_GetServiceManager for an explanation while
329 * the assertion is nothing to orry about actually).
330 */
331class NS_COM nsAutoMonitorCanBeNull : public nsAutoLockBase {
332public:
333
334
335 /**
336 * Constructor
337 * The constructor locks the given monitor. During destruction
338 * the monitor will be unlocked.
339 *
340 * @param mon A valid PRMonitor* returned from
341 * nsAutoMonitor::NewMonitor().
342 **/
343 nsAutoMonitorCanBeNull(PRMonitor* mon)
344 : nsAutoLockBase((void*)mon, eAutoMonitor),
345 mMonitor(mon), mLockCount(0)
346 {
347 if (mMonitor) {
348 PR_EnterMonitor(mMonitor);
349 mLockCount = 1;
350 }
351 }
352
353 ~nsAutoMonitorCanBeNull() {
354 if (mMonitor && mLockCount) {
355 PR_ExitMonitor(mMonitor);
356 }
357 }
358
359private:
360 PRMonitor* mMonitor;
361 PRInt32 mLockCount;
362
363 // Not meant to be implemented. This makes it a compiler error to
364 // construct or assign an nsAutoLock object incorrectly.
365 nsAutoMonitorCanBeNull(void);
366 nsAutoMonitorCanBeNull(const nsAutoMonitorCanBeNull& /*aMon*/);
367 nsAutoMonitorCanBeNull& operator =(const nsAutoMonitorCanBeNull& /*aMon*/);
368
369 // Not meant to be implemented. This makes it a compiler error to
370 // attempt to create an nsAutoLock object on the heap.
371 static void* operator new(size_t /*size*/) CPP_THROW_NEW;
372 static void operator delete(void* /*memory*/);
373};
374
375#endif // nsAutoLock_h__
376
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