Skip to content

Commit 67a958a

Browse files
committed
Merge branch 'v0.20.x'
2 parents 3850716 + 7372c93 commit 67a958a

File tree

9 files changed

+83
-18
lines changed

9 files changed

+83
-18
lines changed

NEWS

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ ver 0.21 (not yet released)
66
ver 0.20.5 (not yet released)
77
* tags
88
- id3: fix memory leak on corrupt ID3 tags
9+
* decoder
10+
- sidplay: don't require libsidutils when building with libsidplayfp
11+
* mixer
12+
- alsa: fix crash bug
913

1014
ver 0.20.4 (2017/02/01)
1115
* input

configure.ac

+1-1
Original file line numberDiff line numberDiff line change
@@ -988,7 +988,7 @@ AM_CONDITIONAL(ENABLE_VORBIS_DECODER, test x$enable_vorbis = xyes || test x$enab
988988
dnl --------------------------------- sidplay ---------------------------------
989989
if test x$enable_sidplay != xno; then
990990
dnl Check for libsidplayfp first
991-
PKG_CHECK_MODULES([SIDPLAY], [libsidplayfp libsidutils],
991+
PKG_CHECK_MODULES([SIDPLAY], [libsidplayfp],
992992
[found_sidplayfp=yes],
993993
[found_sidplayfp=no])
994994
found_sidplay=$found_sidplayfp

src/event/Call.cxx

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ class BlockingCallMonitor final
7979
void
8080
BlockingCall(EventLoop &loop, std::function<void()> &&f)
8181
{
82-
if (loop.IsInside()) {
82+
if (loop.IsInsideOrNull()) {
8383
/* we're already inside the loop - we can simply call
8484
the function */
8585
f();

src/event/Loop.cxx

+2-1
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,9 @@ EventLoop::Run()
222222
#ifndef NDEBUG
223223
assert(busy);
224224
assert(thread.IsInside());
225-
thread = ThreadId::Null();
226225
#endif
226+
227+
thread = ThreadId::Null();
227228
}
228229

229230
void

src/event/Loop.hxx

+6-2
Original file line numberDiff line numberDiff line change
@@ -212,12 +212,16 @@ public:
212212
}
213213
#endif
214214

215-
#ifndef NDEBUG
215+
/**
216+
* Like IsInside(), but also returns true if the thread has
217+
* already ended (or was not started yet). This is useful for
218+
* code which may run during startup or shutdown, when events
219+
* are not yet/anymore handled.
220+
*/
216221
gcc_pure
217222
bool IsInsideOrNull() const {
218223
return thread.IsNull() || thread.IsInside();
219224
}
220-
#endif
221225
};
222226

223227
#endif /* MAIN_NOTIFY_H */

src/event/MultiSocketMonitor.cxx

+9-3
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,18 @@
2828
#endif
2929

3030
MultiSocketMonitor::MultiSocketMonitor(EventLoop &_loop)
31-
:IdleMonitor(_loop), TimeoutMonitor(_loop), ready(false) {
31+
:IdleMonitor(_loop), TimeoutMonitor(_loop) {
3232
}
3333

34-
MultiSocketMonitor::~MultiSocketMonitor()
34+
void
35+
MultiSocketMonitor::Reset()
3536
{
36-
// TODO
37+
assert(GetEventLoop().IsInsideOrNull());
38+
39+
fds.clear();
40+
IdleMonitor::Cancel();
41+
TimeoutMonitor::Cancel();
42+
ready = refresh = false;
3743
}
3844

3945
void

src/event/MultiSocketMonitor.hxx

+50-3
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,19 @@ class MultiSocketMonitor : IdleMonitor, TimeoutMonitor
9696

9797
friend class SingleFD;
9898

99-
bool ready, refresh;
99+
/**
100+
* DispatchSockets() should be called.
101+
*/
102+
bool ready = false;
103+
104+
/**
105+
* PrepareSockets() should be called.
106+
*
107+
* Note that this doesn't need to be initialized by the
108+
* constructor; this class is activated with the first
109+
* InvalidateSockets() call, which initializes this flag.
110+
*/
111+
bool refresh;
100112

101113
std::forward_list<SingleFD> fds;
102114

@@ -107,11 +119,26 @@ public:
107119
static constexpr unsigned HANGUP = SocketMonitor::HANGUP;
108120

109121
MultiSocketMonitor(EventLoop &_loop);
110-
~MultiSocketMonitor();
111122

112123
using IdleMonitor::GetEventLoop;
113124

114-
public:
125+
/**
126+
* Clear the socket list and disable all #EventLoop
127+
* registrations. Run this in the #EventLoop thread before
128+
* destroying this object.
129+
*
130+
* Later, this object can be reused and reactivated by calling
131+
* InvalidateSockets().
132+
*
133+
* Note that this class doesn't have a destructor which calls
134+
* this method, because this would be racy and thus pointless:
135+
* at the time ~MultiSocketMonitor() is called, our virtual
136+
* methods have been morphed to be pure again, and in the
137+
* meantime the #EventLoop thread could invoke those pure
138+
* methods.
139+
*/
140+
void Reset();
141+
115142
/**
116143
* Invalidate the socket list. A call to PrepareSockets() is
117144
* scheduled which will then update the list.
@@ -121,12 +148,19 @@ public:
121148
IdleMonitor::Schedule();
122149
}
123150

151+
/**
152+
* Add one socket to the list of monitored sockets.
153+
*
154+
* May only be called from PrepareSockets().
155+
*/
124156
void AddSocket(int fd, unsigned events) {
125157
fds.emplace_front(*this, fd, events);
126158
}
127159

128160
/**
129161
* Remove all sockets.
162+
*
163+
* May only be called from PrepareSockets().
130164
*/
131165
void ClearSocketList();
132166

@@ -135,6 +169,8 @@ public:
135169
* each one; its return value is the events bit mask. A
136170
* return value of 0 means the socket will be removed from the
137171
* list.
172+
*
173+
* May only be called from PrepareSockets().
138174
*/
139175
template<typename E>
140176
void UpdateSocketList(E &&e) {
@@ -157,15 +193,26 @@ public:
157193
/**
158194
* Replace the socket list with the given file descriptors.
159195
* The given pollfd array will be modified by this method.
196+
*
197+
* May only be called from PrepareSockets().
160198
*/
161199
void ReplaceSocketList(pollfd *pfds, unsigned n);
162200
#endif
163201

164202
protected:
165203
/**
204+
* Override this method and update the socket registrations.
205+
* To do that, call AddSocket(), ClearSocketList(),
206+
* UpdateSocketList() and ReplaceSocketList().
207+
*
166208
* @return timeout or a negative value for no timeout
167209
*/
168210
virtual std::chrono::steady_clock::duration PrepareSockets() = 0;
211+
212+
/**
213+
* At least one socket is ready or the timeout has expired.
214+
* This method should be used to perform I/O.
215+
*/
169216
virtual void DispatchSockets() = 0;
170217

171218
private:

src/input/plugins/AlsaInputPlugin.cxx

+2-6
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,8 @@ class AlsaInputStream final
9999
}
100100

101101
~AlsaInputStream() {
102-
/* ClearSocketList must be called from within the
103-
IOThread; if we don't do it manually here, the
104-
~MultiSocketMonitor() will do it in the current
105-
thread */
106102
BlockingCall(MultiSocketMonitor::GetEventLoop(), [this](){
107-
ClearSocketList();
103+
MultiSocketMonitor::Reset();
108104
});
109105

110106
snd_pcm_close(capture_handle);
@@ -182,7 +178,7 @@ AlsaInputStream::PrepareSockets()
182178
}
183179

184180
int count = snd_pcm_poll_descriptors_count(capture_handle);
185-
if (count < 0) {
181+
if (count <= 0) {
186182
ClearSocketList();
187183
return std::chrono::steady_clock::duration(-1);
188184
}

src/mixer/plugins/AlsaMixerPlugin.cxx

+8-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "output/OutputAPI.hxx"
2424
#include "event/MultiSocketMonitor.hxx"
2525
#include "event/DeferredMonitor.hxx"
26+
#include "event/Call.hxx"
2627
#include "util/ASCII.hxx"
2728
#include "util/ReusableArray.hxx"
2829
#include "util/Domain.hxx"
@@ -53,6 +54,12 @@ class AlsaMixerMonitor final : MultiSocketMonitor, DeferredMonitor {
5354
DeferredMonitor::Schedule();
5455
}
5556

57+
~AlsaMixerMonitor() {
58+
BlockingCall(MultiSocketMonitor::GetEventLoop(), [this](){
59+
MultiSocketMonitor::Reset();
60+
});
61+
}
62+
5663
private:
5764
virtual void RunDeferred() override {
5865
InvalidateSockets();
@@ -102,7 +109,7 @@ AlsaMixerMonitor::PrepareSockets()
102109
}
103110

104111
int count = snd_mixer_poll_descriptors_count(mixer);
105-
if (count < 0)
112+
if (count <= 0)
106113
count = 0;
107114

108115
struct pollfd *pfds = pfd_buffer.Get(count);

0 commit comments

Comments
 (0)