blob: 1c67f4eac479c26ec27349c3108c64ba69150fd4 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
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);
}
}
}
|