PageRenderTime 105ms CodeModel.GetById 42ms app.highlight 34ms RepoModel.GetById 25ms app.codeStats 0ms

/gecko_api/include/nsAutoLock.h

http://firefox-mac-pdf.googlecode.com/
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