Merge pull request #211 from Montellese/jsonrpc_actor_thumb
[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
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
45 {
46   bool manualReset;
47   bool signaled;
48   unsigned int numWaits;
49
50   std::vector<XbmcThreads::CEventGroup*> * groups;
51
52   /**
53    * To satisfy the TightConditionVariable requirements and allow the 
54    *  predicate being monitored to include both the signaled and interrupted
55    *  states.
56    */
57   XbmcThreads::TightConditionVariable<bool&> condVar;
58   CCriticalSection mutex;
59
60   friend class XbmcThreads::CEventGroup;
61
62   void groupSet();
63   void addGroup(XbmcThreads::CEventGroup* group);
64   void removeGroup(XbmcThreads::CEventGroup* group);
65
66   // helper for the two wait methods
67   inline bool prepReturn() { bool ret = signaled; if (!manualReset && numWaits == 0) signaled = false; return ret; }
68
69   // block the ability to copy
70   inline CEvent& operator=(const CEvent& src) { return *this; }
71   inline CEvent(const CEvent& other): condVar(signaled) {}
72
73 public:
74   inline CEvent(bool manual = false, bool signaled_ = false) : 
75     manualReset(manual), signaled(signaled_), numWaits(0), groups(NULL), condVar(signaled) {}
76
77   inline void Reset() { CSingleLock lock(mutex); signaled = false; }
78   inline void Set() { CSingleLock lock(mutex); signaled = true; condVar.notifyAll(); groupSet(); }
79
80   /**
81    * This will wait up to 'milliSeconds' milliseconds for the Event
82    *  to be triggered. The method will return 'true' if the Event
83    *  was triggered. Otherwise it will return false.
84    */
85   inline bool WaitMSec(unsigned int milliSeconds) 
86   { CSingleLock lock(mutex); numWaits++; condVar.wait(mutex,milliSeconds); numWaits--; return prepReturn(); }
87
88   /**
89    * This will wait for the Event to be triggered. The method will return 
90    * 'true' if the Event was triggered. If it was either interrupted
91    * it will return false. Otherwise it will return false.
92    */
93   inline bool Wait()
94   { CSingleLock lock(mutex); numWaits++; condVar.wait(mutex); numWaits--; return prepReturn(); }
95
96 };
97
98 namespace XbmcThreads
99 {
100   /**
101    * CEventGroup is a means of grouping CEvents to wait on them together.
102    * It is equivalent to WaitOnMultipleObject that returns when "any" Event
103    * in the group signaled.
104    */
105   class CEventGroup
106   {
107     std::vector<CEvent*> events;
108     CEvent* signaled;
109     XbmcThreads::TightConditionVariable<CEvent*&> condVar;
110     CCriticalSection mutex;
111
112     unsigned int numWaits;
113
114     inline void Set(CEvent* child) { CSingleLock lock(mutex); signaled = child; condVar.notifyAll(); }
115
116     friend class ::CEvent;
117
118     inline CEvent* prepReturn() { CEvent* ret = signaled; if (numWaits == 0) signaled = NULL; return ret; }
119     CEvent* anyEventsSignaled();
120
121   public:
122
123     /**
124      * Create a CEventGroup from a number of CEvents. num is the number
125      *  of Events that follow. E.g.:
126      *
127      *  CEventGroup g(3, event1, event2, event3);
128      */
129     CEventGroup(int num, CEvent* v1, ...);
130
131     /**
132      * Create a CEventGroup from a number of CEvents. The parameters
133      *  should form a NULL terminated list of CEvent*'s
134      *
135      *  CEventGroup g(event1, event2, event3, NULL);
136      */
137     CEventGroup(CEvent* v1, ...);
138     ~CEventGroup();
139
140     /**
141      * This will block until any one of the CEvents in the group are
142      * signaled at which point a pointer to that CEvents will be 
143      * returned.
144      */
145     inline CEvent* wait() 
146     { CSingleLock lock(mutex); 
147       numWaits++; 
148       signaled = anyEventsSignaled(); 
149       if (!signaled) condVar.wait(mutex); 
150       numWaits--; 
151       return prepReturn(); 
152     }
153
154     /**
155      * This will block until any one of the CEvents in the group are
156      * signaled or the timeout is reachec. If an event is signaled then
157      * it will return a pointer to that CEvent, otherwise it will return
158      * NULL.
159      */
160     inline CEvent* wait(unsigned int milliseconds)  
161     { CSingleLock lock(mutex);
162       numWaits++; 
163       signaled = anyEventsSignaled(); 
164       if(!signaled) condVar.wait(mutex,milliseconds); 
165       numWaits--; 
166       return prepReturn(); 
167     }
168   };
169 }