in reply to Re: waitpid stalling on one particular file
in thread waitpid stalling on one particular file

I did an strace -f on the command, and here's the end of the output (path edited out):

[pid 24623] stat("/path/65.db.psq", {st_mode=S_IFREG|0666, st_size=811 +5, ...}) = 0 [pid 24623] open("/path/65.db.psq", O_RDONLY) = 6 [pid 24623] mmap(NULL, 8115, PROT_READ, MAP_PRIVATE, 6, 0) = 0x7f78165 +73000 [pid 24623] write(1, "AT5G51490.1.CDS\tAT4G00190.1\t46.0"..., 1340) = +1340 [pid 24623] write(1, "AT2G26450.1.CDS\tAT1G53830.1\t40.5"..., 1615) = +1615 [pid 24623] write(1, "AT1G11580.1.CDS\tAT3G14310.1\t50.1"..., 1286) = +1286 [pid 24623] write(1, "AT2G45220.1.CDS\tAT4G00190.1\t52.6"..., 1279) = +1279 [pid 24623] write(1, "AT3G14310.1.CDS\tAT3G14310.1\t100."..., 1270) = +1270 [pid 24623] write(1, "AT5G55590.1.CDS\tAT5G55590.1\t100."..., 1452 <un +finished ...>

I guess this isn't a perl question, but it doesn't make sense to me that writing to a file would freeze.

Replies are listed 'Best First'.
Re^3: waitpid stalling on one particular file
by salva (Canon) on Sep 25, 2014 at 16:16 UTC
    It freezes because file descriptor 1 (stdout) is attached to a pipe and nobody is reading from the other side.

    Why are you using open3 to launch the process?

      Oh, I hadn't thought of that, my slightly extended code was:

      $pid=open3($wtr, '>&reader', $err, $cmd); waitpid($pid, 0); my %Results=(); while(<$rdr>){ chomp; @temp=split(/\t/); if(!exists($Results{$temp[0]}) || $Results{$temp[0]}<$temp[10] +){ $Results{$temp[0]}=$temp[10]; } }

      So I take it that I should've used waitpid after I finished "reading" the pipe. Duh(!) Moving waitpid til after <$rdr> worked. Upon reflection, I realized that the output from running this particular file was far larger than any other, and was thus the first to fill the I/O buffer.

      In related news, I gave myself a crash course in buffering and also tried using IPC::Run() with pty, and worked too, but which is recommended?

        but which is recommended?

        Well, it depends...

        IPC::Open3 is an old module with an ugly interface and limited functionality. On the other hand you can rely on it being available mostly everywhere as it is distributed with Perl.

        IPC::Run is a feature rich module and quite popular too. I find its API too complex, but that is probably the prize you pay for being feature rich!.

        There is another alternative if you don't need your scripts to run on any OS other than Linux or Unix: to use the raw POSIX calls (fork, exec, dup2, etc.). In other words, doing it a-la 'C'.

        In your particular case, where you are not sending any data to the child process, there is an even simpler solution: to use a single pipe. Perl provides native support for that via the open built-in:

        my $pid = open my $rdr, "$cmd |" or die "unable to run external comman +d: $!"; while (<$rdr>) { ... } close $rdr or die "reading from $rdr failed: $!";

        Or even better, in order to avoid the shell (specially if it is the today infamous bash!), using the multi-argument open invocation:

        my $pid = open my $rdr, '-|', $cmd, @args or die "unable to run extern +al command: $!"; while (<$rdr>) { ... } close $rdr or die "reading from $rdr failed: $!";