Send Sigint in Python to Os.System

Send SIGINT to Python subprocess using os.kill as if pressing Ctrl+C

It's not working because you can't use os.kill to send arbitrary signals on Windows:

os.kill(pid, sig)

Send signal sig to the process pid. Constants for the specific signals
available on the host platform are defined in the signal module.

Windows: The signal.CTRL_C_EVENT and signal.CTRL_BREAK_EVENT signals
are special signals which can only be sent to console processes which
share a common console window, e.g., some subprocesses. Any other
value for sig will cause the process to be unconditionally killed by
the TerminateProcess API, and the exit code will be set to sig
. The
Windows version of kill() additionally takes process handles to be
killed.

The only signals that can be sent via os.kill are signal.CTRL_C_EVENT and signal.CTRL_BREAK_EVENT. Anything else just terminates the process, which is what is happening in your case. Using signal.CTRL_C_EVENT won't work here, either, because processes started via multiprocessing.Process aren't "console processes which share a common console window" with the parent. I'm not sure there's much you can do here with signals on Windows; It doesn't look like you're allowed to catch TerminateProcess the way you can catch SIGTERM on Unix, so you can't do any clean up prior to the process terminating, and you're not using a console application for the child, so signal.*_EVENT won't work.

I think your options are: 1) Use the subprocess module, and launch the child process with shell=True, which I believe will mean signal.CTRL+C+EVENT will work. 2) Stick with the multiprocessing module, and use a "co-operative" method of interrupting the worker, like multiprocessing.Event.

Sending a Ctrl+C SIGINT to sudoed C subprocess from python framework

You are actually getting pid of and killing sudo process (that forked your application process). Instead you should kill the whole process group with:

import subprocess, os
p = Popen(["sudo", "./a.out"])
pgid = os.getpgid(p.pid)
subprocess.check_output("sudo kill {}".format(pgid))

or with the help of pkill:

import subprocess
p = Popen(["sudo", "./a.out"])
subprocess.call(f"sudo pkill -2 -P {p.pid})

python forward SIGINT to subprocess

The code is in subprocess.run, the function you called. SIGINT gets converted into a KeyboardInterrupt exception, which is handled by an except clause that calls process.kill(). You could implement different handling of SIGINT using the signal module. Notably, kill doesn't send SIGINT but sends SIGKILL, so the subprocess does not get a chance to do similar handling with this default cleanup.

Python parent process is not catching SIGTERM/SIGINT signals when launching subprocess using os.sytem()

I think you'll have better luck with subprocess than os.system. In particular, I think you'll want to use subprocess with shell=False so that your child command is executed without a subshell (which might interfere with your ability to handle these kinds of signal-handling scenarios).

The code below does what you want, if I understand you correctly: CTRL-C causes both child and parent to stop; but if child dies for some other reason, parent will run the child again.

Here's a parent program similar to yours:

import signal
import subprocess

shutdown = False

def sigterm_handler(signum, frame):
print 'parent got shutdown'
global shutdown
shutdown = True

if __name__ == '__main__':
signal.signal(signal.SIGTERM, sigterm_handler)
signal.signal(signal.SIGINT, sigterm_handler)
cmd_args = ['python', 'child.py']
while not shutdown:
print 'executing', cmd_args
try:
subprocess.check_call(cmd_args)
except subprocess.CalledProcessError:
print 'child died'
pass
print 'Exiting Parent'

And here is a child program that runs for a while and then dies with a ZeroDivisionError.

import signal
import sys
import time

def sigterm_handler(signum, frame):
print 'child got shutdown'
sys.exit(0)

if __name__ == '__main__':
signal.signal(signal.SIGTERM, sigterm_handler)
signal.signal(signal.SIGINT, sigterm_handler)
for i in range(3, -1, -1):
print 'Child Process Running', i, i/i
time.sleep(3)

How do I capture SIGINT in Python?

Register your handler with signal.signal like this:

#!/usr/bin/env python
import signal
import sys

def signal_handler(sig, frame):
print('You pressed Ctrl+C!')
sys.exit(0)

signal.signal(signal.SIGINT, signal_handler)
print('Press Ctrl+C')
signal.pause()

Code adapted from here.

More documentation on signal can be found here.
 

python SIGINT not terminating calling shell

After considerable digging I found a few loosely related questions on Stack Overflow that eventually led me to an article describing the proper handling of SIGINT. (The most relevant section is How to be a proper program.)

From this information, I was able to solve the problem. Without it, I would have never have come close.

The solution is best illustrated by beginning with a bash script that cannot be terminated by a keyboard interrupt, but which does hide the ugly stack trace from Python's KeyboardInterrupt exception:

#!/usr/bin/env bash                                                             
echo "Press Ctrl-C to stop... No sorry it won't work."
while true
do
python -c '
import time, signal
signal.signal(signal.SIGINT, signal.SIG_IGN)
time.sleep(100)
'
done

The change that makes the outer script process the interrupt is:

echo "Press Ctrl-C to stop..."
while true
do
python -c '
import time, signal, os
signal.signal(signal.SIGINT, signal.SIG_DFL)
time.sleep(100)
'
done

However, this solution makes it impossible to use a custom handler (for example, to perform cleanup). If doing so is required, then a more sophisticated approach is needed:

#!/usr/bin/env bash
echo "Press [CTRL+C] to stop ..."
while true
do
python -c '
import time, sys, signal, os
def handle_int(signum, frame):
# Cleanup code here
signal.signal(signum, signal.SIG_DFL)
os.kill(os.getpid(), signum)
signal.signal(signal.SIGINT, handle_int)
time.sleep(100)
'
done

The reason appears to be that unless the inner process terminates through executing the default SIGINT handler provided by the system, the parent bash process does not realize that the child has terminated because of a keyboard interrupt, and does not itself terminate.

I have not fully understood all the ancillary issues quite yet, such as whether the parent process is not receiving the SIGINT from the system, or is receiving a signal, but ignoring it. I also have no idea what the default handler does or how the parent detects that it was called. If I am able to learn more, I will offer an update.

I must advance the question of whether the current behavior of Python should be considered a design flaw in Python. I have seen various manifestations of this issue over the years when calling Python from a shell script, but have not had the luxury of investigation until now. I have not found a single article through a web search, however, on the topic. If the issue does represent a flaw, it surprised me to observe that not many developers are affected.



Related Topics



Leave a reply



Submit