2 * Copyright (c) 2002 Frodo
3 * Portions Copyright (c) by the authors of ffmpeg and xvid
4 * Copyright (C) 2002-2013 Team XBMC
7 * This Program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
12 * This Program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with XBMC; see the file COPYING. If not, see
19 * <http://www.gnu.org/licenses/>.
28 void CEvent::addGroup(XbmcThreads::CEventGroup* group)
30 CSingleLock lock(groupListMutex);
32 groups = new std::vector<XbmcThreads::CEventGroup*>();
34 groups->push_back(group);
37 void CEvent::removeGroup(XbmcThreads::CEventGroup* group)
39 CSingleLock lock(groupListMutex);
42 for (std::vector<XbmcThreads::CEventGroup*>::iterator iter = groups->begin(); iter != groups->end(); iter++)
51 if (groups->size() <= 0)
59 // locking is ALWAYS done in this order:
60 // CEvent::groupListMutex -> CEventGroup::mutex -> CEvent::mutex
63 // Originally I had this without locking. Thanks to FernetMenta who
64 // pointed out that this creates a race condition between setting
65 // checking the signal and calling wait() on the Wait call in the
66 // CEvent class. This now perfectly matches the boost example here:
67 // http://www.boost.org/doc/libs/1_41_0/doc/html/thread/synchronization.html#thread.synchronization.condvar_ref
69 CSingleLock slock(mutex);
75 CSingleLock l(groupListMutex);
78 for (std::vector<XbmcThreads::CEventGroup*>::iterator iter = groups->begin();
79 iter != groups->end(); iter++)
87 * This will block until any one of the CEvents in the group are
88 * signaled at which point a pointer to that CEvents will be
91 CEvent* CEventGroup::wait()
93 return wait(std::numeric_limits<unsigned int>::max());
97 * This will block until any one of the CEvents in the group are
98 * signaled or the timeout is reachec. If an event is signaled then
99 * it will return a pointer to that CEvent, otherwise it will return
102 // locking is ALWAYS done in this order:
103 // CEvent::groupListMutex -> CEventGroup::mutex -> CEvent::mutex
105 // Notice that this method doesn't grab the CEvent::groupListMutex at all. This
106 // is fine. It just grabs the CEventGroup::mutex and THEN the individual
108 CEvent* CEventGroup::wait(unsigned int milliseconds)
110 CSingleLock lock(mutex); // grab CEventGroup::mutex
113 // ==================================================
114 // This block checks to see if any child events are
115 // signaled and sets 'signaled' to the first one it
117 // ==================================================
119 for (std::vector<CEvent*>::iterator iter = events.begin();
120 signaled == NULL && iter != events.end(); iter++)
126 // ==================================================
130 // both of these release the CEventGroup::mutex
131 if (milliseconds == std::numeric_limits<unsigned int>::max())
134 condVar.wait(mutex,milliseconds);
135 } // at this point the CEventGroup::mutex is reacquired
138 // signaled should have been set by a call to CEventGroup::Set
139 CEvent* ret = signaled;
143 // This acquires and releases the CEvent::mutex. This is fine since the
144 // CEventGroup::mutex is already being held
145 signaled->WaitMSec(0); // reset the event if needed
146 signaled = NULL; // clear the signaled if all the waiters are gone
151 CEventGroup::CEventGroup(int num, CEvent* v1, ...) : signaled(NULL), condVar(actualCv,signaled), numWaits(0)
156 events.push_back(v1);
157 num--; // account for v1
158 for (;num > 0; num--)
159 events.push_back(va_arg(ap,CEvent*));
162 // we preping for a wait, so we need to set the group value on
163 // all of the CEvents.
164 for (std::vector<CEvent*>::iterator iter = events.begin();
165 iter != events.end(); iter++)
166 (*iter)->addGroup(this);
169 CEventGroup::CEventGroup(CEvent* v1, ...) : signaled(NULL), condVar(actualCv,signaled), numWaits(0)
174 events.push_back(v1);
178 CEvent* cur = va_arg(ap,CEvent*);
180 events.push_back(cur);
186 // we preping for a wait, so we need to set the group value on
187 // all of the CEvents.
188 for (std::vector<CEvent*>::iterator iter = events.begin();
189 iter != events.end(); iter++)
190 (*iter)->addGroup(this);
193 CEventGroup::~CEventGroup()
195 for (std::vector<CEvent*>::iterator iter = events.begin();
196 iter != events.end(); iter++)
197 (*iter)->removeGroup(this);