[Windows] Remove redundant DirectSound error codes
[xbmc.git] / xbmc / threads / Event.h
blob72ce75464ac318938a2b90162f12a73d6e7feb69
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #pragma once
11 #include "threads/Condition.h"
13 #include <initializer_list>
14 #include <memory>
15 #include <mutex>
16 #include <vector>
18 // forward declare the CEventGroup
19 namespace XbmcThreads
21 class CEventGroup;
24 /**
25 * @brief This is an Event class built from a ConditionVariable. The Event adds the state
26 * that the condition is gating as well as the mutex/lock.
28 * This Event can be 'interruptible' (even though there is only a single place
29 * in the code that uses this behavior).
31 * This class manages 'spurious returns' from the condition variable.
35 class CEvent
37 bool manualReset;
38 volatile bool signaled;
39 unsigned int numWaits = 0;
41 CCriticalSection groupListMutex; // lock for the groups list
42 std::unique_ptr<std::vector<XbmcThreads::CEventGroup*>> groups;
44 XbmcThreads::ConditionVariable actualCv;
45 CCriticalSection mutex;
47 friend class XbmcThreads::CEventGroup;
49 void addGroup(XbmcThreads::CEventGroup* group);
50 void removeGroup(XbmcThreads::CEventGroup* group);
52 // helper for the two wait methods
53 inline bool prepReturn()
55 bool ret = signaled;
56 if (!manualReset && numWaits == 0)
57 signaled = false;
58 return ret;
61 CEvent(const CEvent&) = delete;
62 CEvent& operator=(const CEvent&) = delete;
64 public:
65 inline CEvent(bool manual = false, bool signaled_ = false)
66 : manualReset(manual), signaled(signaled_)
70 inline void Reset()
72 std::unique_lock<CCriticalSection> lock(mutex);
73 signaled = false;
75 void Set();
77 /**
78 * @brief Returns true if Event has been triggered and not reset, false otherwise.
81 inline bool Signaled()
83 std::unique_lock<CCriticalSection> lock(mutex);
84 return signaled;
87 /**
88 * @brief This will wait up to 'duration' for the Event to be
89 * triggered. The method will return 'true' if the Event
90 * was triggered. Otherwise it will return false.
93 template<typename Rep, typename Period>
94 inline bool Wait(std::chrono::duration<Rep, Period> duration)
96 std::unique_lock<CCriticalSection> lock(mutex);
97 numWaits++;
98 actualCv.wait(mutex, duration, std::bind(&CEvent::Signaled, this));
99 numWaits--;
100 return prepReturn();
104 * @brief This will wait for the Event to be triggered. The method will return
105 * 'true' if the Event was triggered. If it was either interrupted
106 * it will return false. Otherwise it will return false.
109 inline bool Wait()
111 std::unique_lock<CCriticalSection> lock(mutex);
112 numWaits++;
113 actualCv.wait(mutex, std::bind(&CEvent::Signaled, this));
114 numWaits--;
115 return prepReturn();
119 * @brief This is mostly for testing. It allows a thread to make sure there are
120 * the right amount of other threads waiting.
123 inline int getNumWaits()
125 std::unique_lock<CCriticalSection> lock(mutex);
126 return numWaits;
130 namespace XbmcThreads
133 * @brief CEventGroup is a means of grouping CEvents to wait on them together.
134 * It is equivalent to WaitOnMultipleObject that returns when "any" Event
135 * in the group signaled.
138 class CEventGroup
140 std::vector<CEvent*> events;
141 CEvent* signaled{};
142 XbmcThreads::ConditionVariable actualCv;
143 CCriticalSection mutex;
145 unsigned int numWaits{0};
147 // This is ONLY called from CEvent::Set.
148 inline void Set(CEvent* child)
150 std::unique_lock<CCriticalSection> l(mutex);
151 signaled = child;
152 actualCv.notifyAll();
155 friend class ::CEvent;
157 CEventGroup(const CEventGroup&) = delete;
158 CEventGroup& operator=(const CEventGroup&) = delete;
160 public:
162 * @brief Create a CEventGroup from a number of CEvents.
165 CEventGroup(std::initializer_list<CEvent*> events);
167 ~CEventGroup();
170 * @brief This will block until any one of the CEvents in the group are
171 * signaled at which point a pointer to that CEvents will be
172 * returned.
175 CEvent* wait();
178 * @brief locking is ALWAYS done in this order:
179 * CEvent::groupListMutex -> CEventGroup::mutex -> CEvent::mutex
181 * Notice that this method doesn't grab the CEvent::groupListMutex at all. This
182 * is fine. It just grabs the CEventGroup::mutex and THEN the individual
185 template<typename Rep, typename Period>
186 CEvent* wait(std::chrono::duration<Rep, Period> duration)
188 std::unique_lock<CCriticalSection> lock(mutex); // grab CEventGroup::mutex
189 numWaits++;
191 // ==================================================
192 // This block checks to see if any child events are
193 // signaled and sets 'signaled' to the first one it
194 // finds.
195 // ==================================================
196 signaled = nullptr;
197 for (auto* cur : events)
199 std::unique_lock<CCriticalSection> lock2(cur->mutex);
200 if (cur->signaled)
201 signaled = cur;
203 // ==================================================
205 if (!signaled)
207 // both of these release the CEventGroup::mutex
208 if (duration == std::chrono::duration<Rep, Period>::max())
209 actualCv.wait(mutex, [this]() { return signaled != nullptr; });
210 else
211 actualCv.wait(mutex, duration, [this]() { return signaled != nullptr; });
212 } // at this point the CEventGroup::mutex is reacquired
213 numWaits--;
215 // signaled should have been set by a call to CEventGroup::Set
216 CEvent* ret = signaled;
217 if (numWaits == 0)
219 if (signaled)
220 // This acquires and releases the CEvent::mutex. This is fine since the
221 // CEventGroup::mutex is already being held
222 signaled->Wait(std::chrono::duration<Rep, Period>::zero()); // reset the event if needed
223 signaled = nullptr; // clear the signaled if all the waiters are gone
225 return ret;
229 * @brief This is mostly for testing. It allows a thread to make sure there are
230 * the right amount of other threads waiting.
233 inline int getNumWaits()
235 std::unique_lock<CCriticalSection> lock(mutex);
236 return numWaits;
239 } // namespace XbmcThreads