/*
- * Copyright (C) 2005-2011 Team XBMC
- * http://www.xbmc.org
+ * Copyright (C) 2005-2013 Team XBMC
+ * http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with XBMC; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- * http://www.gnu.org/copyleft/gpl.html
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
*
*/
#include <vector>
#include "threads/Condition.h"
-#include "threads/Interruptible.h"
+#include "threads/SingleLock.h"
// forward declare the CEventGroup
namespace XbmcThreads
*
* This class manages 'spurious returns' from the condition variable.
*/
-class CEvent : public XbmcThreads::IInterruptible
+class CEvent : public XbmcThreads::NonCopyable
{
bool manualReset;
- bool signaled;
- bool interrupted;
- bool interruptible;
-
+ volatile bool signaled;
unsigned int numWaits;
+ CCriticalSection groupListMutex; // lock for the groups list
std::vector<XbmcThreads::CEventGroup*> * groups;
- XbmcThreads::ConditionVariable condVar;
+ /**
+ * To satisfy the TightConditionVariable requirements and allow the
+ * predicate being monitored to include both the signaled and interrupted
+ * states.
+ */
+ XbmcThreads::ConditionVariable actualCv;
+ XbmcThreads::TightConditionVariable<volatile bool&> condVar;
CCriticalSection mutex;
- // block the ability to copy
- inline CEvent& operator=(const CEvent& src) { return *this; }
- inline CEvent(const CEvent& other) {}
-
friend class XbmcThreads::CEventGroup;
- void groupSet();
void addGroup(XbmcThreads::CEventGroup* group);
void removeGroup(XbmcThreads::CEventGroup* group);
+
+ // helper for the two wait methods
+ inline bool prepReturn() { bool ret = signaled; if (!manualReset && numWaits == 0) signaled = false; return ret; }
+
public:
+ inline CEvent(bool manual = false, bool signaled_ = false) :
+ manualReset(manual), signaled(signaled_), numWaits(0), groups(NULL), condVar(actualCv,signaled) {}
- inline CEvent(bool manual = false, bool interruptible_ = false) :
- manualReset(manual), signaled(false), interrupted(false),
- interruptible(interruptible_), numWaits(0), groups(NULL) {}
inline void Reset() { CSingleLock lock(mutex); signaled = false; }
- inline void Set() { CSingleLock lock(mutex); signaled = true; condVar.notifyAll(); groupSet(); }
-
- virtual void Interrupt();
- inline bool wasInterrupted() { CSingleLock lock(mutex); return interrupted; }
+ void Set();
/**
* This will wait up to 'milliSeconds' milliseconds for the Event
* to be triggered. The method will return 'true' if the Event
- * was triggered. If it was either interrupted, or it timed out
- * it will return false. To determine if it was interrupted you can
- * use 'wasInterrupted()' call prior to any further call to a
- * Wait* method.
+ * was triggered. Otherwise it will return false.
*/
- bool WaitMSec(unsigned int milliSeconds);
+ inline bool WaitMSec(unsigned int milliSeconds)
+ { CSingleLock lock(mutex); numWaits++; condVar.wait(mutex,milliSeconds); numWaits--; return prepReturn(); }
/**
* This will wait for the Event to be triggered. The method will return
* 'true' if the Event was triggered. If it was either interrupted
- * it will return false. To determine if it was interrupted you can
- * use 'wasInterrupted()' call prior to any further call to a Wait* method.
+ * it will return false. Otherwise it will return false.
+ */
+ inline bool Wait()
+ { CSingleLock lock(mutex); numWaits++; condVar.wait(mutex); numWaits--; return prepReturn(); }
+
+ /**
+ * This is mostly for testing. It allows a thread to make sure there are
+ * the right amount of other threads waiting.
*/
- bool Wait();
+ inline int getNumWaits() { CSingleLock lock(mutex); return numWaits; }
+
};
namespace XbmcThreads
{
/**
* CEventGroup is a means of grouping CEvents to wait on them together.
- * It is equivalent to WaitOnMultipleObject with that returns when "any"
+ * It is equivalent to WaitOnMultipleObject that returns when "any" Event
* in the group signaled.
*/
- class CEventGroup
+ class CEventGroup : public NonCopyable
{
std::vector<CEvent*> events;
- XbmcThreads::ConditionVariable condVar;
- CCriticalSection mutex;
CEvent* signaled;
+ XbmcThreads::ConditionVariable actualCv;
+ XbmcThreads::TightConditionVariable<CEvent*&> condVar;
+ CCriticalSection mutex;
unsigned int numWaits;
- void Set(CEvent* child);
+
+ // This is ONLY called from CEvent::Set.
+ inline void Set(CEvent* child) { CSingleLock l(mutex); signaled = child; condVar.notifyAll(); }
friend class ::CEvent;
+
public:
/**
* returned.
*/
CEvent* wait();
+
+ /**
+ * This will block until any one of the CEvents in the group are
+ * signaled or the timeout is reachec. If an event is signaled then
+ * it will return a pointer to that CEvent, otherwise it will return
+ * NULL.
+ */
+ CEvent* wait(unsigned int milliseconds);
+
+ /**
+ * This is mostly for testing. It allows a thread to make sure there are
+ * the right amount of other threads waiting.
+ */
+ inline int getNumWaits() { CSingleLock lock(mutex); return numWaits; }
+
};
}