From 277822053c2f070940e5a996b9a6d95645d74590 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 1 Aug 2009 03:10:19 +0200 Subject: autospawn: if creating the lock file fails, pass error code cleanly back to main process This makes sure PA clients don't hang if $HOME is for some reason unsuitable for autospawn lockfiles. Closes #539 --- src/pulsecore/lock-autospawn.c | 66 ++++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/pulsecore/lock-autospawn.c b/src/pulsecore/lock-autospawn.c index 4436974d..c0df7938 100644 --- a/src/pulsecore/lock-autospawn.c +++ b/src/pulsecore/lock-autospawn.c @@ -55,10 +55,16 @@ static pa_mutex *mutex; static unsigned n_ref = 0; static int lock_fd = -1; static pa_mutex *lock_fd_mutex = NULL; -static pa_bool_t taken = FALSE; -static pa_thread *thread; +static pa_thread *thread = NULL; static int pipe_fd[2] = { -1, -1 }; +static enum { + STATE_IDLE, + STATE_OWNING, + STATE_TAKEN, + STATE_FAILED +} state = STATE_IDLE; + static void destroy_mutex(void) PA_GCC_DESTRUCTOR; static int ref(void) { @@ -67,15 +73,16 @@ static int ref(void) { pa_assert(pipe_fd[0] >= 0); pa_assert(pipe_fd[1] >= 0); + pa_assert(lock_fd_mutex); n_ref++; return 0; } - pa_assert(lock_fd < 0); pa_assert(!lock_fd_mutex); - pa_assert(!taken); + pa_assert(state == STATE_IDLE); + pa_assert(lock_fd < 0); pa_assert(!thread); pa_assert(pipe_fd[0] < 0); pa_assert(pipe_fd[1] < 0); @@ -83,14 +90,14 @@ static int ref(void) { if (pipe(pipe_fd) < 0) return -1; - lock_fd_mutex = pa_mutex_new(FALSE, FALSE); - pa_make_fd_cloexec(pipe_fd[0]); pa_make_fd_cloexec(pipe_fd[1]); pa_make_fd_nonblock(pipe_fd[1]); pa_make_fd_nonblock(pipe_fd[0]); + lock_fd_mutex = pa_mutex_new(FALSE, FALSE); + n_ref = 1; return 0; } @@ -107,15 +114,18 @@ static void unref(pa_bool_t after_fork) { if (n_ref > 0) return; - pa_assert(!taken); - if (thread) { pa_thread_free(thread); thread = NULL; } pa_mutex_lock(lock_fd_mutex); - if (lock_fd >= 0) { + + pa_assert(state != STATE_TAKEN); + + if (state == STATE_OWNING) { + + pa_assert(lock_fd >= 0); if (after_fork) pa_close(lock_fd); @@ -127,10 +137,12 @@ static void unref(pa_bool_t after_fork) { pa_unlock_lockfile(lf, lock_fd); pa_xfree(lf); - - lock_fd = -1; } } + + lock_fd = -1; + state = STATE_IDLE; + pa_mutex_unlock(lock_fd_mutex); pa_mutex_free(lock_fd_mutex); @@ -205,15 +217,24 @@ static void thread_func(void *u) { if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK))) { pa_log_warn(_("Cannot access autospawn lock.")); - goto finish; + goto fail; } if ((fd = pa_lock_lockfile(lf)) < 0) - goto finish; + goto fail; pa_mutex_lock(lock_fd_mutex); - pa_assert(lock_fd < 0); + pa_assert(state == STATE_IDLE); lock_fd = fd; + state = STATE_OWNING; + pa_mutex_unlock(lock_fd_mutex); + + goto finish; + +fail: + pa_mutex_lock(lock_fd_mutex); + pa_assert(state == STATE_IDLE); + state = STATE_FAILED; pa_mutex_unlock(lock_fd_mutex); finish: @@ -238,12 +259,10 @@ static void create_mutex(void) { } static void destroy_mutex(void) { - if (mutex) pa_mutex_free(mutex); } - int pa_autospawn_lock_init(void) { int ret = -1; @@ -273,13 +292,18 @@ int pa_autospawn_lock_acquire(pa_bool_t block) { empty_pipe(); - if (lock_fd >= 0 && !taken) { - taken = TRUE; + if (state == STATE_OWNING) { + state = STATE_TAKEN; ret = 1; break; } - if (lock_fd < 0) + if (state == STATE_FAILED) { + ret = -1; + break; + } + + if (state == STATE_IDLE) if (start_thread() < 0) break; @@ -310,8 +334,8 @@ void pa_autospawn_lock_release(void) { pa_mutex_lock(mutex); pa_assert(n_ref >= 1); - pa_assert(taken); - taken = FALSE; + pa_assert(state == STATE_TAKEN); + state = STATE_OWNING; ping(); -- cgit