signal handling in preexec_fn of subprocess.Popen does not work

Viewed 196

I'm trying to handle signals of a child process executed with subprocess.Popen(..., preexec_fn=...).

According to the documentation, preexec_fn is run in the child process, so theoretically the following two programs should behave the same, where the first one handles the signal inside the embedded c code, and the second one handles the signal from outside by a python function.

By examining the exit code being 0 or not, however, I found that only handling inside the c code actually works. Does anyone have an idea why signal handling in python doesn't work?

Thanks!

handling from inside, exit with 0:

from tempfile import TemporaryDirectory
import subprocess
import signal
import os

c_code = """
#include <csignal>
#include <cstdlib>
#include <iostream>

int main() {
  std::signal(SIGFPE, [](int){std::quick_exit(0);});  // handling the signal here
  std::cout <<3/0 <<std::endl;
}
"""

def handle_sigfpe():
    # signal.signal(signal.SIGFPE, lambda: os.exit(0)) # not handling here
    pass

def main():
    print(f'main pid: {os.getpid()}', flush=True)
    with TemporaryDirectory() as d:
        code_path = f'{d}/a.cpp'
        bin_path = f'{d}/a'
        with open(code_path, 'w') as f:
            print(c_code, file=f)
        assert(subprocess.run(['g++', '-o', bin_path, code_path]).returncode == 0)
        p = subprocess.Popen([bin_path], preexec_fn=handle_sigfpe)
        p.wait()
        print(f'return code: {p.returncode}', flush=True)


main()

handling from outside, exit with -8 (SIGFPE):

from tempfile import TemporaryDirectory
import subprocess
import signal
import os

c_code = """
#include <csignal>
#include <cstdlib>
#include <iostream>

int main() {
  // std::signal(SIGFPE, [](int){std::quick_exit(0);});  // not handling the signal here
  std::cout <<3/0 <<std::endl;
}
"""

def handle_sigfpe():
    signal.signal(signal.SIGFPE, lambda: os.exit(0))   # but here
    pass

def main():
    print(f'main pid: {os.getpid()}', flush=True)
    with TemporaryDirectory() as d:
        code_path = f'{d}/a.cpp'
        bin_path = f'{d}/a'
        with open(code_path, 'w') as f:
            print(c_code, file=f)
        assert(subprocess.run(['g++', '-o', bin_path, code_path]).returncode == 0)
        p = subprocess.Popen([bin_path], preexec_fn=handle_sigfpe)
        p.wait()
        print(f'return code: {p.returncode}', flush=True)


main()
0 Answers
Related