summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Sperling <stsp@openbsd.org>2013-11-21 18:47:42 +0100
committerTanu Kaskinen <tanu.kaskinen@linux.intel.com>2013-11-22 17:31:11 +0200
commitd8e2b3a78c6c60ffec9a115a0e35a3cb4c68598f (patch)
treebe2de26e622f80c94b4bc3c15454f0453b4c0452
parent303cff04eb8c091fb0c7665440797fc56f07d570 (diff)
Fix undefined behaviour in pulseaudio --start.
Don't call pthread_join() to join a thread from a different process than the thread was created in. Doing so can lead to undefined behaviour. On OpenBSD, the symptom was a pulseaudio process with a single thread waiting forever for other threads to join. Since that process also held the autospawn lock, starting new pulseaudio processes with --start kept failing. The problem was analyzed with help from Philip Guenther. This patch adds a pa_thread_free_nojoin() function which can be used to free resources for a thread without a join, as suggested by Tanu Kaskinen. See https://bugs.freedesktop.org/show_bug.cgi?id=71738
-rw-r--r--src/pulsecore/lock-autospawn.c9
-rw-r--r--src/pulsecore/thread-posix.c7
-rw-r--r--src/pulsecore/thread.h1
3 files changed, 16 insertions, 1 deletions
diff --git a/src/pulsecore/lock-autospawn.c b/src/pulsecore/lock-autospawn.c
index 72806f831..82518dbac 100644
--- a/src/pulsecore/lock-autospawn.c
+++ b/src/pulsecore/lock-autospawn.c
@@ -114,8 +114,15 @@ static void unref(bool after_fork) {
if (n_ref > 0)
return;
+ /* Join threads only in the process the new thread was created in
+ * to avoid undefined behaviour.
+ * POSIX.1-2008 XSH 2.9.2 Thread IDs: "applications should only assume
+ * that thread IDs are usable and unique within a single process." */
if (thread) {
- pa_thread_free(thread);
+ if (after_fork)
+ pa_thread_free_nojoin(thread);
+ else
+ pa_thread_free(thread);
thread = NULL;
}
diff --git a/src/pulsecore/thread-posix.c b/src/pulsecore/thread-posix.c
index b422ab098..5c19b43f5 100644
--- a/src/pulsecore/thread-posix.c
+++ b/src/pulsecore/thread-posix.c
@@ -127,6 +127,13 @@ void pa_thread_free(pa_thread *t) {
pa_xfree(t);
}
+void pa_thread_free_nojoin(pa_thread *t) {
+ pa_assert(t);
+
+ pa_xfree(t->name);
+ pa_xfree(t);
+}
+
int pa_thread_join(pa_thread *t) {
pa_assert(t);
pa_assert(t->thread_func);
diff --git a/src/pulsecore/thread.h b/src/pulsecore/thread.h
index 9cabb8995..a6e5f4240 100644
--- a/src/pulsecore/thread.h
+++ b/src/pulsecore/thread.h
@@ -39,6 +39,7 @@ typedef void (*pa_thread_func_t) (void *userdata);
pa_thread* pa_thread_new(const char *name, pa_thread_func_t thread_func, void *userdata);
void pa_thread_free(pa_thread *t);
+void pa_thread_free_nojoin(pa_thread *t);
int pa_thread_join(pa_thread *t);
int pa_thread_is_running(pa_thread *t);
pa_thread *pa_thread_self(void);