Re: Output disappears when using interrupt key

Guido.van.Rossum@cwi.nl
Thu, 15 Apr 1993 01:02:30 +0200

I tried Steven's try() on two machines and the results differ.

On an SGI (System V, though with lots of BSD extensions) the ^C
triggers the except clause right away (as it should).

On a Sparc running SunOS 4.1 (BSD-based) I need a return after the ^C
and entering 'xxx^Cyyy\n' does indeed place 'yyy\n' in the string.
That is -- it does this most of the time. Sometimes the initial
string remains in the variable L!

Knowing more about Python than most of you :-) I can try to explain
what's going on. Interrupts in Python are handled by a signal handler
which sets a global flag and returns. The interpreter looks at this
flag every ten pseudo-instructions or so. Checking it more often is
expensive since the interface is a function call, to support the Mac
and DOS versions of the interrupt handling interface which works quite
differently. This functional interface is also used by other parts
of Python that expect interrupts.

On System V-like systems, the signal handler causes the read() system
call that's buried deep inside stdio to return with an error (EINTR is
set), causing the stdio getc() call in Python (in "fileobject.c",
getline()) to return EOF, after which getline() checks for an
interrupt and reports an error -- the sys.stdin.readline() call never
returns successful.

However, on BSD-like systems, by default the read() call is
*restarted* after a signal handler returns normally (as is any other
system call that falls victim of a signal handler). As a side effect
the system has emptied its input buffer (which hasn't been transferred
to stdio yet because it's waiting for a whole line to be entered).
The read() call then proceeds normally so if you entered 'xxx^Cyyy\n'
the 'xxx' is thrown away but the 'yyy\n' part is read normally. But
the story isn't finished yet: since the interrupt handler *has* been
called, the global flag is waiting to be checked by the interpreter's
main loop. Depending on where exactly it is it may first assign the
result of sys.stdin.readline() to L or first discover that an
interrupt has occurred -- which explains why I sometimes see L's
initial value.

I suspect that AIX 3.2's signal model is based more on BSD than on
System V (assuming Steven tried this on AIX -- he only said which
system he used for the first try).

I can't reproduce Jaap's problem (nor can Steven), so I suspect that
it is specific to his system. When an interrupt occurs UNIX discards
any output that has been written by the application but not yet
transferred to the terminal. Maybe Jaap's system is doing this
asynchronously and mistaking output written just after the interrupt
for output written just before (I don't know enough about tty drivers
to know if this is a reasonable assumption).

A solution? Maybe I should just check for an interrupt after *every*
read, not just when getc() returns EOF. This would be somewhat
expensive (an extra function call for *every* readline() and read()
call), but it could be made less expensive by doing it only for tty
devices (adding a field to the internal file structure containing the
outcome of isatty()).

Hoping this sheds enough light,

--Guido van Rossum, CWI, Amsterdam <Guido.van.Rossum@cwi.nl>