Beefy Boxes and Bandwidth Generously Provided by pair Networks Frank
Syntactic Confectionery Delight
 
PerlMonks  

SIG{INT} not handling CTRL-C ???

by girishatreya2005 (Novice)
on Jul 12, 2010 at 13:22 UTC ( #849012=perlquestion: print w/ replies, xml ) Need Help??
girishatreya2005 has asked for the wisdom of the Perl Monks concerning the following question:

Hi wise ones, I've defined a routine in my script to handle the SIGINT signal .
main(); sub main () { $SIG{'INT'} = 'exit_handler'; for ( my $count = 1 ; $count <= 3 ; $count ++ ) { child_fork(); } } sub exit_handler () { print " I caught CTRL-C \n"; ### Do cleanup . kill the children $SIG{'INT'} = 'DEFAULT'; exit; } sub child_fork() { my $child_pid ; $child_pid = fork(); if( $child_pid > 0) { print "returning to parent\n"; }else { my $count = 0 ; while ($count <= 60) { print "In child now "; sleep 1; $count=$count+1; } print "returning to parent now \n"; exit; } }

I fork some children from the parent. And when the children are running , I send the SIGINT signal to the parent by pressing CTRL-C on the terminal. But the parent is not handling the SIGINT signal.

If no children are forked, the parent catches the SIGINT signal without any issues and exits.

Any pointers on what I am missing will be really helpful .

Thanks, Girish HV

Comment on SIG{INT} not handling CTRL-C ???
Download Code
Re: SIG{INT} not handling CTRL-C ???
by mje (Deacon) on Jul 12, 2010 at 13:27 UTC

    Shouldn't $SIG{INT} be set to a subroutine reference not a string.

      perlipc recommends it, but it is not required.
Re: SIG{INT} not handling CTRL-C ???
by Neighbour (Friar) on Jul 12, 2010 at 13:37 UTC
    This code doesn't seem to do what you'd expect it to do...At least, it doesn't hang around and wait for your CTRL-C. The only thing it does is spawn 3 children right away and then exiting. This is done quite quickly and I'm guessing any CTRL-C's you do press afterwards are just sent to whatever shell you're executing the code from.
    If you add a sleep 300; after your child_fork();-call, you'll have more time to see that the CTRL-C is indeed handled the way you wanted.

      @Neighbour

      Thank you very much.

      Active waiting in the main did the trick.

        No, just sleeping won't do the trick. It will bite you again as soon as one of your forked processes needs longer than that. And it will waste resources and your time if all of your forked processes are faster than the delay.

        Use the proper way: Remember the PIDs of the forked processes, and wait() for all of your forked processes. End your main process when you have waited for all processes.

        Stupid example:

        #!/usr/bin/perl use 5.010; use strict; use warnings; $|=1; # autoflush my %pids; for (1..10) { my $pid=fork() // die "Can't fork: $!"; if ($pid) { # parent, remember PID $pids{$pid}++; say "Forked child $_, PID=$pid"; } else { # child say "Child process $_"; sleep (5+rand(5)); exit 0; } } while (%pids) { my $pid=wait(); delete $pids{$pid}; say "child with PID $pid exited"; } say "all childs exited";

        If you want to do some work in your parent process, rely on SIGCHLD instead. SIGCHLD will be sent to your parent process as soon as a child process exits.

        Stupid example:

        #!/usr/bin/perl use 5.010; use strict; use warnings; use POSIX ":sys_wait_h"; $|=1; # autoflush my %pids; sub reaper { $SIG{CHLD}=\&reaper; # This does not work, because you may get only one signal when # two or more processes exit at nearly the same time. This is due # to the way signals are implemented. #my $pid=wait(); #delete $pids{$pid}; my $pid; do { $pid=waitpid(-1, WNOHANG); delete $pids{$pid}; } while $pid>0; } $SIG{CHLD}=\&reaper; for (1..10) { my $pid=fork() // die "Can't fork: $!"; if ($pid) { # parent, remember PID $pids{$pid}++; say "Forked child $_, PID=$pid"; } else { # child $SIG{CHLD}='DEFAULT'; # maybe not needed, but doesn't hurt say "Child process $_"; sleep (5+rand(5)); exit 0; } } while (keys %pids) { say "Parent is working, ",scalar keys %pids," children still alive + (PIDS ",join(', ',keys %pids),")..."; sleep 1; } say "all childs exited";

        Note that you should keep the signal handler routine as short as possible, and that you should avoid any I/O there. Just set or clear a flag and return as fast as possible. With modern Perl implementations, you usually have "safe signals" that allow to do more in a signal handler, but you can disable them for speed or other special purposes. And in older Perl implementations, unsafe signals are standard and WILL bite you very fast.

        And now, propagating SIGINT:

        You know the PIDs of all of your child processes, because you need them for wait()/waitpid(). So it is no problem to use it to send SIGINT to your child processes:

        #!/usr/bin/perl use 5.010; use strict; use warnings; use POSIX ":sys_wait_h"; $|=1; # autoflush my %pids; sub reaper { $SIG{CHLD}=\&reaper; # This does not work, because you may get only one signal when # two or more processes exit at nearly the same time. This is due # to the way signals are implemented. #my $pid=wait(); #delete $pids{$pid}; my $pid; do { $pid=waitpid(-1, WNOHANG); delete $pids{$pid}; } while $pid>0; } $SIG{CHLD}=\&reaper; sub sigint { $SIG{INT}=\&sigint; kill INT => keys %pids; } $SIG{INT}=\&sigint; for (1..10) { my $pid=fork() // die "Can't fork: $!"; if ($pid) { # parent, remember PID $pids{$pid}++; say "Forked child $_, PID=$pid"; } else { # child $SIG{CHLD}='DEFAULT'; # maybe not needed, but doesn't hurt $SIG{INT}='DEFAULT'; say "Child process $_"; sleep (5+rand(5)); exit 0; } } while (keys %pids) { say "Parent is working, ",scalar keys %pids," children still alive + (PIDS ",join(', ',keys %pids),")..."; sleep 1; } say "all childs exited";

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://849012]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (16)
As of 2014-04-17 19:53 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    April first is:







    Results (454 votes), past polls