Process supervision and exception

T

titetluc

Hi all

My problem: I have a library managing Perl objects
An object may be composed of several processes

Here is an example of my library (be careful: the sleep call are used
only for debug purpose !!)
#!/usr/bin/perl -w
use strict;

package obj;

sub new
{
my $class = shift;
my %param = @_;
my %obj;
$obj{name} = $param{name};

my @pid;
$pid[0] = fork();
if (!$pid[0]){
sleep(5);
# the treatment to be declared here
exit(1);
}
print "PID: $pid[0]";
$pid[1] = fork();
if (!$pid[1]){
sleep(10000);
# the treatment to be declared here
}
print "PID: $pid[1]";

bless \%obj, $class;
}

sub action
{
my $obj = shift;
sleep(10000);
}

__END__

I would like my library to raise an exception when one of the process
dies for any reasons.

A code, implementing the process death detection and the exception
raise, could be:

sub watch
{
my @pid = @_;
my $p = waitpid(-1,0);
my $to_kill = $pid[0];
if ($p == $to_kill){
$to_kill = $pid[1];
}
kill 15, $to_kill;
die "goodbye cruel world\n";
}


I could then use the library as follows:

package main;
sub main
{
my $o1 = obj->new(name=> 'o1');
my $o2 = obj->new(name=> 'o2');

eval {$o1->action();};
if ($@){
print "o1 killed\n";
}
eval {$o2->action();};
if ($@){
print "o2 killed\n";
}
}

main();
1;

My problem is that I don't know how to call the 'watch' function

.. I could call it in a CHLD sig handler, but in this case I do not
know which object "generates" the CHLD signal. In addtion, the method
is very intrusive because it requires the signal handler declaration
in the main module.
.. I could declare a thread supervision per object (adding the line
threads->new(\&watch, @pid)->detach(); in the obj::new constructor)
but this does not run (message 'thread failed to start: goodbye cruel
world')

I didn't find any information in this group nor in perldoc
Any idea ?

Thanks

Gaetan
 
X

xhoster

Hi all

My problem: I have a library managing Perl objects
An object may be composed of several processes

Here is an example of my library (be careful: the sleep call are used
only for debug purpose !!)


The above doesn't really describe what it is you want to do. And your code
also doesn't do what you want it to do. Between the two of those, I'm left
wondering just what it is you want to do.


#!/usr/bin/perl -w
use strict;

package obj;

sub new
{
my $class = shift;
my %param = @_;
my %obj;
$obj{name} = $param{name};

my @pid;
$pid[0] = fork();
if (!$pid[0]){
sleep(5);
# the treatment to be declared here
exit(1);
}
print "PID: $pid[0]";
$pid[1] = fork();
if (!$pid[1]){
sleep(10000);
# the treatment to be declared here
}
print "PID: $pid[1]";

bless \%obj, $class;
}

@pid is lexical to the sub new, and isn't saved anywhere, so once new
finishes, @pid is lost.
sub action
{
my $obj = shift;
sleep(10000);
}

__END__

I would like my library to raise an exception when one of the process
dies for any reasons.

A code, implementing the process death detection and the exception
raise, could be:

sub watch
{
my @pid = @_;
my $p = waitpid(-1,0);
my $to_kill = $pid[0];
if ($p == $to_kill){
$to_kill = $pid[1];
}
kill 15, $to_kill;
die "goodbye cruel world\n";
}

What if the thing waitpid returns is neither $pid[0] or $pid[1]?

I could then use the library as follows:

package main;
sub main
{
my $o1 = obj->new(name=> 'o1');
my $o2 = obj->new(name=> 'o2');

eval {$o1->action();};
if ($@){
print "o1 killed\n";
}

What if one of the processes from $o2 dies while in the middle of
$o1->action? What is the desired action?
eval {$o2->action();};
if ($@){
print "o2 killed\n";
}
}

main();
1;

My problem is that I don't know how to call the 'watch' function

I don't think that there is any right way to call your existing watch
function. You need to re-arrange it.
. I could call it in a CHLD sig handler, but in this case I do not
know which object "generates" the CHLD signal.

You need a global (or widely-scoped lexical) hash that records the pids
that are started as keys, and the object that started it (or maybe some
kind of closure) as values. Then in a subroutine which is triggered by
SIGCHLD (or some other way), you would call waitpid, get the return value,
and look it up in the global hash to see what object you are in.


my $kid;
while (($kid = waitpid(-1, WNOHANG)) >0) {
die "Someone is spawning children ($kid) without telling me!"
unless exists $global_pid{$kid};
my $object = delete $global_pid{$kid};
if ($object->action_pending()) {
# action is pending on this action, so die to get out of it
die "Something went wrong with the object you are trying to use"
} else {
# no object pending, don't die until next time this object is used.
$object->hosed(1);
};
};

In addtion, the method
is very intrusive because it requires the signal handler declaration
in the main module.

Not all situations can be handled in a nice encapsulated manner. For Perl,
at least, this is one of those situations. I don't think you will find any
non-intrusive way to do this.

. I could declare a thread supervision per object (adding the line
threads->new(\&watch, @pid)->detach(); in the obj::new constructor)
but this does not run (message 'thread failed to start: goodbye cruel
world')

Oh ick. Management of threading and forking are both bad enough on their
own. Mixing them is just that much worse.

Xho
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top