in reply to Shared file-handles & fork fun

You seem to be mixing concepts.

First, read open again. If you use a piped open, it will return the PID of the child process:

my $pid = open my $fh, "| $some_program" or die "Can't run '$some_program': $!\n";

Second, you will only need IPC::Open2 to write and read to/from the child process, but in your script I don't see you're attempting to read. open2 will also return a PID, and it will handle all that fork stuff and plumbing the pipes for you, so you don't need to fork.

Third: if you open a filehandle in the child after forking, it is visible in the child only. If you open it before forking, the file will be open in both parent and child:

#!/usr/bin/perl -w use strict; open(O,'>', "$$.tmp"); select O; $| = 1; # make output unbuffered print STDOUT "file is $$.tmp\n"; $SIG{'CHLD'} = \&reap; if ( (my $pid = fork()) == 0 ) { sleep 1; print "child ($$) here\n"; close O; exit 0; } else { print "parent ($$) here\n"; sleep 2; print "parent ($$) waking up..\n"; } sub reap { my $pid = wait; print "reaped PID $pid\n"; } __END__ file is 4782.tmp
$ cat 4782.tmp parent (4782) here child (4783) here reaped PID 4783 parent (4782) waking up..

Note that you must set $| = 1 for your filehandle to make output unbuffered if you want to keep the output of parent and child in order. Or better use IO::File and set autoflush FH 1.

--shmem

_($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                              /\_¯/(q    /
----------------------------  \__(m.====·.(_("always off the crowd"))."·
");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}

Replies are listed 'Best First'.
Re^2: Shared file-handles & fork fun
by kabeldag (Hermit) on Nov 22, 2006 at 21:16 UTC
    I don't need to read from the process, just write to it. I know open2() returns PID. I am specifically using open2() because it returns a PID and I am able to write to the process. But maybe I can do that like you said.

    I know I can open the handle globally (ie; before I fork), but I couldn't figure out how to work it into the code I wrote so that the flow works out to how it should.

    Thing is, I need to be able to write to the binary process, whilst also checking to see if it exists, if it doesn't, I need to restart it.

    If the binary process terminates for some reason, it must be restarted. But if I want to actually end the binary process, I need to kill off the parent(s). I couldn't see that this would work with what I had done unless I just send it a catchable SIGNAL. Of course if one were to send a SIGKILL signal to the parent, it wouldn't be catchable. Sure it will terminate it, but the binary process would still remain.

    I will try some stuff and re-post it.

    And here is a solution :

    ------------------------------------
    use POSIX ":sys_wait_h"; # Didn't do this before. my $spid; print "Launching \"$actual_prog\" as UID($uid)/GID($gid)\n"; unless (my $pid=fork()) { # Re-direct $program's STDERR to a file on the hard disk open(STDERR,">> $logfile"); $spid = open2(*SREAD, *SWRITE, "$program @prog_options"); while(1) { if($got_sig==1) { print STDOUT "GOT SIGNAL on $0\n"; print SWRITE "Hey there server process\n"; sleep 0.5; kill('KILL',$spid); exit(0); }else{ my $der = waitpid($spid,WNOHANG); # If return val < 0. It ended ... if($der==-1) { print STDOUT "Time to re-launch\n"; open(STDERR,">> $logfile"); $spid = open2(*SREAD, *SWRITE, "$program @prog +_options"); } } } }
    ------------------------------------

    Obviously I am only using one Perl process to manage the spawned binary process now. I also specifically included sys_wait_h : use POSIX ":sys_wait_h";, which I hadn't done before. Now the following works fine :
    my $der = waitpid($spid,WNOHANG); if($der==-1) { print STDOUT "Time to re-launch\n"; open(STDERR,">> $logfile"); $spid = open2(*SREAD, *SWRITE, "$program @prog +_options"); }
    and I can do other stuff whilst the child process state hasn't changed (ie; actually non-blocking waitpid()).

    This works fine for me. But I liked my other code. Oh well. Whatever works. I should probably re-read over waitpid() and how Perl implements it.