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

It happens in this piece of code right here
...bunch of not-interesting settings... local $SIG{INT} = sub { print "| NEXT!\n|\n"; }; foreach $track (@playlist) { print "| Track: $track\n"; open (PIPE, "ssh $machine \"cat $soundroot/$track\" | mpg123 - | "); } print "+--- All done! ---\n\n";
Sinister Greetings

Replies are listed 'Best First'.
Re: My pipe gets the SIGINT. And I dont want that...
by merlyn (Sage) on Apr 26, 2001 at 21:09 UTC
    Launch the ssh in your own forked process:
    foreach $track (@playlist) { print "| Track: $track\n"; unless (open PIPE, "-|") { # I'm the kid $SIG{INT} = 'IGNORE'; exec "ssh $machine \"cat $soundroot/$track\" | mpg123 -"; die "Cannot exec ssh: $!"; } # rest of your loop goes here }

    -- Randal L. Schwartz, Perl hacker

      The whole as you requested... (this is off the top of my head and untested, cause the code dwell's @ work - workstation and I am now at home)
      #!/usr/bin/perl ($machine, $soundroot, $pattern) = @ARGV; open(PIPE, "ssh $machine \"find $soundroot -type f | grep '$pattern' \ +" 2&>1 | "); while(<PIPE>) { chomp; s/$soundroot//g; push @rawlist, $_; } @playlist = sort { $a <> $b || $a cmp $b } @rawlist; close(PIPE); foreach $track (@playlist) { print "playing $track\n"; $DoNotExit = 1; while($DoNotExit) { open(PIPE, "ssh $machine \"cat $soundroot/$track \" | mpg123 - | " +) unless <PIPE>; undef $DoNotExit unless <PIPE>; } close(PIPE); }

      this was my code originally. Now i wanted to use ctrl-c as a 'skip-button'. it doesn't work, cause when I do ctrl-c in this case everything ends...
      Any suggestions?

      Sinister greetings.
        This is gonna require some fork games and some fun signal handling. I should publish the standard warnings that perl's signal handling leaves a lot to be desired and do not blame me if this causes all your hair to fall out and sets your workstation on fire :)

        Basically, what I am going to do is to spawn the PIPE process off as a child process. The parent process will watch for two signals: SIGINT will cause the parent to kill the child off and SIGHUP will cause the parent to kill the child and then itself. To avoid perl's signal problems, I am keeping the handlers very, very simple - they each set a variable and let the main loop handle it. There are still race conditions in the code, which may or may not be able to be fixed.

        Also, not to put too much of a point on it, I am not using a SIGCHLD handler. I use waitpid and reap the children myself.

        I am also gonna do this a bit of pseudo-code here - I am currently too lazy to cut'n'paste :)

        sub spawn { my ( $interesting, $vars, $here ) = @_; my $pid = 0; # The parent process returns the spawned process's pid. # The spawned process does the work if ( $pid = fork ) { return $pid; } else { # do lots of interesting things # Either exit or exec - just make sure the kid # never returns. exit 0; } } my $stop_all = 0; my $stop_kid = 0; my $kid_pid = 0; # Trying to minimize my risk here, I simply set a variable # and let the later code handle it. It isn't perfect, # but it works. # SIGINT stops the kid. SIGHUP stops everything $SIG{SIGHUP} = sub { $stop_all = 1; } $SIG{INT} = sub { $stop_kid = 1; } # This loops forever. You may not want that :) The 5 second sleep # also keeps you from eating too many CPU cycles. Note it # will also mean a maximum 5 second delay between sending the # SIGINT or SIGHUP and anything happening. If that is not # acceptable, use select(undef,undef,undef,0.5) while( 1 ) { sleep 5; if ( $stop_all ) { kill 9, $kid_pid if ( $kid_pid && $kid_pid != -1 ); exit; } # Race conditions ahead! Don't lean too heavily on the # CTRL-C key if ( $stop_kid ) { kill 9, $kid_pid if ( $kid_pid > 0 ); $stop_kid = 0; } # I am a bad man and do not use POSIX. The 1 may # change depending on the OS - this works for # Solaris and FreeBSD my $dpid = waitpid( -1, 1 ); $kid_pid = spawn() if ( $dpid == $kid_pid || $dpid = -1 ); }
        This is untested, but there is also a lot of code to be found on perlmonks dealing with forking and reaping child processes. I have a very extensive example playing games like this but do not have the source code immediately available. I will check when I get home and make sure this example is mostly correct.

        Mik mikfire

    A reply falls below the community's threshold of quality. You may see it by logging in.
    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: My pipe gets the SIGINT. And I dont want that...
by Jouke (Curate) on Apr 26, 2001 at 22:14 UTC
    I'm not completely sure, but I think the 'local' in your script is the problem. I tried the following piece of testcode to create a 'ctrl-c' handler, and it works fine. That means to me that whatever you want to do inside your ctrl-c handler must be possible by modifying my code:
    #!/usr/bin/perl -w use strict; $|=1; my $i=0; $SIG{INT} = sub { print $i++ if $i < 10; die if $i == 10}; while (1) { sleep (5) }
    By pressing ctrl-c it prints out 1 to 9 and the last time it dies..

    Jouke Visser, Perl 'Adept'