Use sigaction(SA_NOCLDWAIT) for SIGCHLD handling 712d6639
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
Chris Down · 2023-01-28 12:53 1 file(s) · +9 −11
dwm.c +9 −11
205 205
static void setup(void);
206 206
static void seturgent(Client *c, int urg);
207 207
static void showhide(Client *c);
208 -
static void sigchld(int unused);
209 208
static void spawn(const Arg *arg);
210 209
static void tag(const Arg *arg);
211 210
static void tagmon(const Arg *arg);
1543 1542
	int i;
1544 1543
	XSetWindowAttributes wa;
1545 1544
	Atom utf8string;
1545 +
	struct sigaction sa;
1546 1546
1547 -
	/* clean up any zombies immediately */
1548 -
	sigchld(0);
1547 +
	/* do not transform children into zombies when they terminate */
1548 +
	sigemptyset(&sa.sa_mask);
1549 +
	sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART;
1550 +
	sa.sa_handler = SIG_IGN;
1551 +
	sigaction(SIGCHLD, &sa, NULL);
1552 +
1553 +
	/* clean up any zombies (inherited from .xinitrc etc) immediately */
1554 +
	while (waitpid(-1, NULL, WNOHANG) > 0);
1549 1555
1550 1556
	/* init screen */
1551 1557
	screen = DefaultScreen(dpy);
1636 1642
		showhide(c->snext);
1637 1643
		XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y);
1638 1644
	}
1639 -
}
1640 -
1641 -
void
1642 -
sigchld(int unused)
1643 -
{
1644 -
	if (signal(SIGCHLD, sigchld) == SIG_ERR)
1645 -
		die("can't install SIGCHLD handler:");
1646 -
	while (0 < waitpid(-1, NULL, WNOHANG));
1647 1645
}
1648 1646
1649 1647
void