Please kill the children as you're leaving


#1

Sorry about the Macabre, but that’s essentially what I want: It seems
that children of my process (created using fork) get reparanted to init
when my process dies unexpectedly. I’d like to have them all die on the
spot instead (not wait for them to finish - kill them on the spot). How
do I do this?

I assume it would have to do with a big begin/rescue/end block around
the whole app…


#2

Allow me to clarify the problem. Say I use irb as follows:

fork do
{ } while true
end
=> SOME_PID

Now, if I kill (externally) the parent irb, then SOME_PID dies along
with it. However, if instead of doing that, I

raise Exception

Then the child lives, reparanted to init. How do I avoid that?


#3

2006/6/4, Ohad L. removed_email_address@domain.invalid:

raise Exception

Then the child lives, reparanted to init. How do I avoid that?

You can either have a beginn rescue end block on your top level or you
use at_exit to deal with the situation, i.e. kill children:

http://www.ruby-doc.org/core/classes/Kernel.html#M002953

Kind regards

robert


#4

How does your parent process die unexpectedly? If it catches signal 9,
for
example, your atexit handlers won’t run. You could try something
dramatic
like open a socketpair between parent and child processes (don’t forget
to
turn off CLOEXEC for forking) and then have the child processes
periodically
send a byte to the parent. If you lose the parent, then the write from
the
child should catch SIGPIPE. Also possible is for the children to
periodically to check the status of the parent process (getppid).


#5

On Sun, 4 Jun 2006, Francis C. wrote:

How does your parent process die unexpectedly? If it catches signal 9, for
example, your atexit handlers won’t run. You could try something dramatic
like open a socketpair between parent and child processes (don’t forget to
turn off CLOEXEC for forking) and then have the child processes periodically
send a byte to the parent. If you lose the parent, then the write from the
child should catch SIGPIPE. Also possible is for the children to
periodically to check the status of the parent process (getppid).

indeed. this is exactly what my slave library does - it sets up a
heartbeat
pipe between parent and child. this way, even if the parent dies via
‘kill
-9’, which no code can handle, the child will die. eg.

harp:~ > cat a.rb

http://codeforpeople.com/lib/ruby/slave/

require ‘slave’

class Child
def initialize
@pid = Process.pid
Thread.new{loop{warn “child <#{ @pid }> @ <#{ Time.now }>”; sleep
1}}
end
end

class Parent
def initialize
@pid = Process.pid
@child = Slave.new(Child.new)
sleep 3
Process.kill -9, @pid
end
end

Parent.new

harp:~ > ruby a.rb
child <26196> @ <Sun Jun 04 09:11:17 MDT 2006>
child <26196> @ <Sun Jun 04 09:11:19 MDT 2006>
child <26196> @ <Sun Jun 04 09:11:20 MDT 2006>
Killed

ps. the gem for slave is on rubyforge but, for some reason, a ‘gem
install
slave’ does not work. you can download the gem manually here:

http://rubyforge.org/frs/?group_id=1024&release_id=5464

pss. this is setup exactly like all the other projects under
codeforopeople -
if anyone has any ideas on why slave installs fail please contact me
offline.

cheers.

-a


#6

Non with irb, but you may be able to make the parent a session leader,
which might cause SIGHUP to be delivered to its children when it exits.

If a process becomes a process group leader (setpgid(0,0) in the child
process after the fork and before it calls exec), then its parent can
kill
it and all of its subprocesses by sending a signal to the negative of
its
pid. Not sure that helps here though. The best idea I’ve heard so far is
for
the child processes to periodically write a pipe that terminates in the
parent. Then if the parent goes, the children will get killed by
SIGPIPE.

This stuff is pretty hard to get right, have to admit.


#7

Quoting removed_email_address@domain.invalid, on Sun, Jun 04, 2006 at 10:15:08PM +0900:

raise Exception

Then the child lives, reparanted to init. How do I avoid that?

Non with irb, but you may be able to make the parent a session leader,
which might cause SIGHUP to be delivered to its children when it exits.

Do some reading on sessions, setsid(), and forground process groups.

Other ways would depend on why you want to do this. You could create a
pipe, and have all your children keep a thread blocked on the read end
of it, so when the parent dies, the write end is closed, and all the
read ends return with an error.

Sam


#8

Advance Programming in the Unix Environment, p.267 (R. Stevens) says:

SIGHUP … This signal is also generated if the session leader
terminates. In this case, the signal is sent to each process in the
foreground process group.

It sounds like it should be possible to arrange for sighup to be sent to
an entire process group automatically if the session leader terminates.
<<<<<<<<<<<<

You get this automatically. I assumed that the OP was raising the issue
because he’s running in some environment (like a daemon or a cron job)
where
there is no controlling tty or foreground process group.


#9

Quoting removed_email_address@domain.invalid, on Mon, Jun 05, 2006 at 10:02:30AM
+0900:

Non with irb, but you may be able to make the parent a session leader,
which might cause SIGHUP to be delivered to its children when it exits.

If a process becomes a process group leader (setpgid(0,0) in the child
process after the fork and before it calls exec), then its parent can kill
it and all of its subprocesses by sending a signal to the negative of its
pid. Not sure that helps here though. The best idea I’ve heard so far is for

Advance Programming in the Unix Environment, p.267 (R. Stevens) says:

SIGHUP … This signal is also generated if the session leader
terminates. In this case, the signal is sent to each process in the
foreground process group.

It sounds like it should be possible to arrange for sighup to be sent to
an entire process group automatically if the session leader terminates.

Cheers,
Sam


#10

On 6/4/06, removed_email_address@domain.invalid removed_email_address@domain.invalid wrote:

ps. the gem for slave is on rubyforge but, for some reason, a ‘gem install
slave’ does not work. you can download the gem manually here:

http://rubyforge.org/frs/?group_id=1024&release_id=5464

pss. this is setup exactly like all the other projects under codeforopeople -
if anyone has any ideas on why slave installs fail please contact me offline.

Probably because the version number is 0.0.0 and gem looks for >0 when
installing something.

Pedro.