Skip to content
This repository has been archived by the owner on Jan 26, 2024. It is now read-only.

double forking for process spawning #211

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 33 additions & 29 deletions dwl.c
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,6 @@ static void setlayout(const Arg *arg);
static void setmfact(const Arg *arg);
static void setmon(Client *c, Monitor *m, unsigned int newtags);
static void setup(void);
static void sigchld(int unused);
static void spawn(const Arg *arg);
static void startdrag(struct wl_listener *listener, void *data);
static void tag(const Arg *arg);
Expand Down Expand Up @@ -1749,22 +1748,31 @@ run(char *startup_cmd)

/* Now that the socket exists, run the startup command */
if (startup_cmd) {
/* For explanation about double-forking see spawn() */
int piperw[2];
pipe(piperw);
startup_pid = fork();
if (startup_pid < 0)
EBARF("startup: fork");
if (startup_pid == 0) {
dup2(piperw[0], STDIN_FILENO);
close(piperw[0]);
pid_t child;
close(piperw[1]);
execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL);
EBARF("startup: execl");
if ((child = fork()) == 0) {
dup2(piperw[0], STDIN_FILENO);
close(piperw[0]);
execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL);
EBARF("startup: execl");
}
close(piperw[0]);
_exit(0);
}
dup2(piperw[1], STDOUT_FILENO);
close(piperw[1]);
close(piperw[0]);

waitpid(startup_pid, NULL, 0);
}

/* If nobody is reading the status output, don't terminate */
signal(SIGPIPE, SIG_IGN);
printstatus();
Expand All @@ -1790,11 +1798,6 @@ run(char *startup_cmd)
* loop configuration to listen to libinput events, DRM events, generate
* frame events at the refresh rate, and so on. */
wl_display_run(dpy);

if (startup_cmd) {
kill(startup_pid, SIGTERM);
waitpid(startup_pid, NULL, 0);
}
}

Client *
Expand Down Expand Up @@ -1915,7 +1918,6 @@ setup(void)
dpy = wl_display_create();

/* Set up signal handlers */
sigchld(0);
signal(SIGINT, quitsignal);
signal(SIGTERM, quitsignal);

Expand Down Expand Up @@ -2079,29 +2081,31 @@ setup(void)
#endif
}

void
sigchld(int unused)
{
/* We should be able to remove this function in favor of a simple
* signal(SIGCHLD, SIG_IGN);
* but the Xwayland implementation in wlroots currently prevents us from
* setting our own disposition for SIGCHLD.
*/
if (signal(SIGCHLD, sigchld) == SIG_ERR)
EBARF("can't install SIGCHLD handler");
while (0 < waitpid(-1, NULL, WNOHANG))
;
}

void
spawn(const Arg *arg)
{
if (fork() == 0) {
dup2(STDERR_FILENO, STDOUT_FILENO);
/* The simplest way to avoid zombie processes is `signal(SIGCHLD, SIG_IGN)`
* but Xwayland implementation in wlroots currently prevent us from setting
* our own disposition for SIGCHLD; to be able to spawn child processes
* we do double-fork, so we spawn the command in the second fork and wait
* for the first fork.
*/
pid_t pid = -1;
if ((pid = fork()) == 0) {
pid_t child = -1;
setsid();
execvp(((char **)arg->v)[0], (char **)arg->v);
EBARF("dwl: execvp %s failed", ((char **)arg->v)[0]);
signal(SIGPIPE, SIG_DFL);
/* Fork child process again */
if ((child = fork()) == 0) {
dup2(STDERR_FILENO, STDOUT_FILENO);
execvp(((char **)arg->v)[0], (char **)arg->v);
EBARF("dwl: execvp %s failed", ((char **)arg->v)[0]);
}
_exit(0); /* Close child process */
} else if (pid < 0) {
EBARF("spawn: fork");
}
waitpid(pid, NULL, 0);
}

void
Expand Down