mirror of
https://github.com/Ryujinx/libsoundio.git
synced 2025-01-03 15:25:42 +00:00
ALSA: fix potential cleanup deadlock
The main ALSA poll now includes another file descriptor which we write to when cleaning up, to ensure that the poll terminates when soundio_outstream_destroy is invoked. closes #36
This commit is contained in:
parent
8f1e1b8752
commit
f61acfd953
40
src/alsa.c
40
src/alsa.c
|
@ -36,6 +36,17 @@ static void wakeup_device_poll(struct SoundIoAlsa *sia) {
|
|||
}
|
||||
}
|
||||
|
||||
static void wakeup_outstream_poll(struct SoundIoOutStreamAlsa *osa) {
|
||||
ssize_t amt = write(osa->poll_exit_pipe_fd[1], "a", 1);
|
||||
if (amt == -1) {
|
||||
assert(errno != EBADF);
|
||||
assert(errno != EIO);
|
||||
assert(errno != ENOSPC);
|
||||
assert(errno != EPERM);
|
||||
assert(errno != EPIPE);
|
||||
}
|
||||
}
|
||||
|
||||
static void destroy_alsa(struct SoundIoPrivate *si) {
|
||||
struct SoundIoAlsa *sia = &si->backend_data.alsa;
|
||||
|
||||
|
@ -970,6 +981,7 @@ static void outstream_destroy_alsa(struct SoundIoPrivate *si, struct SoundIoOutS
|
|||
|
||||
if (osa->thread) {
|
||||
atomic_flag_clear(&osa->thread_exit_flag);
|
||||
wakeup_outstream_poll(osa);
|
||||
soundio_os_thread_destroy(osa->thread);
|
||||
osa->thread = NULL;
|
||||
}
|
||||
|
@ -1034,13 +1046,15 @@ static int outstream_wait_for_poll(struct SoundIoOutStreamPrivate *os) {
|
|||
int err;
|
||||
unsigned short revents;
|
||||
for (;;) {
|
||||
if ((err = poll(osa->poll_fds, osa->poll_fd_count, -1)) < 0) {
|
||||
return err;
|
||||
if ((err = poll(osa->poll_fds, osa->poll_fd_count_with_extra, -1)) < 0) {
|
||||
return SoundIoErrorStreaming;
|
||||
}
|
||||
if (!atomic_flag_test_and_set(&osa->thread_exit_flag))
|
||||
return SoundIoErrorInterrupted;
|
||||
if ((err = snd_pcm_poll_descriptors_revents(osa->handle,
|
||||
osa->poll_fds, osa->poll_fd_count, &revents)) < 0)
|
||||
{
|
||||
return err;
|
||||
return SoundIoErrorStreaming;
|
||||
}
|
||||
if (revents & (POLLERR|POLLNVAL|POLLHUP)) {
|
||||
return 0;
|
||||
|
@ -1113,10 +1127,10 @@ static void outstream_thread_run(void *arg) {
|
|||
case SND_PCM_STATE_RUNNING:
|
||||
case SND_PCM_STATE_PAUSED:
|
||||
{
|
||||
if ((err = outstream_wait_for_poll(os)) < 0) {
|
||||
if (!atomic_flag_test_and_set(&osa->thread_exit_flag))
|
||||
if ((err = outstream_wait_for_poll(os))) {
|
||||
if (err == SoundIoErrorInterrupted)
|
||||
return;
|
||||
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
||||
outstream->error_callback(outstream, err);
|
||||
return;
|
||||
}
|
||||
if (!atomic_flag_test_and_set(&osa->thread_exit_flag))
|
||||
|
@ -1379,7 +1393,8 @@ static int outstream_open_alsa(struct SoundIoPrivate *si, struct SoundIoOutStrea
|
|||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
|
||||
osa->poll_fds = ALLOCATE(struct pollfd, osa->poll_fd_count);
|
||||
osa->poll_fd_count_with_extra = osa->poll_fd_count + 1;
|
||||
osa->poll_fds = ALLOCATE(struct pollfd, osa->poll_fd_count_with_extra);
|
||||
if (!osa->poll_fds) {
|
||||
outstream_destroy_alsa(si, os);
|
||||
return SoundIoErrorNoMem;
|
||||
|
@ -1390,6 +1405,17 @@ static int outstream_open_alsa(struct SoundIoPrivate *si, struct SoundIoOutStrea
|
|||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
|
||||
struct pollfd *extra_fd = &osa->poll_fds[osa->poll_fd_count];
|
||||
if (pipe2(osa->poll_exit_pipe_fd, O_NONBLOCK)) {
|
||||
assert(errno != EFAULT);
|
||||
assert(errno != EINVAL);
|
||||
assert(errno == EMFILE || errno == ENFILE);
|
||||
outstream_destroy_alsa(si, os);
|
||||
return SoundIoErrorSystemResources;
|
||||
}
|
||||
extra_fd->fd = osa->poll_exit_pipe_fd[0];
|
||||
extra_fd->events = POLLIN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,9 @@ struct SoundIoOutStreamAlsa {
|
|||
int sample_buffer_size;
|
||||
char *sample_buffer;
|
||||
int poll_fd_count;
|
||||
int poll_fd_count_with_extra;
|
||||
struct pollfd *poll_fds;
|
||||
int poll_exit_pipe_fd[2];
|
||||
struct SoundIoOsThread *thread;
|
||||
atomic_flag thread_exit_flag;
|
||||
snd_pcm_uframes_t period_size;
|
||||
|
|
Loading…
Reference in a new issue