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

Hi, This code is pretty much from perlipc, but doesn't seem to work. What's wrong? Thanks.
use strict; my $pid = fork(); if ($pid) { print "I am parent $$\n"; kill INT => $pid; print "I am parent $$\n"; } elsif (defined($pid)) { print "I am child $$\n"; local $SIG{INT} = sub { die "\nOutta here!\n" }; print "I am child $$\n"; exit 1; } else { print "child was not created\n"; }

Replies are listed 'Best First'.
•Re: Catching signals
by merlyn (Sage) on Sep 04, 2002 at 17:56 UTC
    use strict; my $pid = fork(); if ($pid) { print "I am parent $$\n"; kill INT => $pid; print "I am parent $$\n"; } elsif (defined($pid)) { print "I am child $$\n"; local $SIG{INT} = sub { die "\nOutta here!\n" }; print "I am child $$\n"; exit 1; } else { print "child was not created\n"; }
    The child isn't hanging around much. I wouldn't be surprised if you never got the "Outta here" message.

    You'll want the child to block. Add sleep 30 or something, after setting up the $SIG{INT}.

    -- Randal L. Schwartz, Perl hacker

      As I have replied to RMGir, i have tried making those corrections already and they don't seem to work. To clarify, here's the adapted code. I still don't see the handler message.
      use strict; use sigtrap 'handler' => \&myhand, 'INT'; sub myhand{ print "\nOutta here $$!\n" }; my $pid = fork(); if ($pid) { print "I am parent $$\n"; for (1 .. 1000000){} kill INT => $pid; print "I am parent $$\n"; } elsif (defined($pid)) { print "I am child $$\n"; while (1){ sleep 1; } } else { print "child was not created\n"; } wait(); print "hi\n";
        Ahh. That code works as expected for me. The signal handler is called in both the parent and the child. I had to use a ^Z to finally get out of the code.

        So, what's your perl -V look like?

        -- Randal L. Schwartz, Perl hacker

Re: Catching signals
by RMGir (Prior) on Sep 04, 2002 at 17:30 UTC
    You're not doing anything to synchronize your parent and child processes, so there's no guarantees which one will execute the if first.

    It's possible you send that signal to the child before the local $SIG{INT} is executed, for instance.

    Try setting $SIG{INT} before the fork, and see what happens. Don't forget to add $$ to what the die prints out, though.

    I'd test it myself, but signal handling in perl on cygwin has a horrible tendency to hang my whole NT system...
    --
    Mike

      putting the $SIG{INT} in front of the fork() did not do anything. I even put in a for (1 .. 1000000){} loop just in front of the kill command, to give the child some time to process, but even at that, no signal is detected.
        Try putting the signal handler before the fork() and adding a sleep(1) to the child (between the two prints) so it doesn't finish before it receives the signal.

        A big ol' for loop is no substitute for a nice little sleep statement.

        -sauoq
        "My two cents aren't worth a dime.";
        
        Hmmm, what platform/perl version are you trying this on?

        I'm guessing your perl or your os may not like signals...
        --
        Mike

Re: Catching signals
by sauoq (Abbot) on Sep 04, 2002 at 18:03 UTC

    The signal never has a chance to be caught as you exit the child right after setting the signal handler and printing your second "I am child" line.

    Turn that exit into a sleep(10) and put a sleep(5) before the kill in the parent's block. Making the parent sleep will ensure that the child process has time to set the signal handler before the parent tries to kill it.

    Update: Yeah, what merlyn said. Except, do make the parent sleep briefly as well, for the reason I gave above.

    -sauoq
    "My two cents aren't worth a dime.";