summaryrefslogtreecommitdiffstats
path: root/xbmc/threads/Event.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/threads/Event.cpp')
-rw-r--r--xbmc/threads/Event.cpp95
1 files changed, 95 insertions, 0 deletions
diff --git a/xbmc/threads/Event.cpp b/xbmc/threads/Event.cpp
new file mode 100644
index 0000000..1c67f4e
--- /dev/null
+++ b/xbmc/threads/Event.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2002 Frodo
+ * Portions Copyright (c) by the authors of ffmpeg and xvid
+ * Copyright (C) 2002-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "Event.h"
+
+#include <algorithm>
+#include <limits>
+#include <mutex>
+
+using namespace std::chrono_literals;
+
+void CEvent::addGroup(XbmcThreads::CEventGroup* group)
+{
+ std::unique_lock<CCriticalSection> lock(groupListMutex);
+ if (!groups)
+ groups.reset(new std::vector<XbmcThreads::CEventGroup*>);
+
+ groups->push_back(group);
+}
+
+void CEvent::removeGroup(XbmcThreads::CEventGroup* group)
+{
+ std::unique_lock<CCriticalSection> lock(groupListMutex);
+ if (groups)
+ {
+ groups->erase(std::remove(groups->begin(), groups->end(), group), groups->end());
+ if (groups->empty())
+ {
+ groups.reset();
+ }
+ }
+}
+
+// locking is ALWAYS done in this order:
+// CEvent::groupListMutex -> CEventGroup::mutex -> CEvent::mutex
+void CEvent::Set()
+{
+ // Originally I had this without locking. Thanks to FernetMenta who
+ // pointed out that this creates a race condition between setting
+ // checking the signal and calling wait() on the Wait call in the
+ // CEvent class. This now perfectly matches the boost example here:
+ // http://www.boost.org/doc/libs/1_41_0/doc/html/thread/synchronization.html#thread.synchronization.condvar_ref
+ {
+ std::unique_lock<CCriticalSection> slock(mutex);
+ signaled = true;
+ }
+
+ actualCv.notifyAll();
+
+ std::unique_lock<CCriticalSection> l(groupListMutex);
+ if (groups)
+ {
+ for (auto* group : *groups)
+ group->Set(this);
+ }
+}
+
+namespace XbmcThreads
+{
+ /**
+ * This will block until any one of the CEvents in the group are
+ * signaled at which point a pointer to that CEvents will be
+ * returned.
+ */
+ CEvent* CEventGroup::wait()
+ {
+ return wait(std::chrono::milliseconds::max());
+ }
+
+ CEventGroup::CEventGroup(std::initializer_list<CEvent*> eventsList)
+ : events{eventsList}
+ {
+ // we preping for a wait, so we need to set the group value on
+ // all of the CEvents.
+ for (auto* event : events)
+ {
+ event->addGroup(this);
+ }
+ }
+
+ CEventGroup::~CEventGroup()
+ {
+ for (auto* event : events)
+ {
+ event->removeGroup(this);
+ }
+ }
+}