As reported by Koen Vossen in c.l.py, when a timeout is
set on a socket, a try...except block around a
socket.recv (or socket.recvfrom) won't properly catch a
keyboard interrupt (by Ctrl-C). I've attached example
code that shows this. Run it and press Ctrl-C before
the socket times out. This is for Python 2.3 under Linux.
I believe the problem boils down to this sequence of
events inside of the socketmodule.c::sock_recv function
(and similiar for sock_recvfrom):
1) internal_select is called, which calls select, which
waits for a timeout. A SIGINT is received (and caught
by the default handler). The select returns with errno
set to EINTR. internal_select returns with timeout==1
2) without checking errno, recv() is called. Since
there is actually no data, it returns an error, with
errno set to EAGAIN.
3) the default socket error handler is called, which
calls PyErr_SetFromErrno(). Since errno != EINTR (it's
now EAGAIN), a socket_error exception is thrown.
4) the innermost try..except block is triggered.
5) next loop around in eval_frame, notices that SIGINT
was caught, and so KeyboardInterrupt is raised, exiting
innermost try..except clause
6) KeyboardInterrupt is caught by the outermost
try..except block.
I was going to make a patch, but I couldn't figure out
the best way to fix this in general :-( There are
likely similiar problems with everywhere
internal_select is used. The quick fix is to check
errno before calling recv()
|