spawn: avoid zombie children without handling SIGCHLD

Current handling of SIGCHLD prevents some terminals, for example
sakura and alacritty, to freeze on ctrl+D.

Related to PR #10
This commit is contained in:
Johan Malm 2020-12-29 18:08:35 +00:00
parent f4cbd4ff61
commit 1a38898f34
2 changed files with 43 additions and 25 deletions

View file

@ -1,4 +1,14 @@
#define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <glib.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 void
spawn_async_no_shell(char const *command) spawn_async_no_shell(char const *command)
@ -6,18 +16,45 @@ spawn_async_no_shell(char const *command)
GError *err = NULL; GError *err = NULL;
gchar **argv = 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); g_shell_parse_argv((gchar *)command, NULL, &argv, &err);
if (err) { if (err) {
g_message("%s", err->message); g_message("%s", err->message);
g_error_free(err); g_error_free(err);
return; return;
} }
g_spawn_async(NULL, argv, NULL,
G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, /*
NULL, &err); * Avoid zombie processes by using a double-fork, whereby the
if (err) { * grandchild becomes orphaned & the responsibility of the OS.
g_message("%s", err->message); */
g_error_free(err); 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); g_strfreev(argv);
} }

View file

@ -14,7 +14,6 @@
static struct wlr_compositor *compositor; static struct wlr_compositor *compositor;
static struct wl_event_source *sighup_source; 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 *sigint_source;
static struct wl_event_source *sigterm_source; static struct wl_event_source *sigterm_source;
@ -34,19 +33,6 @@ handle_sighup(int signal, void *data)
return 0; 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 static int
handle_sigterm(int signal, void *data) 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); event_loop = wl_display_get_event_loop(server->wl_display);
sighup_source = wl_event_loop_add_signal( sighup_source = wl_event_loop_add_signal(
event_loop, SIGHUP, handle_sighup, &server->wl_display); 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( sigint_source = wl_event_loop_add_signal(
event_loop, SIGINT, handle_sigterm, NULL); event_loop, SIGINT, handle_sigterm, NULL);
sigterm_source = wl_event_loop_add_signal( sigterm_source = wl_event_loop_add_signal(
@ -263,9 +247,6 @@ server_finish(struct server *server)
if (sighup_source) { if (sighup_source) {
wl_event_source_remove(sighup_source); wl_event_source_remove(sighup_source);
} }
if (sigchld_source) {
wl_event_source_remove(sigchld_source);
}
wl_display_destroy_clients(server->wl_display); wl_display_destroy_clients(server->wl_display);
seat_finish(server); seat_finish(server);