perl & IPC

From
Andrew Degtiariov ()
To
All ()
Date
2003-06-06T13:56:04Z
Area
RU.UNIX.PROG
From: Andrew Degtiariov <ad@astral-on.net>

Обьясните, пожалуйста, где я жестоко лопухнулся. Почему нижеприведеный
скрипт работает так странно (в скрипте 4 раза вызывается /bin/ls):
ad@ad:/usr/home/ad>perl test.pl |wc -w
   18939
ad@ad:/usr/home/ad>ls | wc -w
     107
ad@ad:/usr/home/ad>

18939/107=177; Отчего такое происходит? Иногда запуск приводит к
спонтанному ребуту станции (естественно, запуск не из под root'а)

Скрипт:
------- cut ------
#!/usr/bin/perl


use POSIX qw(:sys_wait_h);

$kids_limit = 2;
$kids = {};

write_to_separate_procces(undef, "/bin/ls");
write_to_separate_procces(undef, "/bin/ls");
write_to_separate_procces(undef, "/bin/ls");
write_to_separate_procces(undef, "/bin/ls");

sub write_to_separate_procces($$) {
    my $data_ref    = $_[0];
    my $program     = $_[1];

    if ($kids_limit <= scalar(keys %$kids)) {
        $pid = wait;
        delete $$kids{$pid};
    }
    
    local $SIG{CHLD} = sub { 
                             while(1) {
                                $pid = waitpid( -1, WNOHANG );
                                next if $pid == -1 && $! == EINTR();
                                last if $pid <= 0;
                                delete $$kids{$pid};
                                last;
                             }
                           };
    if ($pid = fork) {
        # parent
        $$kids{$pid} = 0;
        return;
    } 
    
    pipe(README, WRITEME);
    if ($pid = fork) {
        # parent
        close(WRITEME);
    } else {
        die "cannot fork: $!" unless defined $pid;
        close(README);
        #close  STDOUT ; close STDIN;
        
        # child
        $pid = open (TO_COMMAND, "|-");
        
        if ($pid) { close WRITEME; exit; } # parent
         
        $pid = open (FROM_COMMAND, "-|");
        if ($pid) { # parent
            while ($str = <FROM_COMMAND>) { print WRITEME $str; }
            close WRITEME; exit;
        }
        close WRITEME; # kid
        if (defined($data_ref)) {
            exec($program) or die "Couldn't run $program : $!\n";
            exit;
        }
        
        # else
        unless (open TO_COMMAND, "|$program") {
            die "Couldn't run $program : $!\n";
        }
        
        unless (ref $data_ref) { print TO_COMMAND $data_ref; } # scalar
        elsif (ref $data_ref eq 'SCALAR') { print TO_COMMAND $$data_ref; } 
        elsif (ref $data_ref eq 'ARRAY') {
            foreach $str (@$data_ref) { print TO_COMMAND $str; }
        }
        close TO_COMMAND;
        exit;
    }

    while (<README>) { $string .= $_; }
    close(README);

    print $string;
}

- --- end cut ---

-- 
Andrew Degtiariov 
AD5898-RIPE
--- ifmail v.2.15dev5
 * Origin: Astral-Kiev (2:5020/400)