diff options
Diffstat (limited to 'Src')
-rw-r--r-- | Src/exec.c | 17 | ||||
-rw-r--r-- | Src/signals.c | 13 |
2 files changed, 29 insertions, 1 deletions
diff --git a/Src/exec.c b/Src/exec.c index 216057aa7..f6c768f37 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -4576,10 +4576,20 @@ readoutput(int in, int qt, int *readerror) char *buf, *ptr; int bsiz, c, cnt = 0; FILE *fin; + int q = queue_signal_level(); fin = fdopen(in, "r"); ret = newlinklist(); ptr = buf = (char *) hcalloc(bsiz = 64); + /* + * We need to be sensitive to SIGCHLD else we can be + * stuck forever with important processes unreaped. + * The case that triggered this was where the exiting + * process is group leader of the foreground process and we need + * to reclaim the terminal else ^C doesn't work. + */ + dont_queue_signals(); + child_unblock(); while ((c = fgetc(fin)) != EOF || errno == EINTR) { if (c == EOF) { errno = 0; @@ -4592,13 +4602,18 @@ readoutput(int in, int qt, int *readerror) cnt++; } if (++cnt >= bsiz) { - char *pp = (char *) hcalloc(bsiz *= 2); + char *pp; + queue_signals(); + pp = (char *) hcalloc(bsiz *= 2); + dont_queue_signals(); memcpy(pp, buf, cnt - 1); ptr = (buf = pp) + cnt - 1; } *ptr++ = c; } + child_block(); + restore_queue_signals(q); if (readerror) *readerror = ferror(fin) ? errno : 0; fclose(fin); diff --git a/Src/signals.c b/Src/signals.c index 94f379e72..2a6aa3f24 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -537,6 +537,19 @@ wait_for_processes(void) #else update_process(pn, status); #endif + if (pn->pid == jn->gleader) { + jn->gleader = 0; + if (!(jn->stat & STAT_NOSTTY)) { + /* + * This PID was in control of the terminal; + * reclaim terminal now it has exited. + * It's still possible some future forked + * process of this job will become group + * leader, however. + */ + attachtty(mypgrp); + } + } } update_job(jn); } else if (findproc(pid, &jn, &pn, 1)) { |