import time
import signal
global_thing = []
class Foreman:
def __init__(self):
signal.signal(signal.SIGUSR1, self.handle_sigusr1)
def handle_sigusr1(self, sig, frame):
global_thing.append("x")
i_am_nr = len(global_thing)
for i in range(4):
print("I am taking my sweet time", i_am_nr, i)
time.sleep(1)
def run_forever(self):
# there is no actual code here, all the action happens in the signal handlers
time.sleep(3600)
Foreman().run_forever()
To my slight surprise, the result of this, when sending a second signal while the first one is still being dealt with, is like so:
$ python example.py
I am taking my sweet time 1 0
I am taking my sweet time 1 1
I am taking my sweet time 1 2
I am taking my sweet time 2 0
I am taking my sweet time 2 1
I am taking my sweet time 2 2
I am taking my sweet time 2 3
I am taking my sweet time 1 3
In other words, it appears that the signal handler is in turn suspended. However, I cannot find anything in the Python docs that describes this. To rely on this behavior I would like to have some kind of document that explains what the expected behavior is.
In addition, and similarly: what happens if 2 signals arrive at (almost) the exact same time: will the CPython interpreter be able to catch them both and deal with them as observed? Or is there some lower level where this can still go wrong (and in what way?)
(I'm particularly interested in Linux)
This behavior is implied by this part of the documentation:
A Python signal handler does not get executed inside the low-level (C) signal handler. Instead, the low-level signal handler sets a flag which tells the virtual machine to execute the corresponding Python signal handler at a later point(for example at the next bytecode instruction).
So while it's executing the first signal handler, another signal comes in. This sets the above flag, so when the interpreter finishes the current instruction in the first signal handler, it calls the handler again.
When this second call returns, it resumes where it was in the first signal handler.