update date in GPL header
[vuplus_xbmc] / xbmc / threads / Event.h
1 /*
2  *      Copyright (C) 2005-2012 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #pragma once
22
23 #include <vector>
24
25 #include "threads/Condition.h"
26 #include "threads/SingleLock.h"
27
28 // forward declare the CEventGroup
29 namespace XbmcThreads
30 {
31   class CEventGroup;
32 }
33
34
35 /**
36  * This is an Event class built from a ConditionVariable. The Event adds the state
37  * that the condition is gating as well as the mutex/lock.
38  *
39  * This Event can be 'interruptible' (even though there is only a single place
40  * in the code that uses this behavior).
41  *
42  * This class manages 'spurious returns' from the condition variable.
43  */
44 class CEvent : public XbmcThreads::NonCopyable
45 {
46   bool manualReset;
47   volatile bool signaled;
48   unsigned int numWaits;
49
50   CCriticalSection groupListMutex; // lock for the groups list
51   std::vector<XbmcThreads::CEventGroup*> * groups;
52
53   /**
54    * To satisfy the TightConditionVariable requirements and allow the 
55    *  predicate being monitored to include both the signaled and interrupted
56    *  states.
57    */
58   XbmcThreads::ConditionVariable actualCv;
59   XbmcThreads::TightConditionVariable<volatile bool&> condVar;
60   CCriticalSection mutex;
61
62   friend class XbmcThreads::CEventGroup;
63
64   void addGroup(XbmcThreads::CEventGroup* group);
65   void removeGroup(XbmcThreads::CEventGroup* group);
66
67   // helper for the two wait methods
68   inline bool prepReturn() { bool ret = signaled; if (!manualReset && numWaits == 0) signaled = false; return ret; }
69
70 public:
71   inline CEvent(bool manual = false, bool signaled_ = false) : 
72     manualReset(manual), signaled(signaled_), numWaits(0), groups(NULL), condVar(actualCv,signaled) {}
73
74   inline void Reset() { CSingleLock lock(mutex); signaled = false; }
75   void Set();
76
77   /**
78    * This will wait up to 'milliSeconds' milliseconds for the Event
79    *  to be triggered. The method will return 'true' if the Event
80    *  was triggered. Otherwise it will return false.
81    */
82   inline bool WaitMSec(unsigned int milliSeconds) 
83   { CSingleLock lock(mutex); numWaits++; condVar.wait(mutex,milliSeconds); numWaits--; return prepReturn(); }
84
85   /**
86    * This will wait for the Event to be triggered. The method will return 
87    * 'true' if the Event was triggered. If it was either interrupted
88    * it will return false. Otherwise it will return false.
89    */
90   inline bool Wait()
91   { CSingleLock lock(mutex); numWaits++; condVar.wait(mutex); numWaits--; return prepReturn(); }
92
93   /**
94    * This is mostly for testing. It allows a thread to make sure there are 
95    *  the right amount of other threads waiting.
96    */
97   inline int getNumWaits() { CSingleLock lock(mutex); return numWaits; }
98
99 };
100
101 namespace XbmcThreads
102 {
103   /**
104    * CEventGroup is a means of grouping CEvents to wait on them together.
105    * It is equivalent to WaitOnMultipleObject that returns when "any" Event
106    * in the group signaled.
107    */
108   class CEventGroup : public NonCopyable
109   {
110     std::vector<CEvent*> events;
111     CEvent* signaled;
112     XbmcThreads::ConditionVariable actualCv;
113     XbmcThreads::TightConditionVariable<CEvent*&> condVar;
114     CCriticalSection mutex;
115
116     unsigned int numWaits;
117
118     // This is ONLY called from CEvent::Set.
119     inline void Set(CEvent* child) { CSingleLock l(mutex); signaled = child; condVar.notifyAll(); }
120
121     friend class ::CEvent;
122
123   public:
124
125     /**
126      * Create a CEventGroup from a number of CEvents. num is the number
127      *  of Events that follow. E.g.:
128      *
129      *  CEventGroup g(3, event1, event2, event3);
130      */
131     CEventGroup(int num, CEvent* v1, ...);
132
133     /**
134      * Create a CEventGroup from a number of CEvents. The parameters
135      *  should form a NULL terminated list of CEvent*'s
136      *
137      *  CEventGroup g(event1, event2, event3, NULL);
138      */
139     CEventGroup(CEvent* v1, ...);
140     ~CEventGroup();
141
142     /**
143      * This will block until any one of the CEvents in the group are
144      * signaled at which point a pointer to that CEvents will be 
145      * returned.
146      */
147     CEvent* wait();
148
149     /**
150      * This will block until any one of the CEvents in the group are
151      * signaled or the timeout is reachec. If an event is signaled then
152      * it will return a pointer to that CEvent, otherwise it will return
153      * NULL.
154      */
155     CEvent* wait(unsigned int milliseconds);
156
157     /**
158      * This is mostly for testing. It allows a thread to make sure there are 
159      *  the right amount of other threads waiting.
160      */
161     inline int getNumWaits() { CSingleLock lock(mutex); return numWaits; }
162
163   };
164 }