/gecko_api/include/nsAutoLock.h
C++ Header | 449 lines | 195 code | 54 blank | 200 comment | 13 complexity | a320ed5672f0bbee8cebd52641da21f0 MD5 | raw file
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/** 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. 117 **/ 118class NS_COM_GLUE nsAutoLockBase { 119 friend class nsAutoUnlockBase; 120 121protected: 122 nsAutoLockBase() {} 123 enum nsAutoLockType {eAutoLock, eAutoMonitor, eAutoCMonitor}; 124 125#ifdef DEBUG 126 nsAutoLockBase(void* addr, nsAutoLockType type); 127 ~nsAutoLockBase(); 128 129 void Show(); 130 void Hide(); 131 132 void* mAddr; 133 nsAutoLockBase* mDown; 134 nsAutoLockType mType; 135#else 136 nsAutoLockBase(void* addr, nsAutoLockType type) {} 137 ~nsAutoLockBase() {} 138 139 void Show() {} 140 void Hide() {} 141#endif 142}; 143 144/** 145 * nsAutoUnlockBase 146 * This is the base class for stack-based unlocking objects. 147 * It unlocks locking objects based on nsAutoLockBase. 148 **/ 149class NS_COM_GLUE nsAutoUnlockBase { 150protected: 151 nsAutoUnlockBase() {} 152 153#ifdef DEBUG 154 nsAutoUnlockBase(void* addr); 155 ~nsAutoUnlockBase(); 156 157 nsAutoLockBase* mLock; 158#else 159 nsAutoUnlockBase(void* addr) {} 160 ~nsAutoUnlockBase() {} 161#endif 162}; 163 164/** 165 * nsAutoLock 166 * Stack-based locking object for PRLock. 167 **/ 168class NS_COM_GLUE nsAutoLock : public nsAutoLockBase { 169private: 170 PRLock* mLock; 171 PRBool mLocked; 172 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; 179 } 180 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; 185 } 186 static void operator delete(void* /*memory*/) {} 187 188public: 189 190 /** 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() 199 **/ 200 static PRLock* NewLock(const char* name); 201 static void DestroyLock(PRLock* lock); 202 203 /** 204 * Constructor 205 * The constructor aquires the given lock. The destructor 206 * releases the lock. 207 * 208 * @param aLock A valid PRLock* returned from the NSPR's 209 * PR_NewLock() function. 210 **/ 211 nsAutoLock(PRLock* aLock) 212 : nsAutoLockBase(aLock, eAutoLock), 213 mLock(aLock), 214 mLocked(PR_TRUE) { 215 PR_ASSERT(mLock); 216 217 // This will assert deep in the bowels of NSPR if you attempt 218 // to re-enter the lock. 219 PR_Lock(mLock); 220 } 221 222 ~nsAutoLock(void) { 223 if (mLocked) 224 PR_Unlock(mLock); 225 } 226 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; 237 } 238 239 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(); 250 } 251}; 252 253class nsAutoUnlock : nsAutoUnlockBase 254{ 255private: 256 PRLock *mLock; 257 258public: 259 nsAutoUnlock(PRLock *lock) : 260 nsAutoUnlockBase(lock), 261 mLock(lock) 262 { 263 PR_Unlock(mLock); 264 } 265 266 ~nsAutoUnlock() { 267 PR_Lock(mLock); 268 } 269}; 270 271#include "prcmon.h" 272#include "nsError.h" 273#include "nsDebug.h" 274 275class NS_COM_GLUE nsAutoMonitor : public nsAutoLockBase { 276public: 277 278 /** 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() 285 **/ 286 static PRMonitor* NewMonitor(const char* name); 287 static void DestroyMonitor(PRMonitor* mon); 288 289 290 /** 291 * Constructor 292 * The constructor locks the given monitor. During destruction 293 * the monitor will be unlocked. 294 * 295 * @param mon A valid PRMonitor* returned from 296 * nsAutoMonitor::NewMonitor(). 297 **/ 298 nsAutoMonitor(PRMonitor* mon) 299 : nsAutoLockBase((void*)mon, eAutoMonitor), 300 mMonitor(mon), mLockCount(0) 301 { 302 NS_ASSERTION(mMonitor, "null monitor"); 303 if (mMonitor) { 304 PR_EnterMonitor(mMonitor); 305 mLockCount = 1; 306 } 307 } 308 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"); 317 } 318 } 319 320 /** 321 * Enter 322 * Client may call this to reenter the given monitor. 323 * @see prmon.h 324 **/ 325 void Enter(); 326 327 /** 328 * Exit 329 * Client may call this to exit the given monitor. 330 * @see prmon.h 331 **/ 332 void Exit(); 333 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; 341 } 342 343 /** 344 * Notify 345 * @see prmon.h 346 **/ 347 nsresult Notify() { 348 return PR_Notify(mMonitor) == PR_SUCCESS 349 ? NS_OK : NS_ERROR_FAILURE; 350 } 351 352 /** 353 * NotifyAll 354 * @see prmon.h 355 **/ 356 nsresult NotifyAll() { 357 return PR_NotifyAll(mMonitor) == PR_SUCCESS 358 ? NS_OK : NS_ERROR_FAILURE; 359 } 360 361private: 362 PRMonitor* mMonitor; 363 PRInt32 mLockCount; 364 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; 371 } 372 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; 377 } 378 static void operator delete(void* /*memory*/) {} 379}; 380 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.) 385 386#include "prcmon.h" 387#include "nsError.h" 388 389class NS_COM_GLUE nsAutoCMonitor : public nsAutoLockBase { 390public: 391 nsAutoCMonitor(void* lockObject) 392 : nsAutoLockBase(lockObject, eAutoCMonitor), 393 mLockObject(lockObject), mLockCount(0) 394 { 395 NS_ASSERTION(lockObject, "null lock object"); 396 PR_CEnterMonitor(mLockObject); 397 mLockCount = 1; 398 } 399 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"); 407 } 408 } 409 410 void Enter(); 411 void Exit(); 412 413 nsresult Wait(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT) { 414 return PR_CWait(mLockObject, interval) == PR_SUCCESS 415 ? NS_OK : NS_ERROR_FAILURE; 416 } 417 418 nsresult Notify() { 419 return PR_CNotify(mLockObject) == PR_SUCCESS 420 ? NS_OK : NS_ERROR_FAILURE; 421 } 422 423 nsresult NotifyAll() { 424 return PR_CNotifyAll(mLockObject) == PR_SUCCESS 425 ? NS_OK : NS_ERROR_FAILURE; 426 } 427 428private: 429 void* mLockObject; 430 PRInt32 mLockCount; 431 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; 438 } 439 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; 444 } 445 static void operator delete(void* /*memory*/) {} 446}; 447 448#endif // nsAutoLock_h__ 449