forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			265 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			265 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #ifndef mozilla_ReentrantMonitor_h
 | |
| #define mozilla_ReentrantMonitor_h
 | |
| 
 | |
| #include "prmon.h"
 | |
| 
 | |
| #ifdef MOZILLA_INTERNAL_API
 | |
| #include "GeckoProfiler.h"
 | |
| #endif //MOZILLA_INTERNAL_API
 | |
| 
 | |
| #include "mozilla/BlockingResourceBase.h"
 | |
| 
 | |
| //
 | |
| // Provides:
 | |
| //
 | |
| //  - ReentrantMonitor, a Java-like monitor
 | |
| //  - ReentrantMonitorAutoEnter, an RAII class for ensuring that
 | |
| //    ReentrantMonitors are properly entered and exited
 | |
| //
 | |
| // Using ReentrantMonitorAutoEnter is MUCH preferred to making bare calls to
 | |
| // ReentrantMonitor.Enter and Exit.
 | |
| //
 | |
| namespace mozilla {
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * ReentrantMonitor
 | |
|  * Java-like monitor.
 | |
|  * When possible, use ReentrantMonitorAutoEnter to hold this monitor within a
 | |
|  * scope, instead of calling Enter/Exit directly.
 | |
|  **/
 | |
| class ReentrantMonitor : BlockingResourceBase
 | |
| {
 | |
| public:
 | |
|   /**
 | |
|    * ReentrantMonitor
 | |
|    * @param aName A name which can reference this monitor
 | |
|    */
 | |
|   explicit ReentrantMonitor(const char* aName,
 | |
|                             recordreplay::Behavior aRecorded = recordreplay::Behavior::Preserve)
 | |
|     : BlockingResourceBase(aName, eReentrantMonitor)
 | |
| #ifdef DEBUG
 | |
|     , mEntryCount(0)
 | |
| #endif
 | |
|   {
 | |
|     MOZ_COUNT_CTOR(ReentrantMonitor);
 | |
|     if (aRecorded == recordreplay::Behavior::Preserve) {
 | |
|       mReentrantMonitor = PR_NewMonitor();
 | |
|     } else {
 | |
|       recordreplay::AutoPassThroughThreadEvents pt;
 | |
|       mReentrantMonitor = PR_NewMonitor();
 | |
|     }
 | |
|     if (!mReentrantMonitor) {
 | |
|       MOZ_CRASH("Can't allocate mozilla::ReentrantMonitor");
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * ~ReentrantMonitor
 | |
|    **/
 | |
|   ~ReentrantMonitor()
 | |
|   {
 | |
|     NS_ASSERTION(mReentrantMonitor,
 | |
|                  "improperly constructed ReentrantMonitor or double free");
 | |
|     PR_DestroyMonitor(mReentrantMonitor);
 | |
|     mReentrantMonitor = 0;
 | |
|     MOZ_COUNT_DTOR(ReentrantMonitor);
 | |
|   }
 | |
| 
 | |
| #ifndef DEBUG
 | |
|   /**
 | |
|    * Enter
 | |
|    * @see prmon.h
 | |
|    **/
 | |
|   void Enter() { PR_EnterMonitor(mReentrantMonitor); }
 | |
| 
 | |
|   /**
 | |
|    * Exit
 | |
|    * @see prmon.h
 | |
|    **/
 | |
|   void Exit() { PR_ExitMonitor(mReentrantMonitor); }
 | |
| 
 | |
|   /**
 | |
|    * Wait
 | |
|    * @see prmon.h
 | |
|    **/
 | |
|   nsresult Wait(PRIntervalTime aInterval = PR_INTERVAL_NO_TIMEOUT)
 | |
|   {
 | |
| #ifdef MOZILLA_INTERNAL_API
 | |
|     AUTO_PROFILER_THREAD_SLEEP;
 | |
| #endif //MOZILLA_INTERNAL_API
 | |
|     return PR_Wait(mReentrantMonitor, aInterval) == PR_SUCCESS ?
 | |
|       NS_OK : NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
| #else // ifndef DEBUG
 | |
|   void Enter();
 | |
|   void Exit();
 | |
|   nsresult Wait(PRIntervalTime aInterval = PR_INTERVAL_NO_TIMEOUT);
 | |
| 
 | |
| #endif  // ifndef DEBUG
 | |
| 
 | |
|   /**
 | |
|    * Notify
 | |
|    * @see prmon.h
 | |
|    **/
 | |
|   nsresult Notify()
 | |
|   {
 | |
|     return PR_Notify(mReentrantMonitor) == PR_SUCCESS ? NS_OK :
 | |
|                                                         NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * NotifyAll
 | |
|    * @see prmon.h
 | |
|    **/
 | |
|   nsresult NotifyAll()
 | |
|   {
 | |
|     return PR_NotifyAll(mReentrantMonitor) == PR_SUCCESS ? NS_OK :
 | |
|                                                            NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
| #ifdef DEBUG
 | |
|   /**
 | |
|    * AssertCurrentThreadIn
 | |
|    * @see prmon.h
 | |
|    **/
 | |
|   void AssertCurrentThreadIn()
 | |
|   {
 | |
|     PR_ASSERT_CURRENT_THREAD_IN_MONITOR(mReentrantMonitor);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * AssertNotCurrentThreadIn
 | |
|    * @see prmon.h
 | |
|    **/
 | |
|   void AssertNotCurrentThreadIn()
 | |
|   {
 | |
|     // FIXME bug 476536
 | |
|   }
 | |
| 
 | |
| #else
 | |
|   void AssertCurrentThreadIn() {}
 | |
|   void AssertNotCurrentThreadIn() {}
 | |
| 
 | |
| #endif  // ifdef DEBUG
 | |
| 
 | |
| private:
 | |
|   ReentrantMonitor();
 | |
|   ReentrantMonitor(const ReentrantMonitor&);
 | |
|   ReentrantMonitor& operator=(const ReentrantMonitor&);
 | |
| 
 | |
|   PRMonitor* mReentrantMonitor;
 | |
| #ifdef DEBUG
 | |
|   int32_t mEntryCount;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * ReentrantMonitorAutoEnter
 | |
|  * Enters the ReentrantMonitor when it enters scope, and exits it when
 | |
|  * it leaves scope.
 | |
|  *
 | |
|  * MUCH PREFERRED to bare calls to ReentrantMonitor.Enter and Exit.
 | |
|  */
 | |
| class MOZ_STACK_CLASS ReentrantMonitorAutoEnter
 | |
| {
 | |
| public:
 | |
|   /**
 | |
|    * Constructor
 | |
|    * The constructor aquires the given lock.  The destructor
 | |
|    * releases the lock.
 | |
|    *
 | |
|    * @param aReentrantMonitor A valid mozilla::ReentrantMonitor*.
 | |
|    **/
 | |
|   explicit ReentrantMonitorAutoEnter(mozilla::ReentrantMonitor& aReentrantMonitor)
 | |
|     : mReentrantMonitor(&aReentrantMonitor)
 | |
|   {
 | |
|     NS_ASSERTION(mReentrantMonitor, "null monitor");
 | |
|     mReentrantMonitor->Enter();
 | |
|   }
 | |
| 
 | |
|   ~ReentrantMonitorAutoEnter(void)
 | |
|   {
 | |
|     mReentrantMonitor->Exit();
 | |
|   }
 | |
| 
 | |
|   nsresult Wait(PRIntervalTime aInterval = PR_INTERVAL_NO_TIMEOUT)
 | |
|   {
 | |
|     return mReentrantMonitor->Wait(aInterval);
 | |
|   }
 | |
| 
 | |
|   nsresult Notify() { return mReentrantMonitor->Notify(); }
 | |
|   nsresult NotifyAll() { return mReentrantMonitor->NotifyAll(); }
 | |
| 
 | |
| private:
 | |
|   ReentrantMonitorAutoEnter();
 | |
|   ReentrantMonitorAutoEnter(const ReentrantMonitorAutoEnter&);
 | |
|   ReentrantMonitorAutoEnter& operator=(const ReentrantMonitorAutoEnter&);
 | |
|   static void* operator new(size_t) CPP_THROW_NEW;
 | |
| 
 | |
|   friend class ReentrantMonitorAutoExit;
 | |
| 
 | |
|   mozilla::ReentrantMonitor* mReentrantMonitor;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * ReentrantMonitorAutoExit
 | |
|  * Exit the ReentrantMonitor when it enters scope, and enters it when it leaves
 | |
|  * scope.
 | |
|  *
 | |
|  * MUCH PREFERRED to bare calls to ReentrantMonitor.Exit and Enter.
 | |
|  */
 | |
| class MOZ_STACK_CLASS ReentrantMonitorAutoExit
 | |
| {
 | |
| public:
 | |
|   /**
 | |
|    * Constructor
 | |
|    * The constructor releases the given lock.  The destructor
 | |
|    * acquires the lock. The lock must be held before constructing
 | |
|    * this object!
 | |
|    *
 | |
|    * @param aReentrantMonitor A valid mozilla::ReentrantMonitor*. It
 | |
|    *                 must be already locked.
 | |
|    **/
 | |
|   explicit ReentrantMonitorAutoExit(ReentrantMonitor& aReentrantMonitor)
 | |
|     : mReentrantMonitor(&aReentrantMonitor)
 | |
|   {
 | |
|     NS_ASSERTION(mReentrantMonitor, "null monitor");
 | |
|     mReentrantMonitor->AssertCurrentThreadIn();
 | |
|     mReentrantMonitor->Exit();
 | |
|   }
 | |
| 
 | |
|   explicit ReentrantMonitorAutoExit(
 | |
|     ReentrantMonitorAutoEnter& aReentrantMonitorAutoEnter)
 | |
|     : mReentrantMonitor(aReentrantMonitorAutoEnter.mReentrantMonitor)
 | |
|   {
 | |
|     NS_ASSERTION(mReentrantMonitor, "null monitor");
 | |
|     mReentrantMonitor->AssertCurrentThreadIn();
 | |
|     mReentrantMonitor->Exit();
 | |
|   }
 | |
| 
 | |
|   ~ReentrantMonitorAutoExit(void)
 | |
|   {
 | |
|     mReentrantMonitor->Enter();
 | |
|   }
 | |
| 
 | |
| private:
 | |
|   ReentrantMonitorAutoExit();
 | |
|   ReentrantMonitorAutoExit(const ReentrantMonitorAutoExit&);
 | |
|   ReentrantMonitorAutoExit& operator=(const ReentrantMonitorAutoExit&);
 | |
|   static void* operator new(size_t) CPP_THROW_NEW;
 | |
| 
 | |
|   ReentrantMonitor* mReentrantMonitor;
 | |
| };
 | |
| 
 | |
| } // namespace mozilla
 | |
| 
 | |
| #endif // ifndef mozilla_ReentrantMonitor_h
 | 
