[ python-Bugs-926423 ] socket timeouts + Ctrl-C don't play nice

SourceForge.net noreply at sourceforge.net
Thu Jan 13 23:59:32 CET 2005


Bugs item #926423, was opened at 2004-03-31 05:48
Message generated for change (Comment added) made by irmen
You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=926423&group_id=5470

Category: Python Library
Group: Python 2.3
Status: Open
Resolution: None
Priority: 5
Submitted By: David M. Cooke (dmcooke)
Assigned to: Nobody/Anonymous (nobody)
Summary: socket timeouts + Ctrl-C don't play nice

Initial Comment:
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()


----------------------------------------------------------------------

Comment By: Irmen de Jong (irmen)
Date: 2005-01-13 23:59

Message:
Logged In: YES 
user_id=129426

(confirmed on Python 2.4 and HEAD)

But: your analysis is not correct:
internal_select doesn't return with timeout==1 when a SIGINT
occurs, instead it returns 0, because it doesn't check for
an error condition that select() may return.

So I hacked around a bit and changed internal_select to
return -1 when the select() system call returns -1,
and then also added the following in sock_recv:

if(errno) {
   Py_DECREF(buf);
   return PyErr_SetFromErrno(socket_error);
}

Which seems to make the example script that is attached to
this bug report run as expected.

As you say, I also think that this check must be added at
all locations where internal_select is called.

What do you say? I can make a patch if this is okay.

----------------------------------------------------------------------

You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=926423&group_id=5470


More information about the Python-bugs-list mailing list