]> git.mdlowis.com Git - proto/labwc.git/commitdiff
spawn: avoid zombie children without handling SIGCHLD
authorJohan Malm <jgm323@gmail.com>
Tue, 29 Dec 2020 18:08:35 +0000 (18:08 +0000)
committerJohan Malm <jgm323@gmail.com>
Tue, 29 Dec 2020 18:08:35 +0000 (18:08 +0000)
Current handling of SIGCHLD prevents some terminals, for example
sakura and alacritty, to freeze on ctrl+D.

Related to PR #10

src/common/spawn.c
src/server.c

index 41acd9f61182c1ed9727d48d2f12cf3d8fca3200..d42061b7278973e5fcd0bb9d1cca123e704ec110 100644 (file)
@@ -1,4 +1,14 @@
+#define _POSIX_C_SOURCE 200809L
+#include <assert.h>
 #include <glib.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include "common/log.h"
+#include "common/spawn.h"
 
 void
 spawn_async_no_shell(char const *command)
@@ -6,18 +16,45 @@ spawn_async_no_shell(char const *command)
        GError *err = NULL;
        gchar **argv = NULL;
 
+       assert(command);
+
+       /* Use glib's shell-parse to mimic Openbox's behaviour */
        g_shell_parse_argv((gchar *)command, NULL, &argv, &err);
        if (err) {
                g_message("%s", err->message);
                g_error_free(err);
                return;
        }
-       g_spawn_async(NULL, argv, NULL,
-               G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL,
-               NULL, &err);
-       if (err) {
-               g_message("%s", err->message);
-               g_error_free(err);
+
+       /*
+        * Avoid zombie processes by using a double-fork, whereby the
+        * grandchild becomes orphaned & the responsibility of the OS.
+        */
+       pid_t child = 0, grandchild = 0;
+
+       child = fork();
+       switch (child) {
+       case -1:
+               warn("unable to fork()");
+               goto out;
+       case 0:
+               setsid();
+               sigset_t set;
+               sigemptyset(&set);
+               sigprocmask(SIG_SETMASK, &set, NULL);
+               grandchild = fork();
+               if (grandchild == 0) {
+                       execvp(argv[0], argv);
+                       exit(0);
+               } else if (grandchild < 0) {
+                       warn("unable to fork()");
+               }
+               exit(0);
+       default:
+               break;
        }
+       waitpid(child, NULL, 0);
+out:
        g_strfreev(argv);
 }
+
index 096267e395605472418b919df593e37ce6c3ba98..54ebe931f8bc29ce9c6e53378e7d1a22ef1e3f5e 100644 (file)
@@ -14,7 +14,6 @@
 
 static struct wlr_compositor *compositor;
 static struct wl_event_source *sighup_source;
-static struct wl_event_source *sigchld_source;
 static struct wl_event_source *sigint_source;
 static struct wl_event_source *sigterm_source;
 
@@ -34,19 +33,6 @@ handle_sighup(int signal, void *data)
        return 0;
 }
 
-static int
-handle_sigchld(int signal, void *data)
-{
-       int status;
-       pid_t pid;
-
-       while ((pid = waitpid(-1, &status, WNOHANG)) > 0);
-       if (pid < 0) {
-               wlr_log_errno(WLR_ERROR, "waitpid");
-       }
-       return 0;
-}
-
 static int
 handle_sigterm(int signal, void *data)
 {
@@ -86,8 +72,6 @@ server_init(struct server *server)
        event_loop = wl_display_get_event_loop(server->wl_display);
        sighup_source = wl_event_loop_add_signal(
                event_loop, SIGHUP, handle_sighup, &server->wl_display);
-       sigchld_source = wl_event_loop_add_signal(
-               event_loop, SIGCHLD, handle_sigchld, NULL);
        sigint_source = wl_event_loop_add_signal(
                event_loop, SIGINT, handle_sigterm, NULL);
        sigterm_source = wl_event_loop_add_signal(
@@ -263,9 +247,6 @@ server_finish(struct server *server)
        if (sighup_source) {
                wl_event_source_remove(sighup_source);
        }
-       if (sigchld_source) {
-               wl_event_source_remove(sigchld_source);
-       }
        wl_display_destroy_clients(server->wl_display);
 
        seat_finish(server);