diff options
author | David Henningsson <david.henningsson@canonical.com> | 2015-03-23 14:39:52 +0100 |
---|---|---|
committer | David Henningsson <david.henningsson@canonical.com> | 2015-03-27 14:34:12 +0100 |
commit | 498689926fc3a13207ec07128339972cdbb2eefc (patch) | |
tree | f4f1085e06ceca17c0f87b7b081e75d0c9e5c443 | |
parent | 85f5d93306888bd3ee09497056bfa1b1e32bd51f (diff) |
thread-mq: Make pa_thread_mq_done more robust
While investigating bug 89672 it was found that pa_thread_mq_done
was called recursively. Regardless of whether the recursion should
be stopped by other means, it seems to make sense to make
pa_thread_mq_done more robust so that it can be called twice
(and even recursively) without harm.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=89672
Signed-off-by: David Henningsson <david.henningsson@canonical.com>
-rw-r--r-- | src/pulsecore/thread-mq.c | 32 |
1 files changed, 23 insertions, 9 deletions
diff --git a/src/pulsecore/thread-mq.c b/src/pulsecore/thread-mq.c index d00641dce..f4489ac31 100644 --- a/src/pulsecore/thread-mq.c +++ b/src/pulsecore/thread-mq.c @@ -148,21 +148,35 @@ void pa_thread_mq_done(pa_thread_mq *q) { * msgs, other stuff). Hence do so if we aren't currently * dispatching anyway. */ - if (!pa_asyncmsgq_dispatching(q->outq)) - pa_asyncmsgq_flush(q->outq, true); + if (q->outq && !pa_asyncmsgq_dispatching(q->outq)) { + /* Flushing the asyncmsgq can cause arbitrarily callbacks to run, + potentially causing recursion into pa_thread_mq_done again. */ + pa_asyncmsgq *z = q->outq; + pa_asyncmsgq_ref(z); + pa_asyncmsgq_flush(z, true); + pa_asyncmsgq_unref(z); + } - q->main_mainloop->io_free(q->read_main_event); - q->main_mainloop->io_free(q->write_main_event); - q->read_main_event = q->write_main_event = NULL; + if (q->main_mainloop) { + if (q->read_main_event) + q->main_mainloop->io_free(q->read_main_event); + if (q->write_main_event) + q->main_mainloop->io_free(q->write_main_event); + q->read_main_event = q->write_main_event = NULL; + } if (q->thread_mainloop) { - q->thread_mainloop->io_free(q->read_thread_event); - q->thread_mainloop->io_free(q->write_thread_event); + if (q->read_thread_event) + q->thread_mainloop->io_free(q->read_thread_event); + if (q->write_thread_event) + q->thread_mainloop->io_free(q->write_thread_event); q->read_thread_event = q->write_thread_event = NULL; } - pa_asyncmsgq_unref(q->inq); - pa_asyncmsgq_unref(q->outq); + if (q->inq) + pa_asyncmsgq_unref(q->inq); + if (q->outq) + pa_asyncmsgq_unref(q->outq); q->inq = q->outq = NULL; q->main_mainloop = NULL; |