5

I have a server that starts a subprocess, and I can manage to do a send_signal(SIGTERM) which will kill the process. But not gracefully. If I call my subprocess from shell (i.e. as a single process), the defined signal handler will kick in and exit gracefully.

server.py: (so.. from another script I first call start_app(), and later exit_app()

def start_app():
    app = subprocess.Popen("python app.py")

def exit_app():
    p = app.poll()
    if p==None:
        print("Subprocess is alive") # debug
    app.send_signal(signal.SIGTERM)

app.py

def exit_signal_handler(signal, frame):
    print("Terminate signal received")
    app.exit()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    signal.signal(signal.SIGTERM, exit_signal_handler)
    signal.signal(signal.SIGINT, exit_signal_handler)
    sys.exit(app.exec())

Again, if I call app.py from shell and send a SIGTERMsignal I get a trace Terminate signal received and app closes. But when app.py is started by server and I call exit_app in server, I get a trace Subprocess is alive (from server.py) and app is killed but the signal is not caught in app's signalhandler exit_signal_handler

EDIT: It seems send_signal() doesn't send a signal to the subprocess in the sense that subprocess catches the signal. It send`s a signal for an action to take place on the subprocess:

    def send_signal(self, sig):
        """Send a signal to the process
        """
        if sig == signal.SIGTERM:
            self.terminate()
        elif sig == signal.CTRL_C_EVENT:
            os.kill(self.pid, signal.CTRL_C_EVENT)
        elif sig == signal.CTRL_BREAK_EVENT:
            os.kill(self.pid, signal.CTRL_BREAK_EVENT)
        else:
            raise ValueError("Unsupported signal: {}".format(sig))

This probably answers my question but I'll leave it open...

georgexsh
  • 15,984
  • 2
  • 37
  • 62
niCk cAMel
  • 869
  • 1
  • 10
  • 26
  • @georgexsh killed = finished, exited, process no longer running on CPU. And `poll()` is done just as a sanity check to see that subprocess is actually alive before sending `SIGTERM` – niCk cAMel Nov 15 '17 at 18:39
  • so real issue is you haven't seen the message that signal handler should be printed out? try write to file instead? – georgexsh Nov 15 '17 at 19:02
  • @georgexsh hmm... Good point. I see where you're going with this, but stuff that happens in `__main__` gets printed when run as `subprocess()`. I have `print()` there as well but just haven't included it here. – niCk cAMel Nov 15 '17 at 19:13
  • you could confirm this by writing log to a file, and check the return value of `app.poll()` is 0 or -15, 0 means a normal exit and the signal handler worked. – georgexsh Nov 16 '17 at 07:00
  • with your new edit, are you using windows? – georgexsh Nov 16 '17 at 19:43
  • The edit is a copy paste of `signal.send_signal()` routine. Yes, windows – niCk cAMel Nov 16 '17 at 19:48
  • oops, I assumed Linux. – georgexsh Nov 16 '17 at 19:59

1 Answers1

10

As you are using Windows, SIGTERM handler is useless, more reference:

On Windows, the C runtime implements the six signals that are required by standard C: SIGINT, SIGABRT, SIGTERM, SIGSEGV, SIGILL, and SIGFPE.

SIGABRT and SIGTERM are implemented just for the current process.

But you could use signal.CTRL_BREAK_EVENT as an alternative.

I.e. create a signal handler in app.py that handles SIGBREAK, but send the CTRL_BREAK_EVENT from the parent. Also, make sure to start your subprocess using creationflags=subprocess.CREATE_NEW_PROCESS_GROUP (otherwise it will kill the parent as well)

app = subprocess.Popen("python app.py", shell=True, creationflags=subprocess.CREATE_NEW_PROCESS_GROUP)
time.sleep(1)

while 1:
    p = app.poll()
    if p is not None:
        break
    app.send_signal(signal.CTRL_BREAK_EVENT)
    time.sleep(2)

app.py:

exit = False

def exit_signal_handler(signal, frame):
    global exit
    print("Terminate signal received")
    exit = True

signal.signal(signal.SIGBREAK, exit_signal_handler)
while not exit:
    pass
Community
  • 1
  • 1
georgexsh
  • 15,984
  • 2
  • 37
  • 62
  • Maybe I've been unclear, might edit the question. In both cases the application is terminated by `SIGTERM` but when running as subprocess the signal handler in app.py is not called... The application is just terminated promptly – niCk cAMel Nov 15 '17 at 18:41
  • 1
    Nice references. Thing is, if I register `SIGINT` and press ctrl+c on my keyboard, my handler catches the signal... But when run as subprocess, I can't send the signal from script since `send_signal(signal.SIGINT)` throws an error (as seen in my edit). It's all weird – niCk cAMel Nov 16 '17 at 20:07
  • why you use `SIGINT`? – georgexsh Nov 16 '17 at 20:41
  • Aahhh... You register `SIGBREAK` but send `CTRL_BREAK_EVENT` – niCk cAMel Nov 16 '17 at 20:50
  • Lol, I'll try it first thing in the morning, left laptop at work. I'll get back to you on this in 11h ;) – niCk cAMel Nov 16 '17 at 20:54
  • But how is one supposed to know that about signals? That `SIGBREAK` and `CTRL_BREAK_EVENT` are related? – niCk cAMel Nov 16 '17 at 20:55
  • then how do you that they don't? you should read all the references first. – georgexsh Nov 16 '17 at 21:03
  • I don't know, I'm just asking how **you** knew that they are related. – niCk cAMel Nov 16 '17 at 21:06
  • I feel it is not very nice that asking before reading the references. – georgexsh Nov 16 '17 at 21:13
  • Got it! "When the console sends the process a CTRL_C_EVENT or CTRL_BREAK_EVENT, the CRT's handler calls the registered SIGINT or SIGBREAK" – niCk cAMel Nov 16 '17 at 21:16
  • Man, how do you find all these references haha – niCk cAMel Nov 16 '17 at 21:20
  • 3
    Thanks! Except the `CTRL_C_EVENT` + `SIGBREAK`, this `creationflags=subprocess.CREATE_NEW_PROCESS_GROUP` was **key**, without it, it will kill the parent aswell. – niCk cAMel Nov 17 '17 at 08:27
  • I encountered an issue with how (or actually **when** the signal was processed/handled. Do you have any inputs on that? https://stackoverflow.com/q/48687981/2923755 – niCk cAMel Feb 10 '18 at 23:19
  • @niCkcAMel ok. but I dont any experience with neither QT or window application dev. – georgexsh Feb 11 '18 at 03:34