[New-bugs-announce] [issue41437] SIGINT blocked by socket operations like recv on Windows
Zhiming Wang
report at bugs.python.org
Wed Jul 29 14:13:12 EDT 2020
New submission from Zhiming Wang <zmwangx at gmail.com>:
I noticed that on Windows, socket operations like recv appear to always block SIGINT until it's done, so if a recv hangs, Ctrl+C cannot interrupt the program. (I'm a *nix developer investigating a behavioral problem of my program on Windows, so please excuse my limited knowledge of Windows.)
Consider the following example where I spawn a TCP server that stalls connections by 5 seconds in a separate thread, and use a client to connect to it on the main thread. I then try to interrupt the client with Ctrl+C.
import socket
import socketserver
import time
import threading
interrupted = threading.Event()
class HoneypotServer(socketserver.TCPServer):
# Stall each connection for 5 seconds.
def get_request(self):
start = time.time()
while time.time() - start < 5 and not interrupted.is_set():
time.sleep(0.1)
return self.socket.accept()
class EchoHandler(socketserver.BaseRequestHandler):
def handle(self):
data = self.request.recv(1024)
self.request.sendall(data)
class HoneypotServerThread(threading.Thread):
def __init__(self):
super().__init__()
self.server = HoneypotServer(("127.0.0.1", 0), EchoHandler)
def run(self):
self.server.serve_forever(poll_interval=0.1)
def main():
start = time.time()
server_thread = HoneypotServerThread()
server_thread.start()
sock = socket.create_connection(server_thread.server.server_address)
try:
sock.sendall(b"hello")
sock.recv(1024)
except KeyboardInterrupt:
print(f"processed SIGINT {time.time() - start:.3f}s into the program")
interrupted.set()
finally:
sock.close()
server_thread.server.shutdown()
server_thread.join()
if __name__ == "__main__":
main()
On *nix systems the KeyboardInterrupt is processed immediately. On Windows, the KeyboardInterrupt is always processed more than 5 seconds into the program, when the recv is finished.
I suppose this is a fundamental limitation of Windows? Is there any workaround (other than going asyncio)?
Btw, I learned about SIGBREAK, which when unhandled seems to kill the process immediately, but that means no chance of cleanup. I tried to handle SIGBREAK but whenever a signal handler is installed, the behavior reverts to that of SIGINT -- the handler is called only after 5 seconds have passed.
(I'm attaching a socket_sigint_sigbreak.py which is a slightly expanded version of my sample program above, showing my attempt at handler SIGBREAK. Both
python .\socket_sigint_sigbreak.py --sigbreak-handler interrupt
and
python .\socket_sigint_sigbreak.py --sigbreak-handler exit
stall for 5 seconds.)
----------
components: Windows
files: socket_sigint_sigbreak.py
messages: 374580
nosy: paul.moore, steve.dower, tim.golden, zach.ware, zmwangx
priority: normal
severity: normal
status: open
title: SIGINT blocked by socket operations like recv on Windows
type: behavior
versions: Python 3.8
Added file: https://bugs.python.org/file49348/socket_sigint_sigbreak.py
_______________________________________
Python tracker <report at bugs.python.org>
<https://bugs.python.org/issue41437>
_______________________________________
More information about the New-bugs-announce
mailing list