From: Paul Moore on
From a quick experiment, it seems that select.select with a timeout
doesn't react to a keyboard interrupt until the timeout expires.
Specifically, if I do

s = socket.socket()
select.select([s], [], [], 30)

and then press Ctrl-C, Python waits for the 30 seconds before raising
KeyboardInterrupt.

Is this a known limitation on Windows? I see no mention of it in the
documentation. Assuming it is a known limitation, is there a way round
it? (I'm writing a tiny server using asyncore/asynchat, and the
delayed response to Ctrl-C is a mild nuisance. Solutions such as "use
twisted", while probably the sensible option in a wider context, don't
really apply here - I need something within the confines of the stdlib
if it's to be worth doing).

Thanks,
Paul
From: Thomas Heller on
Paul Moore schrieb:
>>From a quick experiment, it seems that select.select with a timeout
> doesn't react to a keyboard interrupt until the timeout expires.
> Specifically, if I do
>
> s = socket.socket()
> select.select([s], [], [], 30)
>
> and then press Ctrl-C, Python waits for the 30 seconds before raising
> KeyboardInterrupt.
>
> Is this a known limitation on Windows? I see no mention of it in the
> documentation. Assuming it is a known limitation, is there a way round
> it? (I'm writing a tiny server using asyncore/asynchat, and the
> delayed response to Ctrl-C is a mild nuisance. Solutions such as "use
> twisted", while probably the sensible option in a wider context, don't
> really apply here - I need something within the confines of the stdlib
> if it's to be worth doing).

If you look at the source code for time.sleep(), which CAN be interrupted
by pressing Ctrl-C, you will find that it is carefully programmed to be
interruptible (sp?). Which is not the case for select.select(), obviously.

I guess the best way might be to split your select.select() call into several
ones, using a smaller timeout like 1 second for example.

BTW: I have experimented with calling the win32 function SetConsoleCtrlHandler()
before the call to select.select(). This allows to install a python callback
function which is called when Ctrl+C is pressed. However it seems this callback
is not able to interrupt the select() call - but it can 'raise SystemExit()'
which will terminate the script. Here is the code:

"""
import ctypes, select, socket

@ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_uint)
def HandlerRoutine(dwCtrlType):
print "hoppla", dwCtrlType
if dwCtrlType == 0: # CTRL+C
raise SystemExit()
return 1

s = socket.socket()

print "Waiting."
ctypes.windll.kernel32.SetConsoleCtrlHandler(HandlerRoutine, 1)
select.select([s], [], [], 30)
ctypes.windll.kernel32.SetConsoleCtrlHandler(HandlerRoutine, 0)
print "Done."
"""

From: Paul Moore on
On 6 May, 20:58, Thomas Heller <thel...(a)ctypes.org> wrote:
> If you look at the source code for time.sleep(), which CAN be interrupted
> by pressing Ctrl-C, you will find that it is carefully programmed to be
> interruptible (sp?).  Which is not the case for select.select(), obviously.

Thanks - given this, would it be worth me submitting a documentation
patch noting that select.select is not interruptible on Windows?

> I guess the best way might be to split your select.select() call into several
> ones, using a smaller timeout like 1 second for example.

Yes, that's probably good enough for my case.

> BTW: I have experimented with calling the win32 function SetConsoleCtrlHandler()
> before the call to select.select().  This allows to install a python callback
> function which is called when Ctrl+C is pressed.  However it seems this callback
> is not able to interrupt the select() call - but it can 'raise SystemExit()'
> which will terminate the script.  Here is the code:

That's useful - I doubt I'll need it for this case, but I'll keep it
in mind for the future.

Thanks for the help.
Paul.
From: Giampaolo Rodolà on
You can easily avoid this by setting a lower timeout when calling
asyncore.loop(), like 1 second or less (for example, Twisted uses
0.001 secs).
Actually there's no reason for asyncore to have such a high default
timeout (30 seconds).
I think this should be signaled on the bug tracker.

--- Giampaolo
http://code.google.com/p/pyftpdlib
http://code.google.com/p/psutil


2010/5/6 Paul Moore <p.f.moore(a)gmail.com>:
> >From a quick experiment, it seems that select.select with a timeout
> doesn't react to a keyboard interrupt until the timeout expires.
> Specifically, if I do
>
> s = socket.socket()
> select.select([s], [], [], 30)
>
> and then press Ctrl-C, Python waits for the 30 seconds before raising
> KeyboardInterrupt.
>
> Is this a known limitation on Windows? I see no mention of it in the
> documentation. Assuming it is a known limitation, is there a way round
> it? (I'm writing a tiny server using asyncore/asynchat, and the
> delayed response to Ctrl-C is a mild nuisance. Solutions such as "use
> twisted", while probably the sensible option in a wider context, don't
> really apply here - I need something within the confines of the stdlib
> if it's to be worth doing).
>
> Thanks,
> Paul
> --
> http://mail.python.org/mailman/listinfo/python-list
>
From: Antoine Pitrou on
Le Fri, 07 May 2010 16:36:44 +0200, Giampaolo Rodolà a écrit :
> You can easily avoid this by setting a lower timeout when calling
> asyncore.loop(), like 1 second or less (for example, Twisted uses 0.001
> secs).
> Actually there's no reason for asyncore to have such a high default
> timeout (30 seconds).

The reason for a high default timeout would be to avoid waking the CPU
and do useless work too often. This is important on laptops and smaller
devices, in order to conserve power.

Under Unix, it's easy to have a separate fd on which you write a byte
when an signal comes, and which wakes up your select() call. Under
Windows, it may be more involved -- first because select() only takes
sockets, not pipes.