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-15 12:38 Message: Logged In: YES user_id=129426 I've submitted a patch, it's at 1102879 Please have a close look at it. ---------------------------------------------------------------------- Comment By: David M. Cooke (dmcooke) Date: 2005-01-14 00:28 Message: Logged In: YES user_id=65069 Looks like my assertion that timeout==1 is wrong :-). Otherwise, the analysis is correct: recv is called when select() retuned EINTR. I think your approach is the way to go. Since the return value of internal_select is no longer a boolean for a timeout, maybe in the expressions "timeout = internal_select(...)", "timeout" should be renamed to something more generic (possibly 'selectresult')? ---------------------------------------------------------------------- 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 _______________________________________________ Python-bugs-list mailing list Unsubscribe: http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com