- if (signum == SIGCHLD)
- child_watch_count ++;
-
- if (unix_signal_init_state == UNIX_SIGNAL_INITIALIZED_THREADED)
- {
- char buf[1];
- switch (signum)
- {
- case SIGCHLD:
- buf[0] = _UNIX_SIGNAL_PIPE_SIGCHLD_CHAR;
- break;
- case SIGHUP:
- buf[0] = _UNIX_SIGNAL_PIPE_SIGHUP_CHAR;
- break;
- case SIGINT:
- buf[0] = _UNIX_SIGNAL_PIPE_SIGINT_CHAR;
- break;
- case SIGTERM:
- buf[0] = _UNIX_SIGNAL_PIPE_SIGTERM_CHAR;
- break;
- default:
- /* Shouldn't happen */
- return;
- }
- write (unix_signal_wake_up_pipe[1], buf, 1);
- }
- else
- {
- /* We count on the signal interrupting the poll in the same thread. */
- switch (signum)
- {
- case SIGCHLD:
- /* Nothing to do - the handler will call waitpid() */
- break;
- case SIGHUP:
- unix_signal_state.sighup_delivered = TRUE;
- break;
- case SIGINT:
- unix_signal_state.sigint_delivered = TRUE;
- break;
- case SIGTERM:
- unix_signal_state.sigterm_delivered = TRUE;
- break;
- default:
- g_assert_not_reached ();
- break;
- }
- }
-}
-
-static void
-deliver_unix_signal (int signum)
-{
- GSList *iter;
- g_assert (signum == SIGHUP || signum == SIGINT || signum == SIGTERM);
-
- G_LOCK (unix_signal_lock);
- for (iter = unix_signal_watches; iter; iter = iter->next)
- {
- GUnixSignalWatchSource *source = iter->data;
-
- if (source->signum != signum)
- continue;
-
- source->pending = TRUE;
- }
- G_UNLOCK (unix_signal_lock);
-}
-
-static gpointer unix_signal_helper_thread (gpointer data) G_GNUC_NORETURN;
-
-/*
- * This thread is created whenever anything in GLib needs
- * to deal with UNIX signals; at present, just SIGCHLD
- * from g_child_watch_source_new().
- *
- * Note: We could eventually make this thread a more public interface
- * and allow e.g. GDBus to use it instead of its own worker thread.
- */
-static gpointer
-unix_signal_helper_thread (gpointer data)
-{
- while (1)
- {
- gchar b[128];
- ssize_t i, bytes_read;
- gboolean sigterm_received = FALSE;
- gboolean sigint_received = FALSE;
- gboolean sighup_received = FALSE;
-
- bytes_read = read (unix_signal_wake_up_pipe[0], b, sizeof (b));
- if (bytes_read < 0)
- {
- g_warning ("Failed to read from child watch wake up pipe: %s",
- strerror (errno));
- /* Not much we can do here sanely; just wait a second and hope
- * it was transient.
- */
- g_usleep (G_USEC_PER_SEC);
- continue;
- }
- for (i = 0; i < bytes_read; i++)
- {
- switch (b[i])
- {
- case _UNIX_SIGNAL_PIPE_SIGCHLD_CHAR:
- /* The child watch source will call waitpid() in its
- * prepare() and check() methods; however, we don't
- * know which pid exited, so we need to wake up
- * all contexts. Note: actually we could get the pid
- * from the "siginfo_t" via the handler, but to pass
- * that info down the pipe would require a more structured
- * data stream (as opposed to a single byte).
- */
- break;
- case _UNIX_SIGNAL_PIPE_SIGTERM_CHAR:
- sigterm_received = TRUE;
- break;
- case _UNIX_SIGNAL_PIPE_SIGHUP_CHAR:
- sighup_received = TRUE;
- break;
- case _UNIX_SIGNAL_PIPE_SIGINT_CHAR:
- sigint_received = TRUE;
- break;
- default:
- g_warning ("Invalid char '%c' read from child watch pipe", b[i]);
- break;
- }
- if (sigterm_received)
- deliver_unix_signal (SIGTERM);
- if (sigint_received)
- deliver_unix_signal (SIGINT);
- if (sighup_received)
- deliver_unix_signal (SIGHUP);
- _g_main_wake_up_all_contexts ();
- }
- }
-}
-
-static void
-init_unix_signal_wakeup_state_unlocked (void)
-{
- GError *error = NULL;
-
- if (!g_thread_supported ())
- {
- /* There is nothing to do for initializing in the non-threaded
- * case.
- */
- if (unix_signal_init_state == UNIX_SIGNAL_UNINITIALIZED)
- unix_signal_init_state = UNIX_SIGNAL_INITIALIZED_SINGLE;
- return;
- }
-
- if (unix_signal_init_state == UNIX_SIGNAL_INITIALIZED_THREADED)
- return;
-
- if (!g_unix_pipe_flags (unix_signal_wake_up_pipe, FD_CLOEXEC, &error))
- g_error ("Cannot create UNIX signal wake up pipe: %s\n", error->message);
- fcntl (unix_signal_wake_up_pipe[1], F_SETFL, O_NONBLOCK | fcntl (unix_signal_wake_up_pipe[1], F_GETFL));
-
- /* We create a helper thread that polls on the wakeup pipe indefinitely */
- if (g_thread_create (unix_signal_helper_thread, NULL, FALSE, &error) == NULL)
- g_error ("Cannot create a thread to monitor UNIX signals: %s\n", error->message);