classification
Title: Print not safe in signal handlers
Type: Stage: resolved
Components: Versions:
process
Status: closed Resolution: wont fix
Dependencies: Superseder:
Assigned To: Nosy List: Devin Jeanpierre, pitrou, vstinner
Priority: normal Keywords:

Created on 2015-05-25 08:37 by Devin Jeanpierre, last changed 2015-05-25 16:05 by vstinner. This issue is now closed.

Files
File name Uploaded Description Edit
threading_print_test.py Devin Jeanpierre, 2015-05-25 08:37
Messages (4)
msg244020 - (view) Author: Devin Jeanpierre (Devin Jeanpierre) * Date: 2015-05-25 08:37
The code attached runs a while loop that prints, and has a signal handler that also prints. There is a thread that constantly fires off signals, but this is just to ensure the condition for the bug happens -- this is a bug with signal handling, not threads -- I can trigger a RuntimeError (... with a missing message?) by commenting out the threading lines and instead running a separate process "while true; do kill -s SIGUSR1 4687; done".

Traceback:

$ python3 threading_print_test.py 
hello
world
Traceback (most recent call last):
  File "/usr/local/google/home/devinj/Downloads/threading_print_test.py", line 36, in <module>
    main()
  File "/usr/local/google/home/devinj/Downloads/threading_print_test.py", line 30, in main
    print("world")
  File "/usr/local/google/home/devinj/Downloads/threading_print_test.py", line 13, in print_hello
    print("hello")
RuntimeError: reentrant call inside <_io.BufferedWriter name='<stdout>'>
msg244037 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2015-05-25 14:03
> RuntimeError: reentrant call inside <_io.BufferedWriter name='<stdout>'>

As the exception message suggests: the IO stack is not reentrant. If an ongoing IO call is interrupted by a signal, and the signal handler calls again into the IO stack, this situation is detected and an error is raised. If instead we allowed the IO call to continue, all sorts of problems could ensue (data loss, crashes...).

So, indeed, print() is not safe in signal handlers. Though the fact that it raises an exception, rather than crashes, makes things easier for the developer ;)
msg244041 - (view) Author: Devin Jeanpierre (Devin Jeanpierre) * Date: 2015-05-25 15:59
It doesn't do any of those things in Python 2, to my knowledge. Why aren't we willing to make this work?
msg244042 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2015-05-25 16:05
> It doesn't do any of those things in Python 2, to my knowledge.

Well, even if Python 2 doesn't warn you,  threading_print_test.py is also wrong on Python 2. Python 3 is better because it warns you :-)

> Why aren't we willing to make this work?

It would be very complex to support reentrant calls in the io stack. It's much easier to redesign your application to defer the work of the signal handler outside the signal handler.
History
Date User Action Args
2015-05-25 16:05:11vstinnersetmessages: + msg244042
2015-05-25 15:59:26Devin Jeanpierresetmessages: + msg244041
2015-05-25 14:03:24pitrousetstatus: open -> closed
resolution: wont fix
messages: + msg244037

stage: resolved
2015-05-25 13:55:46r.david.murraysetnosy: + pitrou
2015-05-25 08:37:41Devin Jeanpierrecreate