Remove the double forking in start_application (#5510)

Having just a single fork is beneficial, as it preserves the approprate
parent information for the children of i3, which is useful in some
scenarious e.g. when a child wants to do something on the wm's exit
(possible via `prctl(PR_SET_PDEATHSIG, ...)`).

Moreover, this is a zero-cost benefit: i3 is already using libev with
the default loop, which automatically reaps all the zombie children even
when there is no corresponding event set.

Resolves #5506
This commit is contained in:
Nikolay Nechaev 2023-06-15 09:38:35 +03:00 committed by GitHub
parent a95870120c
commit 3ae5f31d04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 16 additions and 16 deletions

View File

@ -579,7 +579,11 @@ int main(int argc, char *argv[]) {
/* Initialize the libev event loop. This needs to be done before loading
* the config file because the parser will install an ev_child watcher
* for the nagbar when config errors are found. */
* for the nagbar when config errors are found.
*
* Main loop must be ev's default loop because (at the moment of writing)
* only the default loop can handle ev_child events and reap zombies
* (the start_application routine relies on that too). */
main_loop = EV_DEFAULT;
if (main_loop == NULL)
die("Could not initialize libev. Bad LIBEV_FLAGS?\n");

View File

@ -118,10 +118,9 @@ void startup_sequence_delete(struct Startup_Sequence *sequence) {
}
/*
* Starts the given application by passing it through a shell. We use double
* fork to avoid zombie processes. As the started applications parent exits
* (immediately), the application is reparented to init (process-id 1), which
* correctly handles children, so we dont have to do it :-).
* Starts the given application by passing it through a shell. Zombie processes
* will be collected by ev in the default loop, we don't have to manually
* deal with it.
*
* The shell used to start applications is the system's bourne shell (i.e.,
* /bin/sh).
@ -173,7 +172,8 @@ void start_application(const char *command, bool no_startup_id) {
LOG("executing: %s\n", command);
if (fork() == 0) {
/* Child process */
/* Child process.
* It will be reaped by ev, even though there is no corresponding ev_child */
setsid();
setrlimit(RLIMIT_CORE, &original_rlimit_core);
/* Close all socket activation file descriptors explicitly, we disabled
@ -186,18 +186,14 @@ void start_application(const char *command, bool no_startup_id) {
unsetenv("LISTEN_PID");
unsetenv("LISTEN_FDS");
signal(SIGPIPE, SIG_DFL);
if (fork() == 0) {
/* Setup the environment variable(s) */
if (!no_startup_id)
sn_launcher_context_setup_child_process(context);
setenv("I3SOCK", current_socketpath, 1);
/* Setup the environment variable(s) */
if (!no_startup_id)
sn_launcher_context_setup_child_process(context);
setenv("I3SOCK", current_socketpath, 1);
execl(_PATH_BSHELL, _PATH_BSHELL, "-c", command, NULL);
/* not reached */
}
_exit(EXIT_SUCCESS);
execl(_PATH_BSHELL, _PATH_BSHELL, "-c", command, NULL);
/* not reached */
}
wait(0);
if (!no_startup_id) {
/* Change the pointer of the root window to indicate progress */