PerlIpcOpen2

Perl IPC::Open2
(a.k.a. filehandle/STDIN/STDOUT/STDERR weirdness)

Introduction

The Perl Standard Library IPC::Open2 (and it's counterpart Open3) are functions much like the built-in function, open(), except that give simultaneous access to the STDIN, STDOUT and with open3(), STDERR of the process being opened. The Open3() variant will require your program to have a select() on the three filehandles, followed by suitable handling depending on what you get. Open2() allows for simpler programming, as you can achieve something like:

$pid=Open2(\*PROC_STDOUT,\*PROC_STDIN,"/path/to/binary");

    print [[PROC_STDIN]] &quot;do something\n&quot;;<br />
    $ret=&lt;PROC_STDOUT&gt;;<br />
    print &quot;Got $ret back from binary\n&quot;;7

...and so perform reasonably sequential operations in your code. The well documented caveat is Unix buffering is likely to mess you up. Most Unix binaries aren't designed to be operated from Pipes, so don't work very well with Open2(). If you control the source code to the binary however, you can arrange that for each line of input, you output exactly one line (and ensure that input/output buffering is switched off).

Problems

Update: Use Proc::Daemon (from CPAN) to daemonise your process - it (correctly) opens /dev/null for filehandles 0,1 and 2.

There is another (seemingly undocumented) problem with Open2() (and possibly other functions). It's in a fairly obscure case when you're trying to daemonise your Perl program.

Usually, when becoming a daemon, you would perform a fork(), lose the process group, the controlling TTY, perform another fork() and close all your filehandles (here's an example bit of Perl). The trouble comes in when that (now daemonised) process tries to Open2() another process. For some reason (and I haven't fully worked this out), the other process misunderstands the filehandles it opens.

In my application, the daemon runs an indexing process. The indexer's job is to read it's config, then read a filename from STDIN, process it and return results on how it got on (to it's STDOUT). This all works fine, except if started by a daemon. Having played about with &quot;strace&quot; (&quot;truss&quot;, if you're a Solaris user), I found that the index process would start-up (loading libraries and the like), then open it's config file. The system allocates it filehandle 0 for this, which it subsequently seems to use as it's STDIN. As a result, the strace shows the indexer trying to stat() each line of the config file. These obviously fail, and eventually, the indexer runs out of config, so closes down. The only notice my daemon gets of this is when it tries to write to the pipe to the indexer which fails with a &quot;Broken Pipe&quot; error (which is what you'd expect, since the Indexer has quit).

It is possible that my indexer process is at fault here. However, the indexer's &quot;confusion&quot; about what is STDIN and what is a filehandle is a bit of a worry. I have worked around the problem by splitting the daemonise code in half. daemonise() does everything except close STDIN, STDOUT and STDERR. It then starts the indexer process, and then closes STDIN, STDOUT and STDERR. It's at that point that the process becomes genuinely daemonised and runs nicely in the background.

Another workaround is to write a wrapper around your daemon process. First, remove the daemonise code from the daemon, and move it to the wrapper. Now, the wrapper starts up, half-daemonises, starts your program via an ordinary open() call, closes STDIN, STDOUT and STDERR and then just loops reading from your program. This also seems to work, but requires a second process.

Submitted by coofercat on Sun, 2005-01-02 14:57