gecko/xpcom/glue/ReentrantMonitor.h
Karl Tomlinson 2364c5394f b=928222 move ReentrantMonitorAutoExit from VideoUtils.h to ReentrantMonitor.h r=bsmedberg
--HG--
extra : transplant_source : %13O%CF%90x%02%B8%B6%A3%EA%AD%03%99%9A7%1B%A0%21%C4%A3
2013-10-24 07:22:53 +13:00

261 lines
6.1 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: sw=4 ts=4 et :
* 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"
#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 NS_COM_GLUE ReentrantMonitor : BlockingResourceBase
{
public:
/**
* ReentrantMonitor
* @param aName A name which can reference this monitor
*/
ReentrantMonitor(const char* aName) :
BlockingResourceBase(aName, eReentrantMonitor)
#ifdef DEBUG
, mEntryCount(0)
#endif
{
MOZ_COUNT_CTOR(ReentrantMonitor);
mReentrantMonitor = PR_NewMonitor();
if (!mReentrantMonitor)
NS_RUNTIMEABORT("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 interval = PR_INTERVAL_NO_TIMEOUT)
{
return PR_Wait(mReentrantMonitor, interval) == PR_SUCCESS ?
NS_OK : NS_ERROR_FAILURE;
}
#else
void Enter();
void Exit();
nsresult Wait(PRIntervalTime interval = 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 NS_COM_GLUE MOZ_STACK_CLASS ReentrantMonitorAutoEnter
{
public:
/**
* Constructor
* The constructor aquires the given lock. The destructor
* releases the lock.
*
* @param aReentrantMonitor A valid mozilla::ReentrantMonitor*.
**/
ReentrantMonitorAutoEnter(mozilla::ReentrantMonitor &aReentrantMonitor) :
mReentrantMonitor(&aReentrantMonitor)
{
NS_ASSERTION(mReentrantMonitor, "null monitor");
mReentrantMonitor->Enter();
}
~ReentrantMonitorAutoEnter(void)
{
mReentrantMonitor->Exit();
}
nsresult Wait(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT)
{
return mReentrantMonitor->Wait(interval);
}
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;
static void operator delete(void*);
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.
**/
ReentrantMonitorAutoExit(ReentrantMonitor& aReentrantMonitor) :
mReentrantMonitor(&aReentrantMonitor)
{
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;
static void operator delete(void*);
ReentrantMonitor* mReentrantMonitor;
};
} // namespace mozilla
#endif // ifndef mozilla_ReentrantMonitor_h