4

From here, i found that when a signal is received, exit_gracefully is called meanwhile the code inside while True is running. At first i thought that handler is running in another thread so i wrote a code to test it out:

import os
import signal
import threading

def sig_handler(signal_frame, num):
    print('handler PID: {}'.format(os.getpid()))
    print('current thread identity: {}'.format(threading.current_thread().ident))

signal.signal(signal.SIGTERM, sig_handler)

try:
    print('main execution PID: {}'.format(os.getpid()))
    print('current thread identity: {}'.format(threading.current_thread().ident))
    while True:
        time.sleep(5)
        print('Hello')
except KeyboardInterrupt:
    print('Good bye')

I ran the code and first sent a SIGTERM signal (using kill -SIGTERM pid command) and then sent a SIGINT signal. The output was:

main execution PID: 1002
current thread identity: 140284238558976
Hello
Hello
handler PID: 1002
current thread identity: 140284238558976
Hello
Hello
Good bye

You see that everything is the same, but how it's possible that the handler is running in the same exact context that main code is executing? Shouldn't be in another thread?

Mehran Torki
  • 977
  • 1
  • 9
  • 37

1 Answers1

3

The answer you're looking for is right in the python signal documentation:

Python signal handlers are always executed in the main Python thread, even if the signal was received in another thread.

Also:

the low-level signal handler sets a flag which tells the virtual machine to execute the corresponding Python signal handler at a later point

So when a signal is received, the handler doesn't execute alongside the code in the while loop. Instead, the virtual machine executing your code is told to run the signal handling code 'soon', which could be after X number of bytecode instructions, so essentially your loop goes on pause while the handler code is running. Changing your code a little demonstrates this:

def sig_handler(signal_frame, num):
    print('handler PID: {}'.format(os.getpid()))
    print('current thread identity: {}'.format(threading.current_thread().ident))
    time.sleep(5) # we put a long delay here

signal.signal(signal.SIGTERM, sig_handler)

try:
    print('main execution PID: {}'.format(os.getpid()))
    print('current thread identity: {}'.format(threading.current_thread().ident))
    while True:
        time.sleep(1) # sleep less now
        print('Hello')
except KeyboardInterrupt:
    print('Good bye')

Now, when you send your SIGTERM, you'll notice the execution of your while loop pauses for 5s.

codelessbugging
  • 2,849
  • 1
  • 14
  • 19