commit a6a8f296664be3d652015dd26bdaf3e2101e7f04
parent 3d4ad85bdd4e1f3f3dac229033dbcd5300ba2a18
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Thu, 31 Mar 2022 22:54:48 +0200
sfeed_curses: improve waiting on processes and reaping them
- Wait on the exact process id and get its status.
- Handle SIGCHLD explicitly and reap zombie children: ignoring them by using
sigaction(SIGCHLD, &sa, NULL); would be racy in this case because sfeed_curses
has interactive and non-interactive programs.
Note while testing: if the markread program would be slow and in the meantime a
plumb process would exit. This signal is now pending and is a zombie process
until the SIGCHLD signal can be processed. This is fine.
This also fixes a regression from commit
30a70fa2dab1925b0eaea04f67e3f86b360386dd because SIGCHLD was ignored in the
parent for interactive processes aswell. This broke reading the exit status of
the markread program, reproducable by plumbing an item and then trying to mark
it as read (with SFEED_URL_FILE set).
Diffstat:
1 file changed, 17 insertions(+), 14 deletions(-)
diff --git a/sfeed_curses.c b/sfeed_curses.c
@@ -554,6 +554,7 @@ init(void)
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART; /* require BSD signal semantics */
sa.sa_handler = sighandler;
+ sigaction(SIGCHLD, &sa, NULL);
sigaction(SIGHUP, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
@@ -563,7 +564,6 @@ init(void)
void
processexit(pid_t pid, int interactive)
{
- pid_t wpid;
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
@@ -574,17 +574,12 @@ processexit(pid_t pid, int interactive)
/* ignore SIGINT (^C) in parent for interactive applications */
sa.sa_handler = SIG_IGN;
sigaction(SIGINT, &sa, NULL);
- /* wait for process to change state */
- while ((wpid = wait(NULL)) >= 0 && wpid != pid)
- ;
+ /* wait for process to change state, ignore errors */
+ waitpid(pid, NULL, 0);
init();
updatesidebar();
updategeom();
updatetitle();
- } else {
- /* ignore SIGCHLD: for non-interactive programs: don't become a zombie */
- sa.sa_handler = SIG_IGN;
- sigaction(SIGCHLD, &sa, NULL);
}
}
@@ -1010,6 +1005,7 @@ lineeditor(void)
} else if (ch < 0) {
switch (sigstate) {
case 0:
+ case SIGCHLD:
case SIGWINCH:
/* continue editing: process signal later */
continue;
@@ -1582,6 +1578,7 @@ void
sighandler(int signo)
{
switch (signo) {
+ case SIGCHLD:
case SIGHUP:
case SIGINT:
case SIGTERM:
@@ -1838,7 +1835,7 @@ markread(struct pane *p, off_t from, off_t to, int isread)
FILE *fp;
off_t i;
const char *cmd;
- int isnew = !isread, pid, wpid, status = -1, visstart;
+ int isnew = !isread, pid, status = -1, visstart;
if (!urlfile || !p->nrows)
return;
@@ -1869,11 +1866,9 @@ markread(struct pane *p, off_t from, off_t to, int isread)
status = WIFEXITED(status) ? WEXITSTATUS(status) : 127;
_exit(status);
default:
- while ((wpid = wait(&status)) >= 0 && wpid != pid)
- ;
-
- /* fail: exit statuscode was non-zero */
- if (status)
+ /* waitpid() and block on process status change,
+ fail if exit statuscode was unavailable or non-zero */
+ if (waitpid(pid, &status, 0) <= 0 || status)
break;
visstart = p->pos - (p->pos % p->height); /* visible start */
@@ -2343,6 +2338,14 @@ event:
continue; /* just a time-out, nothing to do */
switch (sigstate) {
+ case SIGCHLD:
+ /* wait on child processes so they don't become a zombie,
+ do not block the parent process if there is no status,
+ ignore errors */
+ while (waitpid((pid_t)-1, NULL, WNOHANG) > 0)
+ ;
+ sigstate = 0;
+ break;
case SIGHUP:
feeds_reloadall();
sigstate = 0;