Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: interrupt handling bug (again?)

On Jun 6,  9:08pm, Mikael Magnusson wrote:
} % for a in 1 2 3; do xterm; done
} then hit ctrl-z in that term and bg it, do stuff and at some point hit
} ctrl-c, the backgrounded for loop will be interrupted

I'm not 100% sure but this is most likely a TTY process group issue.

If I change "xterm" to

% for a in 1 2 3; do; sleep 10; echo $a; done

then I can reproduce the behavior on "bg".  However, if I stop, bg,
*and* disown, I end up with the sleep resumed, but the subshell that
handles the loop is still stopped.  Which is an entirely different
but related bug.

} This happens even if you disown it, but not if
} you run it with & or &|.

Here's what I think is going on:

When you run with & or &|, it's known "up front" that the job will be
in the background, so the entire loop is immediately disconnected
from the terminal and with &! also discarded from the job table.

If instead you start in the foreground, the loop is in the parent
shell, so by definition is attached to the terminal.  This is very
important because it means that "xterm" (or in my case "sleep") is
the foreground job.

When you ^Z, that suspends the foreground job.  The parent zsh gets
a wait-status of stopped, but it knows it's in a loop, so it forks
and also suspends the new subshell to be able to keep the loop state
without suspending the parent.

This is where things get weird.  When you "bg" that only resumes the
previous foreground job, it does not resume the forked subshell (if
it did, the next command in the loop would immediately start).  That
means the loop-subhell is still in the job table.  It stays there
(still stopped) until the previous foreground job finishes, at which
point the parent continues and backgrounds it to resume looping.

However, if you interrupt before the foreground job is done, the
parent faithfully propagates the signal to the entry in the job
table, and that kills the loop when it finally does restart.  If you
instead disown before the foreground job is done, the job table entry
for the foreground job is deleted, so the parent never notices that
it has exited and never resumes the loop at all.

That latter bit is going to be nearly impossible to fix.  Only the
original parent shell can manage both the foreground job and the
suspended subshell, which means it *can't* disown both of them if
the loop is to remain blocked until the opportune moment.  I think
the only answer will be to refuse to disown.  We already have a
warning for jobs that can't be suspended, and one for disowning a job
that is going to remain stopped.

The former issue can probably be fixed by skipping those subshell
job entries when propagating the TTY signal.  We must be able to
find those entries already to resume them when the current loop
foreground job exits, so this shouldn't be impossible.

I don't have time to look into this any further at this point.  PWS?

Messages sorted by: Reverse Date, Date, Thread, Author