commit 712d6639ff8e863560328131bbb92b248dc9cde7 from: Chris Down via: Hiltjo Posthuma date: Sat Jan 28 12:34:43 2023 UTC Use sigaction(SA_NOCLDWAIT) for SIGCHLD handling signal() semantics are pretty unclearly specified. For example, depending on OS kernel and libc, the handler may be returned to SIG_DFL (hence the inner call to read the signal handler). Moving to sigaction() means the behaviour is consistently defined. Using SA_NOCLDWAIT also allows us to avoid calling the non-reentrant function die() in the handler. Some addditional notes for archival purposes: * NRK pointed out errno of waitpid could also theoretically get clobbered. * The original patch was iterated on and modified by NRK and Hiltjo: * SIG_DFL was changed to SIG_IGN, this is required, atleast on older systems such as tested on Slackware 11. * signals are not blocked using sigprocmask, because in theory it would briefly for example also ignore a SIGTERM signal. It is OK if waitpid() is (in theory interrupted). POSIX reference: "Consequences of Process Termination": https://pubs.opengroup.org/onlinepubs/9699919799/functions/_Exit.html#tag_16_01_03_01 commit - 89f9905714c1c1b2e8b09986dfbeca15b68d8af8 commit + 712d6639ff8e863560328131bbb92b248dc9cde7 blob - 03baf42b350240f1ab7907169f85725f05d6fe70 blob + c2bd8710544eb4b4e7eaa4a1307e1f1dfd8d16ba --- dwm.c +++ dwm.c @@ -205,7 +205,6 @@ static void setmfact(const Arg *arg); static void setup(void); static void seturgent(Client *c, int urg); static void showhide(Client *c); -static void sigchld(int unused); static void spawn(const Arg *arg); static void tag(const Arg *arg); static void tagmon(const Arg *arg); @@ -1543,10 +1542,17 @@ setup(void) int i; XSetWindowAttributes wa; Atom utf8string; + struct sigaction sa; - /* clean up any zombies immediately */ - sigchld(0); + /* do not transform children into zombies when they terminate */ + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART; + sa.sa_handler = SIG_IGN; + sigaction(SIGCHLD, &sa, NULL); + /* clean up any zombies (inherited from .xinitrc etc) immediately */ + while (waitpid(-1, NULL, WNOHANG) > 0); + /* init screen */ screen = DefaultScreen(dpy); sw = DisplayWidth(dpy, screen); @@ -1639,14 +1645,6 @@ showhide(Client *c) } void -sigchld(int unused) -{ - if (signal(SIGCHLD, sigchld) == SIG_ERR) - die("can't install SIGCHLD handler:"); - while (0 < waitpid(-1, NULL, WNOHANG)); -} - -void spawn(const Arg *arg) { if (arg->v == dmenucmd)