I can't seem to get my python program to kill all the child prcoesses
that it may fork. Is this possible?
I've researched usenet+the web and read subproc.py from
ftp.python.org, but still no go.
My latest attempt was a python script that forks itself, uses setpgid,
then the child does an execl(). The execl'd program creates some
children. Meanwhile, the parent decides time is up on the child and
tries to kill everything, but my os.kill(pid,9) only succeeds in
killing the child aka the execvp'd process.
There's another bug that I haven't yet addressed about the parent
waiting around when the child doesn't write to either of the pipes.
But that'd not my focus now, so don't worry about that; I just want
all the children to die.
My full code it at the bottom. Hints, anyone? This is on Linux and
FreeBSD.
Thanks,
Kevin
---Full code follows---
---- pcontrol.py below
#!/usr/bin/python
#
# pcontrol.py
#
import os
import sys
import signal
_alarm = "request timed out"
time = 5
cmd="sh1.sh"
###########################################################
def alarm_handler(a , b):
global _alarm
signal.alarm(0)
raise _alarm
###########################################################
# Okay, let's do this the hard way: create two unnamed
# pipes for stdout/err. Then, fork this process, and the
# child becomes the new command and shoves their output
# onto the pipes, while the parent waits for the child to die.
# Create two named pipes
child_out_r, child_out_w = os.pipe()
child_err_r, child_err_w = os.pipe()
# Let's fork a child that gets replaced with the test process - krf
child_pid = os.fork()
if (child_pid != 0):
# We're the parent
os.close(child_out_w) # the parent won't read the pipes
os.close(child_err_w)
os.setpgid(child_pid, 0)
# Now do the timing...
signal.signal(signal.SIGALRM, alarm_handler)
signal.alarm(time)
try:
child_pid, child_status = os.waitpid(child_pid, 0); # wait for
child
except OSError:
print("OSError... did the executable time out?")
child_status = -1 # this is the same as a timeout for now
except _alarm:
print("Timed out")
# kill it!
os.kill(child_pid, 9)
child_status = -1 # timeout
signal.alarm(0) # clean up alarm
else:
# We're the child
os.setpgid(0, 0) # now the child is it's group leader (?)
# Redirect error to our pipes
os.close(child_out_r) # the child won't read the pipes
os.close(child_err_r)
os.dup2(child_out_w, sys.stdout.fileno())
os.dup2(child_err_w, sys.stderr.fileno())
# replace the process
os.execl(cmd, cmd) #strange, but execl->execv needs a second
arg...
# the child is no more... (assuming success)
print "Status = ", child_status
print "Child stdout [",os.read(child_out_r,999),"]"
print "Child stderr [",os.read(child_err_r,999),"]"
------- sh1.sh below
#!/bin/sh
echo "This is processs (1) $$."
sh2.sh &
sh3.sh &
sleep 600
echo "Process (1) $$ exiting."
------- sh2.sh below
#!/bin/sh
echo "This is processs (2) $$."
sleep 600
echo "Process (2) $$ exiting."
------- sh3.sh below
#!/bin/sh
echo "This is processs (3) $$."
sleep 600
echo "Process (3) $$ exiting."
So in the line that reads:
os.kill(child_pid, 9)
You need to change it to read:
os.kill(-child_pid, 9)
That kills the given pid and every process that has a
process group id with the same number as the child_pid.
You ensured that all the children had the same group as
the first child (session leader) when you wrote this line:
os.setpgid(0, 0)
But note that Python has a special call just for that:
os.setpgrp() # Sets process session leader.
FYI, execlp() takes two arguments because the
first one is the path to the command to exec and the second
one is supposed to become the argv[0] of the command.
But it doesn't seem to do that. I'm not sure why.
Yours,
Noah
Let's see if I can visualise:
Parent_1
|
____|____
| |
Child1 Child2
|
Child3
Now, if I send a SIGKILL to Parent_1, it will pass on <SIGKILL> to
Child1 and Child2. Child1 will pass on <SIGKILL> to Child3 via the same
mechanism.
The only potential problem would be if a child branch died before hand,
and the PID was taken by another process that Parent_1 could kill (same
user).
Hope this helps, if not, just ignore my waffling.
Martin.
> --
> http://mail.python.org/mailman/listinfo/python-list
>
--
Experience is that marvelous thing that enables you recognize a mistake
when you make it again.
-- F. P. Jones