I’m working on a programming project–writing a basic P2P filesharing application in Python. I’m using two threads: a main one to call select and wait for input from a list of sockets and sys.stdin (to receive typed commands) and a helper thread that takes status update messages off a queue and prints them. (It is the only thing that prints anything)
I’m also required to catch the standard SIGINT and handle it to exit gracefully. I have a quit method that does this; typing ‘quit’ as a command works just fine. So in the main thread I try setting this method as the handler for SIGINT. As far as I can tell, the process catches the signal and calls the quit method. The helper thread prints a message confirming that it is exiting. But then I get the following error message from the main thread:
Traceback (most recent call last):
File "peer.py", line 226, in <module>
main()
File "peer.py", line 223, in main
p.run()
File "peer.py", line 160, in run
readables, writables, exceptions = select(self.sockets, [], [])
select.error: (4, 'Interrupted system call')
After which the program does still exit. Whereas without the signal handler in place, sending a SIGINT gives me the following:
Traceback (most recent call last):
File "peer.py", line 225, in <module>
main()
File "peer.py", line 222, in main
p.run()
File "peer.py", line 159, in run
readables, writables, exceptions = select(self.sockets, [], [])
KeyboardInterrupt
Which fails to terminate the program; I have to stop and kill it. This is confusing because the SIGINT appears to interrupt the call to select only when it is caught by my custom method. (Which only puts a message on the print queue and sets a “done” variable) Does anyone know how this can be happening? Is it just a bad idea trying to use signal handlers and threads simultaneously?
Yes, last night after I stopped working on it I realized that I did want it to interrupt. It was being interrupted by executing the signal handler, presumably. So I just catch the select.error and have it jump to the end of the loop, where it immediately exits and moves on to the cleanup code.