[pulseaudio-discuss] [RFC PATCH] inotify-wrapper: Quit daemon if pid file is removed

David Henningsson david.henningsson at canonical.com
Wed Apr 17 08:56:12 PDT 2013


XDG_RUNTIME_DIR is deleted on logout (according to xdg spec), and
that's where we keep our pid file and native protocol socket.

When these two files are deleted, it makes no sense to run anymore,
so quit. Hanging around is not only sloppy, but can also be harmful:
e g, if esd compat module is loaded, it will bind to the esd address.
When a new pulseaudio process is created on next login of the same
user, pulseaudio cannot start because the esd address is occupied.

Buglink: https://bugs.launchpad.net/bugs/1167192
Signed-off-by: David Henningsson <david.henningsson at canonical.com>
---

This patch is probably unfinished, because I don't know how to deal with this
on win32 systems etc. I had to come up with a quick fix for Ubuntu 13.04, and
this is what I came up with.

 src/Makefile.am                 |    1 +
 src/daemon/main.c               |   20 ++++++++-
 src/pulsecore/inotify-wrapper.c |   93 +++++++++++++++++++++++++++++++++++++++
 src/pulsecore/inotify-wrapper.h |   13 ++++++
 src/pulsecore/pid.c             |    5 +++
 src/pulsecore/pid.h             |    1 +
 6 files changed, 131 insertions(+), 2 deletions(-)
 create mode 100644 src/pulsecore/inotify-wrapper.c
 create mode 100644 src/pulsecore/inotify-wrapper.h

diff --git a/src/Makefile.am b/src/Makefile.am
index a621a30..b8fb4b0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -865,6 +865,7 @@ libpulsecore_ at PA_MAJORMINOR@_la_SOURCES = \
 		pulsecore/core.c pulsecore/core.h \
 		pulsecore/fdsem.c pulsecore/fdsem.h \
 		pulsecore/hook-list.c pulsecore/hook-list.h \
+		pulsecore/inotify-wrapper.c pulsecore/inotify-wrapper.h \
 		pulsecore/ltdl-helper.c pulsecore/ltdl-helper.h \
 		pulsecore/modargs.c pulsecore/modargs.h \
 		pulsecore/modinfo.c pulsecore/modinfo.h \
diff --git a/src/daemon/main.c b/src/daemon/main.c
index c18524f..3016538 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -74,6 +74,7 @@
 #include <pulsecore/core-rtclock.h>
 #include <pulsecore/core-scache.h>
 #include <pulsecore/core.h>
+#include <pulsecore/inotify-wrapper.h>
 #include <pulsecore/module.h>
 #include <pulsecore/cli-command.h>
 #include <pulsecore/log.h>
@@ -360,6 +361,15 @@ static char *check_configured_address(void) {
     return default_server;
 }
 
+static bool valid_pid_file = false;
+static void pid_file_deleted(void *userdata)
+{
+    pa_core *c = userdata;
+    pa_log_info("Our pid file has been deleted (probably due to session logout), quitting...");
+    valid_pid_file = false;
+    pa_core_exit(c, true, 0);
+}
+
 #ifdef HAVE_DBUS
 static pa_dbus_connection *register_dbus_name(pa_core *c, DBusBusType bus, const char* name) {
     DBusError error;
@@ -402,7 +412,6 @@ int main(int argc, char *argv[]) {
     char *s;
     char *configured_address;
     int r = 0, retval = 1, d = 0;
-    pa_bool_t valid_pid_file = FALSE;
     pa_bool_t ltdl_init = FALSE;
     int passed_fd = -1;
     const char *e;
@@ -414,6 +423,7 @@ int main(int argc, char *argv[]) {
     pa_time_event *win32_timer;
     struct timeval win32_tv;
 #endif
+    pa_inotify *pid_monitor = NULL;
     int autospawn_fd = -1;
     pa_bool_t autospawn_locked = FALSE;
 #ifdef HAVE_DBUS
@@ -984,7 +994,7 @@ int main(int argc, char *argv[]) {
             goto finish;
         }
 
-        valid_pid_file = TRUE;
+        valid_pid_file = true;
     }
 
     pa_disable_sigpipe();
@@ -1014,6 +1024,9 @@ int main(int argc, char *argv[]) {
         goto finish;
     }
 
+    if (valid_pid_file)
+        pid_monitor = pa_inotify_start(pa_pid_file_name(), c, pid_file_deleted, c);
+
     c->default_sample_spec = conf->default_sample_spec;
     c->alternate_sample_rate = conf->alternate_sample_rate;
     c->default_channel_map = conf->default_channel_map;
@@ -1161,6 +1174,9 @@ finish:
         pa_mainloop_get_api(mainloop)->time_free(win32_timer);
 #endif
 
+    if (pid_monitor)
+        pa_inotify_stop(pid_monitor);
+
     if (c) {
         /* Ensure all the modules/samples are unloaded when the core is still ref'ed,
          * as unlink callback hooks in modules may need the core to be ref'ed */
diff --git a/src/pulsecore/inotify-wrapper.c b/src/pulsecore/inotify-wrapper.c
new file mode 100644
index 0000000..00e36c6
--- /dev/null
+++ b/src/pulsecore/inotify-wrapper.c
@@ -0,0 +1,93 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <fcntl.h>
+#include <sys/inotify.h>
+#include <errno.h>
+
+#include "inotify-wrapper.h"
+#include <pulse/mainloop.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/core-error.h>
+
+struct pa_inotify {
+    char *filename;
+    void *callback_data;
+    pa_inotify_cb callback;
+    int fd;
+    pa_io_event *io_event;
+    pa_core *core;
+};
+
+
+static void inotify_cb(
+        pa_mainloop_api *a,
+        pa_io_event *e,
+        int fd,
+        pa_io_event_flags_t events,
+        void *userdata) {
+
+    pa_inotify *i = userdata;
+    int pid_fd;
+
+    pa_assert(i);
+
+    pid_fd = pa_open_cloexec(i->filename, O_RDONLY
+#ifdef O_NOFOLLOW
+                       |O_NOFOLLOW
+#endif
+                       , S_IRUSR);
+
+    if (pid_fd < 0) {
+        if (i->callback)
+            i->callback(i->callback_data);
+    } else
+        pa_close(pid_fd);
+}
+
+
+pa_inotify *pa_inotify_start(const char *filename, void *userdata, pa_inotify_cb cb, pa_core *core) {
+
+    pa_inotify *i = pa_xnew0(pa_inotify, 1);
+    pa_assert(i);
+
+    i->core = core;
+    pa_core_ref(core);
+
+    i->filename = pa_xstrdup(filename);
+    i->callback_data = userdata;
+    i->callback = cb;
+    i->fd = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
+
+    if (i->fd < 0) {
+        pa_log("inotify_init1() failed: %s", pa_cstrerror(errno));
+        pa_inotify_stop(i);
+        return NULL;
+    }
+
+    if (inotify_add_watch(i->fd, filename, IN_ATTRIB|IN_CLOSE_WRITE|IN_DELETE_SELF|IN_MOVE_SELF) < 0) {
+        pa_log("inotify_add_watch() failed: %s", pa_cstrerror(errno));
+        pa_inotify_stop(i);
+        return NULL;
+    }
+
+    pa_assert_se(i->io_event = core->mainloop->io_new(core->mainloop, i->fd, PA_IO_EVENT_INPUT, inotify_cb, i));
+
+    return i;
+}
+
+
+void pa_inotify_stop(pa_inotify *i) {
+
+    pa_assert(i);
+
+    if (i->io_event)
+        i->core->mainloop->io_free(i->io_event);
+    if (i->fd)
+        pa_close(i->fd);
+    pa_xfree(i->filename);
+    if (i->core)
+        pa_core_unref(i->core);
+    pa_xfree(i);
+}
diff --git a/src/pulsecore/inotify-wrapper.h b/src/pulsecore/inotify-wrapper.h
new file mode 100644
index 0000000..e3b78d7
--- /dev/null
+++ b/src/pulsecore/inotify-wrapper.h
@@ -0,0 +1,13 @@
+#ifndef fooinotifywrapperhfoo
+#define fooinotifywrapperhfoo
+
+#include <pulsecore/core.h>
+
+typedef struct pa_inotify pa_inotify;
+
+typedef void (*pa_inotify_cb)(void *userdata);
+
+pa_inotify *pa_inotify_start(const char *filename, void *userdata, pa_inotify_cb cb, pa_core *c);
+void pa_inotify_stop(pa_inotify *i);
+
+#endif
diff --git a/src/pulsecore/pid.c b/src/pulsecore/pid.c
index 588349b..3ef3981 100644
--- a/src/pulsecore/pid.c
+++ b/src/pulsecore/pid.c
@@ -183,6 +183,11 @@ static int proc_name_ours(pid_t pid, const char *procname) {
 
 }
 
+char *pa_pid_file_name()
+{
+    return pa_runtime_path("pid");
+}
+
 /* Create a new PID file for the current process. */
 int pa_pid_file_create(const char *procname) {
     int fd = -1;
diff --git a/src/pulsecore/pid.h b/src/pulsecore/pid.h
index d8458bf..507f75e 100644
--- a/src/pulsecore/pid.h
+++ b/src/pulsecore/pid.h
@@ -22,6 +22,7 @@
   USA.
 ***/
 
+char *pa_pid_file_name(void);
 int pa_pid_file_create(const char *procname);
 int pa_pid_file_remove(void);
 int pa_pid_file_check_running(pid_t *pid, const char *procname);
-- 
1.7.9.5



More information about the pulseaudio-discuss mailing list