1

I have two Python scripts foo.py and bar.py, foo.py will call bar.py via os.system().

#foo.py
import os

print os.getpid()
os.system("python dir/bar.py")
#bar.py
import time

time.sleep(10)
print "over"

Say the pid of foo.py is 123, if the program terminate normally, it'll print

123
over

If I type kill 123 while it's running, I'll get the following output

123
Terminated
over

If I press Ctrl-C while it's running, I'll get something like

123
^CTraceback (most recent call last):
  File "dir/bar.py", line 4, in <module>
    time.sleep(10)
KeyboardInterrupt

But if I type kill -SIGINT 123 while it's running, it seems the program will just ignore the signal and exit normally.

123
over

It seems to me that,
if I type kill 123, the sub-process will not be affected.
if I type Ctrl-C, both processes will be terminated.
if I type kill -SIGINT 123 while the sub-process is running, the signal will be ignored.

Can someone please explain to me how it works?
Isn't Ctrl-C and kill -SIGINT supposed to be equivalent?
If I type kill 123 is it guaranteed that the sub-process will not be affected (if it happens to be running)?

I am on Ubuntu 14.04 by the way. Thanks!

dontloo
  • 10,067
  • 4
  • 29
  • 50

1 Answers1

2

Let's consider each case in turn:

if I type kill 123, the sub-process will not be affected.

Yes, that's how kill [pid] works. It sends a signal only to the process you want to kill. If you want to send the signal to an group of processes, then you have to use the negative number representing the process group.

if I type Ctrl-C, both processes will be terminated.

I assume you mean "terminated by Ctrl-C". Actually, that's not the case: only the child is terminated. If you add at the end of foo.py a line like this one print "I'm a little teapot", you'll see this line gets printed. What happens is that the child gets the signal. The parent then continues from os.system. Without the additional line, it looks like the parent was also affected by the Ctrl-C but it is not the case, as the additional line shows.

You shell does send the signal to the process group that is associated with the tty, which includes the parent. However, os.system uses the system call which blocks the SIGINT and SIGQUIT signals in the process that makes the call. So the parent is immune.

If you do not use os.system, then your process will be affected by the SIGINT. Try this code for foo.py:

import os
import subprocess

print os.getpid()
p = subprocess.Popen(["python", "dir/bar.py"])
p.wait()
print "I'm a little teapot"

If you hit Ctrl-C while this runs, you'll get two tracebacks: one from the parent, one from the child:

$ python foo.py 
29626
^CTraceback (most recent call last):
  File "dir/bar.py", line 4, in <module>
Traceback (most recent call last):
  File "foo.py", line 8, in <module>
    time.sleep(10)
KeyboardInterrupt    p.wait()

  File "/usr/lib/python2.7/subprocess.py", line 1389, in wait
    pid, sts = _eintr_retry_call(os.waitpid, self.pid, 0)
  File "/usr/lib/python2.7/subprocess.py", line 476, in _eintr_retry_call
    return func(*args)
KeyboardInterrupt

if I type kill -SIGINT 123 while the sub-process is running, the signal will be ignored.

See above.

Isn't Ctrl-C and kill -SIGINT supposed to be equivalent?

Ctrl-C does send a SIGINT to foreground process group associated with the tty in which you issue the Ctrl-C.

If I type kill 123 is it guaranteed that the sub-process will not be affected (if it happens to be running)?

By itself kill 123 will send the signal only to the process with pid 123. Children won't be affected.

Louis
  • 146,715
  • 28
  • 274
  • 320