]> code.delx.au - pulseaudio/blobdiff - src/daemon/main.c
volume: Rename 'sync volume' to 'deferred volume'.
[pulseaudio] / src / daemon / main.c
index 533c4c3237d8091c8fbaef70ba81e642624f19e0..e2e4a810a3d23375f820b11def360289d925a259 100644 (file)
@@ -33,7 +33,6 @@
 #include <stddef.h>
 #include <ltdl.h>
 #include <limits.h>
-#include <fcntl.h>
 #include <unistd.h>
 #include <locale.h>
 #include <sys/types.h>
 #include <pulse/mainloop-signal.h>
 #include <pulse/timeval.h>
 #include <pulse/xmalloc.h>
-#include <pulse/i18n.h>
 
+#include <pulsecore/i18n.h>
 #include <pulsecore/lock-autospawn.h>
 #include <pulsecore/socket.h>
 #include <pulsecore/core-error.h>
 #include <pulsecore/core-rtclock.h>
+#include <pulsecore/core-scache.h>
 #include <pulsecore/core.h>
-#include <pulsecore/memblock.h>
 #include <pulsecore/module.h>
 #include <pulsecore/cli-command.h>
 #include <pulsecore/log.h>
 #include <pulsecore/sioman.h>
 #include <pulsecore/cli-text.h>
 #include <pulsecore/pid.h>
-#include <pulsecore/namereg.h>
 #include <pulsecore/random.h>
 #include <pulsecore/macro.h>
-#include <pulsecore/mutex.h>
-#include <pulsecore/thread.h>
-#include <pulsecore/once.h>
 #include <pulsecore/shm.h>
 #include <pulsecore/memtrap.h>
+#include <pulsecore/strlist.h>
 #ifdef HAVE_DBUS
 #include <pulsecore/dbus-shared.h>
 #endif
 #include <pulsecore/cpu-arm.h>
 #include <pulsecore/cpu-x86.h>
+#include <pulsecore/cpu-orc.h>
 
 #include "cmdline.h"
 #include "cpulimit.h"
@@ -381,7 +378,7 @@ static pa_dbus_connection *register_dbus_name(pa_core *c, DBusBusType bus, const
     if (dbus_error_is_set(&error))
         pa_log_error("Failed to acquire %s: %s: %s", name, error.name, error.message);
     else
-        pa_log_error("D-Bus name %s already taken. Weird shit!", name);
+        pa_log_error("D-Bus name %s already taken.", name);
 
     /* PA cannot be started twice by the same user and hence we can
      * ignore mostly the case that a name is already taken. */
@@ -409,6 +406,7 @@ int main(int argc, char *argv[]) {
     const char *e;
 #ifdef HAVE_FORK
     int daemon_pipe[2] = { -1, -1 };
+    int daemon_pipe2[2] = { -1, -1 };
 #endif
 #ifdef OS_IS_WIN32
     pa_time_event *win32_timer;
@@ -671,10 +669,49 @@ int main(int argc, char *argv[]) {
     }
 
     if (conf->cmd == PA_CMD_START && (configured_address = check_configured_address())) {
-        pa_log_notice(_("User-configured server at %s, not autospawning."), configured_address);
+        /* There is an server address in our config, but where did it come from?
+         * By default a standard X11 login will load module-x11-publish which will
+         * inject PULSE_SERVER X11 property. If the PA daemon crashes, we will end
+         * up hitting this code path. So we have to check to see if our configured_address
+         * is the same as the value that would go into this property so that we can
+         * recover (i.e. autospawn) from a crash.
+         */
+        char *ufn;
+        pa_bool_t start_anyway = FALSE;
+
+        if ((ufn = pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET))) {
+            char *id;
+
+            if ((id = pa_machine_id())) {
+                pa_strlist *server_list;
+                char formatted_ufn[256];
+
+                pa_snprintf(formatted_ufn, sizeof(formatted_ufn), "{%s}unix:%s", id, ufn);
+                pa_xfree(id);
+
+                if ((server_list = pa_strlist_parse(configured_address))) {
+                    char *u = NULL;
+
+                    /* We only need to check the first server */
+                    server_list = pa_strlist_pop(server_list, &u);
+                    pa_strlist_free(server_list);
+
+                    start_anyway = (u && pa_streq(formatted_ufn, u));
+                    pa_xfree(u);
+                }
+            }
+            pa_xfree(ufn);
+        }
+
+        if (!start_anyway) {
+            pa_log_notice(_("User-configured server at %s, refusing to start/autospawn."), configured_address);
+            pa_xfree(configured_address);
+            retval = 0;
+            goto finish;
+        }
+
+        pa_log_notice(_("User-configured server at %s, which appears to be local. Probing deeper."), configured_address);
         pa_xfree(configured_address);
-        retval = 0;
-        goto finish;
     }
 
     if (conf->system_instance && !conf->disallow_exit)
@@ -712,7 +749,9 @@ int main(int argc, char *argv[]) {
     }
 
     if (conf->daemonize) {
+#ifdef HAVE_FORK
         pid_t child;
+#endif
 
         if (pa_stdio_acquire() < 0) {
             pa_log(_("Failed to acquire stdio."));
@@ -727,6 +766,7 @@ int main(int argc, char *argv[]) {
 
         if ((child = fork()) < 0) {
             pa_log(_("fork() failed: %s"), pa_cstrerror(errno));
+            pa_close_pipe(daemon_pipe);
             goto finish;
         }
 
@@ -778,21 +818,54 @@ int main(int argc, char *argv[]) {
         }
 #endif
 
+#ifdef HAVE_FORK
         /* We now are a session and process group leader. Let's fork
          * again and let the father die, so that we'll become a
          * process that can never acquire a TTY again, in a session and
          * process group without leader */
 
-#ifdef HAVE_FORK
+        if (pipe(daemon_pipe2) < 0) {
+            pa_log(_("pipe() failed: %s"), pa_cstrerror(errno));
+            goto finish;
+        }
+
         if ((child = fork()) < 0) {
             pa_log(_("fork() failed: %s"), pa_cstrerror(errno));
+            pa_close_pipe(daemon_pipe2);
             goto finish;
         }
 
         if (child != 0) {
-            retval = 0;
+            ssize_t n;
+            /* Father */
+
+            pa_assert_se(pa_close(daemon_pipe2[1]) == 0);
+            daemon_pipe2[1] = -1;
+
+            if ((n = pa_loop_read(daemon_pipe2[0], &retval, sizeof(retval), NULL)) != sizeof(retval)) {
+
+                if (n < 0)
+                    pa_log(_("read() failed: %s"), pa_cstrerror(errno));
+
+                retval = 1;
+            }
+
+            /* We now have to take care of signalling the first fork with
+             * the return value we've received from this fork... */
+            pa_assert(daemon_pipe[1] >= 0);
+
+            pa_loop_write(daemon_pipe[1], &retval, sizeof(retval), NULL);
+            pa_close(daemon_pipe[1]);
+            daemon_pipe[1] = -1;
+
             goto finish;
         }
+
+        pa_assert_se(pa_close(daemon_pipe2[0]) == 0);
+        daemon_pipe2[0] = -1;
+
+        /* We no longer need the (first) daemon_pipe as it's handled in our child above */
+        pa_close_pipe(daemon_pipe);
 #endif
 
 #ifdef SIGTTOU
@@ -943,8 +1016,8 @@ int main(int argc, char *argv[]) {
     c->default_channel_map = conf->default_channel_map;
     c->default_n_fragments = conf->default_n_fragments;
     c->default_fragment_size_msec = conf->default_fragment_size_msec;
-    c->sync_volume_safety_margin_usec = conf->sync_volume_safety_margin_usec;
-    c->sync_volume_extra_delay_usec = conf->sync_volume_extra_delay_usec;
+    c->deferred_volume_safety_margin_usec = conf->deferred_volume_safety_margin_usec;
+    c->deferred_volume_extra_delay_usec = conf->deferred_volume_extra_delay_usec;
     c->exit_idle_time = conf->exit_idle_time;
     c->scache_idle_time = conf->scache_idle_time;
     c->resample_method = conf->resample_method;
@@ -952,7 +1025,7 @@ int main(int argc, char *argv[]) {
     c->realtime_scheduling = !!conf->realtime_scheduling;
     c->disable_remixing = !!conf->disable_remixing;
     c->disable_lfe_remixing = !!conf->disable_lfe_remixing;
-    c->sync_volume = !!conf->sync_volume;
+    c->deferred_volume = !!conf->deferred_volume;
     c->running_as_daemon = !!conf->daemonize;
     c->disallow_exit = conf->disallow_exit;
     c->flat_volumes = conf->flat_volumes;
@@ -1045,11 +1118,11 @@ int main(int argc, char *argv[]) {
 #endif
 
 #ifdef HAVE_FORK
-    if (daemon_pipe[1] >= 0) {
+    if (daemon_pipe2[1] >= 0) {
         int ok = 0;
-        pa_loop_write(daemon_pipe[1], &ok, sizeof(ok), NULL);
-        pa_close(daemon_pipe[1]);
-        daemon_pipe[1] = -1;
+        pa_loop_write(daemon_pipe2[1], &ok, sizeof(ok), NULL);
+        pa_close(daemon_pipe2[1]);
+        daemon_pipe2[1] = -1;
     }
 #endif
 
@@ -1084,6 +1157,11 @@ finish:
 #endif
 
     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 */
+        pa_module_unload_all(c);
+        pa_scache_free_all(c);
+
         pa_core_unref(c);
         pa_log_info(_("Daemon terminated."));
     }
@@ -1094,9 +1172,14 @@ finish:
     pa_signal_done();
 
 #ifdef HAVE_FORK
+    /* If we have daemon_pipe[1] still open, this means we've failed after
+     * the first fork, but before the second. Therefore just write to it. */
     if (daemon_pipe[1] >= 0)
         pa_loop_write(daemon_pipe[1], &retval, sizeof(retval), NULL);
+    else if (daemon_pipe2[1] >= 0)
+        pa_loop_write(daemon_pipe2[1], &retval, sizeof(retval), NULL);
 
+    pa_close_pipe(daemon_pipe2);
     pa_close_pipe(daemon_pipe);
 #endif