bug in 4.2 select()
rws%mit-bold at sri-unix.UUCP
rws%mit-bold at sri-unix.UUCP
Sun Feb 26 13:19:47 AEST 1984
From: Robert W. Scheifler <rws at mit-bold>
Description:
If a SIGTSTP is generated on the controlling tty of a process
that is waiting in a select() on that tty, the process will
mysteriously vanish.
Repeat-By:
Run in foreground the program:
main()
{
int fds = 1;
select(1, &fds, 0, 0, 0);
}
and then generate SIGTSTP from the keyboard. The process will
correctly suspend, but as soon as a character becomes available
for input to the terminal (i.e. as soon as you type CR to the shell),
the process will vanish.
Why: At the select(), the tty t_rsel gets set to the process, but no
chars are available, so the process goes into state SSLEEP on &selwait.
When the suspend character is typed, a psignal() on the process
changes its state to SSTOP and sets p_cursig to SIGTSTP. When input
chars are made available to the tty, a ttwakeup() is performed, which
calls selwakeup() because t_rsel is still set. Since this is the only
process that has done select() on the tty, there are no collisions,
and selwakeup() simply calls setrun() on the process rather than
calling wakeup(). Therein lies the bug, because this bogusly makes
the process runnable, and it will run before the input chars are
gobbled, and so the select() will succeed and try to return. However,
p_cursig is still set to SIGTSTP, and syscall() will see it and call
psig(), which will call exit() and the process will vanish.
Also note another bug (which I don't propose a fix for here): select()
will succeed on a tty even if the process and the tty are in different
process groups. So the process will think there is data to read, and
then hang trying to do the actual read.
Fix:
selwakeup() should make the same checks in the single process case
that wakeup() makes per process in the general case.
In selwakeup(), replace:
setrun(p);
with:
{
if (p->p_stat == SSLEEP)
setrun(p);
else unsleep(p);
}
[Note that the special casing of one process from multiple processes
and tracking collisions doesn't seem to have helped much, since
setrun() or unsleep() will do basically the same work wakeup() does
in munging the hash chain.]
More information about the Comp.unix.wizards
mailing list