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

It's said, that

The open2() and open3() functions are unlikely to work anywhere except on a Unix system, or at least one purporting POSIX compliance.

There are, however, examples of the opposite, i.e. open2 can work on Windows.

I want my Perl script to dynamically create Postscript code, invoke the Ghostscript, feed it, collect the output for further tasks. Without any IPC:

use strict; use warnings; my $in_fn = 'in.ps'; my $out_fn = 'out.pdf'; open my $fh, '>', $in_fn; print $fh <<'END'; %!PS % % skipped % showpage END close $fh; system 'gswin32c', '-q', '-sDEVICE=pdfwrite', '-o', $out_fn, $in_fn; # now do something useful with out.pdf

Ghostscript can use pipes, therefore I thought about more efficient implementation. Below, for simplicity, GS doesn't produce any output except error messages. E.g., using IPC::Run3:

use strict; use warnings; use IPC::Run3; run3 [ 'gswin32c', '-q', '-sDEVICE=nullpage', '-' ], \ 'syntax error!', \ my $out, \ my $err, { binmode_stdin => 1, binmode_stdout => 1, }; print "*** STDOUT ***\n$out\n"; print "*** STDERR ***\n$err\n";

It works, but module's documentation says about nearly always creating temporary files. Therefore it's all nothing but syntactic sugar compared to no-IPC solution above.

The IPC::Open2, however, won't work, it just hangs indefinitely (and so does GS process):

use strict; use warnings; use IPC::Open2; my ( $in, $out, ); my $pid = open2 $out, $in, 'gswin32c -q -sDEVICE=nullpage -'; $in-> autoflush( 1 ); print $in "syntax error!\n\cZ\n"; close $in; print do { local $/; <$out> }; close $out; waitpid( $pid, 0 );

Autoflushing, and ctrl-Z were my futile attempts to make it work.

I understand, efficiency gain of in-memory buffers vs disk-IO can be negligible. But, if not for this case, but for the future -- are there clear advice about when IPC::Open\d will work on Windows, and when not to waste time trying?

Replies are listed 'Best First'.
Re: When does IPC::Open\d work on Windows, and when doesn't?
by BrowserUk (Patriarch) on Apr 01, 2017 at 13:35 UTC

    The basic problem with IPC::Open3, is that if the output buffer on either of the output handles of the slave process, fills, the slave process will block pending the master reading some data from its end of that pipe so that the buffer is no longer full.

    But if the controlling process is currently in a blocking read on the other pipe waiting for input, the slave process won't produce any more output to that pipe, until the other pipe has been read; which it never will.

    On *nix, the programmer using IPC:Open3 can set the two pipe handles non-blocking and use select to only read from pipes when they have something ready to be read.

    But Windows implementation of pipes does not support non-blocking pipes (it provides equivalent but incompatible, functionality through NamedPipeRead())

    Hence, IPC::Open3 (and most of the attempted substitutes) are always unreliable on Windows.

    The simplest potential work around I am aware of would be to extend Win32::Socketpair to include a winopen3() function in addition to the winopen2() and winopen2_5() functions it already contains. That module (originally by salva) dups the pipe handles to socket handles, which can be set non-blocking and used with select.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". The enemy of (IT) success is complexity.
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: When does IPC::Open\d work on Windows, and when doesn't?
by haukex (Archbishop) on Apr 01, 2017 at 12:05 UTC

    Unfortunately I don't have a Windows machine handy at the moment, so I can't answer your question directly. The IPC::Run3 docs do say this:

    For each redirector $stdin, $stdout, and $stderr, run3() furnishes a filehandle: if the redirector already specifies a filehandle it just uses that

    Running the following test on Linux with strace appears to show this is true even for Perl's in-memory filehandles:

    use warnings; use strict; use IPC::Run3 'run3'; my $in = "Foo\nBar\n"; my $out = ""; # This uses temp files: #run3 ['/bin/cat'], \$in, \$out or die "run3"; open my $infh, '<', \$in or die $!; open my $outfh, '>', \$out or die $!; run3 ['/bin/cat'], $infh, $outfh or die "run3"; $?==0 or die "$?";

    If that doesn't work, you might also want to give IPC::Run a try.

    AFAIK many IPC modules have similar issues on Windows, I think that's part of the reason why IPC::Run3 uses temporary files often - it's more reliable (just compare the CPAN Testers Matrix of IPC::Run3 with any other IPC module).

    BTW, you're worried about efficiency, but haven't said what kind of a load you're expecting - are you sure this isn't premature optimization?

      With Perl's in-memory filehandles I get "run3(): Bad file descriptor redirecting STDIN at ...". With IPC::Run and, again, with Perl's in-memory filehandles, script just dies without giving any reason "at C:/PDL24/perl/vendor/lib/IPC/Run.pm line 1852." With references to scalars, IPC::Run works, it seems, just like IPC::Run3.

      The IPC::Run documentation is a bit overwhelming, I'll browse through it, at leisure :)

      As to "premature optimization" - of course, the solution with IPC::Run3 and temp files will work fine. It's not that something is broken and I'm desperate and asking someone to do a research for me. I just thought maybe there already is (and has been for a long time) some FAQ list with nicely enumerated items, etc. :) Thank you for answer.