Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I try to write a program that monitors several oracle instances and when the database creates an archived redo logfile then the program should fork a child and backup the archived log to tape.

Everthing works fine till I opened a DBI db-connection. If I do that the the parent doesn't receive a signal that the child died, nor it's return value. I don't want to you the db-connection in the child I only want to keep a persistent connection in the parent.

Does any one see what I am doing wrong or if there is a work around?

Tanks in advance,

Kris.
kris.lemaire@pandora.be

This code works fine (no db-connection)
# hash with the status of the childern
# at startup -> started 
# when child dies -> return code
my %h;

$| = 1;
# Trap sig send from child to parent
# when child dies -> then change the status to return value
$SIG{CHLD}= sub {$pid = wait();$h{$pid} = $?;};

# start forking 4 childern
for (my $i=1; $i < 5; $i++) {
  print "I'll fork a new child\n";
  if( !defined($child_pid = fork() ) ) {
    die "Can't fork : $!";
  } elsif ($child_pid) {
    # child started -> set status
    $h{$child_pid} = 'started';
  } else {
    child_action(3*$i, $i%2);
  }
}

# the parent sleeps 1 sec and then print the 
# status for all childeren
while (1) {
  foreach $key (sort keys %h) {
    print "$key->$h{$key} ";
  }
  print "\n";
  sleep 2;
}

# The child just sleep a few sec 
# prints to stdout when it stops
sub child_action {
  my ($sleeptime,$retcode) = @_;
  sleep 1; # always start sleeping 1 sec to allow initialisation
	print "I'm the child $$ and will sleep for $sleeptime s and return $retcode\n";
  sleep($sleeptime);
	print "I'm the child $$ : $retcode, I'm awake\n";
  exit $retcode;
}

# output :
#
#$ perl -w test5.pl
#I'll fork a new child
#I'll fork a new child
#I'll fork a new child
#I'll fork a new child
#15259->started 15260->started 15261->started 15262->started 
#I'm the child 15260 and will sleep for 6 s and return 0
#I'm the child 15259 and will sleep for 3 s and return 1
#I'm the child 15261 and will sleep for 9 s and return 1
#I'm the child 15262 and will sleep for 12 s and return 0
#15259->started 15260->started 15261->started 15262->started 
#I'm the child 15259 : 1, I'm awake
#15259->256 15260->started 15261->started 15262->started 
#15259->256 15260->started 15261->started 15262->started 
#I'm the child 15260 : 0, I'm awake
#15259->256 15260->0 15261->started 15262->started 
#15259->256 15260->0 15261->started 15262->started 
#I'm the child 15261 : 1, I'm awake
#15259->256 15260->0 15261->256 15262->started 
#15259->256 15260->0 15261->256 15262->started 
#I'm the child 15262 : 0, I'm awake
#15259->256 15260->0 15261->256 15262->0 
#15259->256 15260->0 15261->256 15262->0 
#15259->256 15260->0 15261->256 15262->0 
#15259->256 15260->0 15261->256 15262->0 
#^C
This code doesn't work (with db-connection)
use DBI;
# hash with the status of the childern
# at startup -> started 
# when child dies -> return code
my %h;

$| = 1;
# Trap sig send from child to parent
# when child dies -> then change the status to return value
$SIG{CHLD}= sub {$pid = wait();$h{$pid} = $?;};

# Open connection : this is when it goes wrong
my $dbh = DBI->connect("dbi:Oracle:", "/", "",
                       {PrintError=>1, RaiseError=>0, ora_session_mode=>2});
# Try without this line, with this line at 1 and at 0, but it doesn't work;
#$dbh->{InactiveDestroy} = 0;

# start forking 4 childern
for (my $i=1; $i < 5; $i++) {
  print "I'll fork a new child\n";
  if( !defined($child_pid = fork() ) ) {
    die "Can't fork : $!";
  } elsif ($child_pid) {
    # child started -> set status
    $h{$child_pid} = 'started';
  } else {
    child_action(3*$i, $i%2);
  }
}

# the parent sleeps 1 sec and then print the 
# status for all childeren
while (1) {
  foreach $key (sort keys %h) {
    print "$key->$h{$key} ";
  }
  print "\n";
  sleep 2;
}

# The child just sleep a few sec 
# prints to stdout when it stops
sub child_action {
  my ($sleeptime,$retcode) = @_;
  sleep 1; # always start sleeping 1 sec to allow initialisation
	print "I'm the child $$ and will sleep for $sleeptime s and return $retcode\n";
  sleep($sleeptime);
	print "I'm the child $$ : $retcode, I'm awake\n";
  exit $retcode;
}

# output :
#
#$ perl -w test6.pl
#I'll fork a new child
#I'll fork a new child
#I'll fork a new child
#I'll fork a new child
#15362->started 15363->started 15364->started 15365->started 
#I'm the child 15362 and will sleep for 3 s and return 1
#I'm the child 15363 and will sleep for 6 s and return 0
#I'm the child 15364 and will sleep for 9 s and return 1
#I'm the child 15365 and will sleep for 12 s and return 0
#15362->started 15363->started 15364->started 15365->started 
#I'm the child 15362 : 1, I'm awake
#15362->started 15363->started 15364->started 15365->started 
#15362->started 15363->started 15364->started 15365->started 
#I'm the child 15363 : 0, I'm awake
#15362->started 15363->started 15364->started 15365->started 
#I'm the child 15364 : 1, I'm awake
#15362->started 15363->started 15364->started 15365->started 
#15362->started 15363->started 15364->started 15365->started 
#I'm the child 15365 : 0, I'm awake
#15362->started 15363->started 15364->started 15365->started 
#15362->started 15363->started 15364->started 15365->started 
#15362->started 15363->started 15364->started 15365->started 
#15362->started 15363->started 15364->started 15365->started 
#^C15362->started 15363->started 15364->started 15365->started 
  • Comment on Is DBI trapping CHLD sigs, is there a workaround?

Replies are listed 'Best First'.
Re: Is DBI trapping CHLD sigs, is there a workaround?
by htoug (Deacon) on Aug 25, 2001 at 17:36 UTC
    All kinds of evil things may happen when you fork with an open database connection.

    What (if anything) happens depends on the database system, what you do to the connection after forking, ...

    I don't have the answer to what happens in your case

    The problem is that the database system is not prepared to have several process share the same connection - the purpose of the connection is to give a single channel of access, when that is shared evereything might break.

    Neither the DBI or the database systems are 'fork-safe'. The DBI is not really threadsafe yet. Most DBD-drivers are definitely not thread safe.

    So avoid forking when you have an active database connection.

      I don't want to do anything with the database connection in the child.

      The database connection is only used in the parent and I intended to keep a persistent connection in the parent so the parent could poll each database and fork a child when some (non db) actions should be taken.

      I have a work around, reassign all tasks among parent and child and let the child build and maintain it's db connection. It means a complete redesign and rewrite of the code...

      Tnx for the info.