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