From 0ee204f699886315340d16bf8a9de47451ae3819 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 13 Oct 2018 10:36:18 +0100 Subject: [PATCH] uxpty: propagate exit code more reliably on pty EIO. There was a bit of a race condition depending on whether uxpty spotted the EOF/EIO on the process's output first, or the SIGCHLD for its actual termination: if the former came first, it would never bother to reap the exit code at all. It still doesn't bother if it's closing the session immediately and the process genuinely _hasn't_ died (say, if it detaches itself completely from the controlling tty to run in the background like a weird parody of an old DOS TSR). But now when we see EOF, we make an immediate (but nonblocking) attempt to wait for the child process, in case its exit code was already available and we just hadn't noticed yet. --- unix/uxpty.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/unix/uxpty.c b/unix/uxpty.c index 57b3308f..834d360f 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -580,7 +580,9 @@ void pty_pre_init(void) } -void pty_real_select_result(Pty *pty, int event, int status) +static void pty_try_wait(void); + +static void pty_real_select_result(Pty *pty, int event, int status) { char buf[4096]; int ret; @@ -627,6 +629,7 @@ void pty_real_select_result(Pty *pty, int event, int status) * the pterm window to hang around! */ finished = TRUE; + pty_try_wait(); /* one last effort to collect exit code */ if (!pty->child_dead) pty->exit_code = 0; } else if (ret < 0) { @@ -683,27 +686,34 @@ void pty_real_select_result(Pty *pty, int event, int status) } } +static void pty_try_wait(void) +{ + Pty *pty; + pid_t pid; + int status; + + do { + pid = waitpid(-1, &status, WNOHANG); + + pty = find234(ptys_by_pid, &pid, pty_find_by_pid); + + if (pty) + pty_real_select_result(pty, -1, status); + } while (pid > 0); +} + void pty_select_result(int fd, int event) { Pty *pty; if (fd == pty_signal_pipe[0]) { - pid_t pid; - int status; char c[1]; if (read(pty_signal_pipe[0], c, 1) <= 0) /* ignore error */; /* ignore its value; it'll be `x' */ - do { - pid = waitpid(-1, &status, WNOHANG); - - pty = find234(ptys_by_pid, &pid, pty_find_by_pid); - - if (pty) - pty_real_select_result(pty, -1, status); - } while (pid > 0); + pty_try_wait(); } else { pty = find234(ptys_by_fd, &fd, pty_find_by_fd);