Back to index

lightning-sunbird  0.9+nobinonly
nsAutoLock.h
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 
00039 /*
00040   A stack-based lock object that makes using PRLock a bit more
00041   convenient. It acquires the monitor when constructed, and releases
00042   it when it goes out of scope.
00043 
00044   For example,
00045 
00046     class Foo {
00047     private:
00048         PRLock* mLock;
00049 
00050     public:
00051         Foo(void) {
00052             mLock = PR_NewLock();
00053         }
00054 
00055         ~Foo(void) {
00056             PR_DestroyLock(mLock);
00057         }
00058 
00059         void ThreadSafeMethod(void) {
00060             // we're don't hold the lock yet...
00061 
00062             nsAutoLock lock(mLock);
00063             // ...but now we do.
00064 
00065             // we even can do wacky stuff like return from arbitrary places w/o
00066             // worrying about forgetting to release the lock
00067             if (some_weird_condition)
00068                 return;
00069 
00070             // otherwise do some other stuff
00071         }
00072 
00073         void ThreadSafeBlockScope(void) {
00074             // we're not in the lock here...
00075 
00076             {
00077                 nsAutoLock lock(mLock);
00078                 // but we are now, at least until the block scope closes
00079             }
00080 
00081             // ...now we're not in the lock anymore
00082         }
00083     };
00084 
00085     A similar stack-based locking object is available for PRMonitor.  The 
00086     major difference is that the PRMonitor must be created and destroyed 
00087     via the static methods on nsAutoMonitor.
00088 
00089     For example:
00090     Foo::Foo() {
00091       mMon =  nsAutoMonitor::NewMonitor("FooMonitor");
00092     }
00093     nsresult Foo::MyMethod(...) {
00094        nsAutoMonitor mon(mMon);
00095        ...
00096        // go ahead and do deeply nested returns...
00097                     return NS_ERROR_FAILURE;
00098        ...
00099        // or call Wait or Notify...
00100        mon.Wait();
00101        ...
00102        // cleanup is automatic
00103     }
00104  */
00105 
00106 #ifndef nsAutoLock_h__
00107 #define nsAutoLock_h__
00108 
00109 #include "nscore.h"
00110 #include "prlock.h"
00111 #include "prlog.h"
00112 
00118 class NS_COM nsAutoLockBase {
00119     friend class nsAutoUnlockBase;
00120 
00121 protected:
00122     nsAutoLockBase() {}
00123     enum nsAutoLockType {eAutoLock, eAutoMonitor, eAutoCMonitor};
00124 
00125 #ifdef DEBUG
00126     nsAutoLockBase(void* addr, nsAutoLockType type);
00127     ~nsAutoLockBase();
00128 
00129     void            Show();
00130     void            Hide();
00131 
00132     void*           mAddr;
00133     nsAutoLockBase* mDown;
00134     nsAutoLockType  mType;
00135 #else
00136     nsAutoLockBase(void* addr, nsAutoLockType type) {}
00137     ~nsAutoLockBase() {}
00138 
00139     void            Show() {}
00140     void            Hide() {}
00141 #endif
00142 };
00143 
00149 class NS_COM nsAutoUnlockBase {
00150 protected:
00151     nsAutoUnlockBase() {}
00152 
00153 #ifdef DEBUG
00154     nsAutoUnlockBase(void* addr);
00155     ~nsAutoUnlockBase();
00156 
00157     nsAutoLockBase* mLock;
00158 #else
00159     nsAutoUnlockBase(void* addr) {}
00160     ~nsAutoUnlockBase() {}
00161 #endif
00162 };
00163 
00168 class NS_COM nsAutoLock : public nsAutoLockBase {
00169 private:
00170     PRLock* mLock;
00171     PRBool mLocked;
00172 
00173     // Not meant to be implemented. This makes it a compiler error to
00174     // construct or assign an nsAutoLock object incorrectly.
00175     nsAutoLock(void) {}
00176     nsAutoLock(nsAutoLock& /*aLock*/) {}
00177     nsAutoLock& operator =(nsAutoLock& /*aLock*/) {
00178         return *this;
00179     }
00180 
00181     // Not meant to be implemented. This makes it a compiler error to
00182     // attempt to create an nsAutoLock object on the heap.
00183     static void* operator new(size_t /*size*/) CPP_THROW_NEW {
00184         return nsnull;
00185     }
00186     static void operator delete(void* /*memory*/) {}
00187 
00188 public:
00189 
00200     static PRLock* NewLock(const char* name);
00201     static void    DestroyLock(PRLock* lock);
00202 
00211     nsAutoLock(PRLock* aLock)
00212         : nsAutoLockBase(aLock, eAutoLock),
00213           mLock(aLock),
00214           mLocked(PR_TRUE) {
00215         PR_ASSERT(mLock);
00216 
00217         // This will assert deep in the bowels of NSPR if you attempt
00218         // to re-enter the lock.
00219         PR_Lock(mLock);
00220     }
00221     
00222     ~nsAutoLock(void) {
00223         if (mLocked)
00224             PR_Unlock(mLock);
00225     }
00226 
00232     void lock() {
00233         Show();
00234         PR_ASSERT(!mLocked);
00235         PR_Lock(mLock);
00236         mLocked = PR_TRUE;
00237     }
00238 
00239 
00245      void unlock() {
00246         PR_ASSERT(mLocked);
00247         PR_Unlock(mLock);
00248         mLocked = PR_FALSE;
00249         Hide();
00250     }
00251 };
00252 
00253 #include "prcmon.h"
00254 #include "nsError.h"
00255 #include "nsDebug.h"
00256 
00257 class NS_COM nsAutoMonitor : public nsAutoLockBase {
00258 public:
00259 
00268     static PRMonitor* NewMonitor(const char* name);
00269     static void       DestroyMonitor(PRMonitor* mon);
00270 
00271     
00280     nsAutoMonitor(PRMonitor* mon)
00281         : nsAutoLockBase((void*)mon, eAutoMonitor),
00282           mMonitor(mon), mLockCount(0)
00283     {
00284         NS_ASSERTION(mMonitor, "null monitor");
00285         if (mMonitor) {
00286             PR_EnterMonitor(mMonitor);
00287             mLockCount = 1;
00288         }
00289     }
00290 
00291     ~nsAutoMonitor() {
00292         NS_ASSERTION(mMonitor, "null monitor");
00293         if (mMonitor && mLockCount) {
00294 #ifdef DEBUG
00295             PRStatus status = 
00296 #endif
00297             PR_ExitMonitor(mMonitor);
00298             NS_ASSERTION(status == PR_SUCCESS, "PR_ExitMonitor failed");
00299         }
00300     }
00301 
00307     void Enter();
00308 
00314     void Exit();
00315 
00320     nsresult Wait(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT) {
00321         return PR_Wait(mMonitor, interval) == PR_SUCCESS
00322             ? NS_OK : NS_ERROR_FAILURE;
00323     }
00324 
00329     nsresult Notify() {
00330         return PR_Notify(mMonitor) == PR_SUCCESS
00331             ? NS_OK : NS_ERROR_FAILURE;
00332     }
00333 
00338     nsresult NotifyAll() {
00339         return PR_NotifyAll(mMonitor) == PR_SUCCESS
00340             ? NS_OK : NS_ERROR_FAILURE;
00341     }
00342 
00343 private:
00344     PRMonitor*  mMonitor;
00345     PRInt32     mLockCount;
00346 
00347     // Not meant to be implemented. This makes it a compiler error to
00348     // construct or assign an nsAutoLock object incorrectly.
00349     nsAutoMonitor(void) {}
00350     nsAutoMonitor(nsAutoMonitor& /*aMon*/) {}
00351     nsAutoMonitor& operator =(nsAutoMonitor& /*aMon*/) {
00352         return *this;
00353     }
00354 
00355     // Not meant to be implemented. This makes it a compiler error to
00356     // attempt to create an nsAutoLock object on the heap.
00357     static void* operator new(size_t /*size*/) CPP_THROW_NEW {
00358         return nsnull;
00359     }
00360     static void operator delete(void* /*memory*/) {}
00361 };
00362 
00364 // Once again, this time with a cache...
00365 // (Using this avoids the need to allocate a PRMonitor, which may be useful when
00366 // a large number of objects of the same class need associated monitors.)
00367 
00368 #include "prcmon.h"
00369 #include "nsError.h"
00370 
00371 class NS_COM nsAutoCMonitor : public nsAutoLockBase {
00372 public:
00373     nsAutoCMonitor(void* lockObject)
00374         : nsAutoLockBase(lockObject, eAutoCMonitor),
00375           mLockObject(lockObject), mLockCount(0)
00376     {
00377         NS_ASSERTION(lockObject, "null lock object");
00378         PR_CEnterMonitor(mLockObject);
00379         mLockCount = 1;
00380     }
00381 
00382     ~nsAutoCMonitor() {
00383         if (mLockCount) {
00384 #ifdef DEBUG
00385             PRStatus status =
00386 #endif
00387             PR_CExitMonitor(mLockObject);
00388             NS_ASSERTION(status == PR_SUCCESS, "PR_CExitMonitor failed");
00389         }
00390     }
00391 
00392     void Enter();
00393     void Exit();
00394 
00395     nsresult Wait(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT) {
00396         return PR_CWait(mLockObject, interval) == PR_SUCCESS
00397             ? NS_OK : NS_ERROR_FAILURE;
00398     }
00399 
00400     nsresult Notify() {
00401         return PR_CNotify(mLockObject) == PR_SUCCESS
00402             ? NS_OK : NS_ERROR_FAILURE;
00403     }
00404 
00405     nsresult NotifyAll() {
00406         return PR_CNotifyAll(mLockObject) == PR_SUCCESS
00407             ? NS_OK : NS_ERROR_FAILURE;
00408     }
00409 
00410 private:
00411     void*   mLockObject;
00412     PRInt32 mLockCount;
00413 
00414     // Not meant to be implemented. This makes it a compiler error to
00415     // construct or assign an nsAutoLock object incorrectly.
00416     nsAutoCMonitor(void) {}
00417     nsAutoCMonitor(nsAutoCMonitor& /*aMon*/) {}
00418     nsAutoCMonitor& operator =(nsAutoCMonitor& /*aMon*/) {
00419         return *this;
00420     }
00421 
00422     // Not meant to be implemented. This makes it a compiler error to
00423     // attempt to create an nsAutoLock object on the heap.
00424     static void* operator new(size_t /*size*/) CPP_THROW_NEW {
00425         return nsnull;
00426     }
00427     static void operator delete(void* /*memory*/) {}
00428 };
00429 
00430 #endif // nsAutoLock_h__
00431