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.
This commit is contained in:
Simon Tatham 2018-10-13 10:36:18 +01:00
Родитель c970d2b694
Коммит 0ee204f699
1 изменённых файлов: 21 добавлений и 11 удалений

Просмотреть файл

@ -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,18 +686,11 @@ void pty_real_select_result(Pty *pty, int event, int status)
}
}
void pty_select_result(int fd, int event)
static void pty_try_wait(void)
{
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);
@ -704,6 +700,20 @@ void pty_select_result(int fd, int event)
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]) {
char c[1];
if (read(pty_signal_pipe[0], c, 1) <= 0)
/* ignore error */;
/* ignore its value; it'll be `x' */
pty_try_wait();
} else {
pty = find234(ptys_by_fd, &fd, pty_find_by_fd);