IPC::Open3 call is causing blocking, script is locking up, please help...

Hello,

Will someone please help me...  I am totally stuck on this IPC::Open3 call thing, cause of blocking I believe.  My calls execute once through, but on the second attempt of the loop, the process hangs.  The results of waitpid are never returned...

      open (CATCHERR, "+>>error.txt")   || die $!;
      local *CATCHIN = IO::File->new_tmpfile;
      local *CATCHOUT = IO::File->new_tmpfile;

    my $pid = open3(">&CATCHIN",\*CATCHOUT, ">&CATCHERR", $cmd);

    waitpid ($pid, 0);
    if ($?) {
          print "That child exited with wait status of $?<br />\n";
      }

    while( <CATCHERR> ) { }

    while( <CATCHOUT> ) { }

      close (CATCHERR);
      close (CATCHOUT);
      close (CATCHIN);

      sleep(3);


I believe this has something to do with "blocking" which I've read about in perldoc, but don't know how to properly solve.  Can someone please explain what to do with my code so I can execute my command multiple times over and over again in loop with the program locking up on me?  How do I properly wait for it finish executing... getting a result code... without locking up the script?

Thanks in advance,
G
ghostingAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

ozoCommented:
could $cd be waiting for input on CATCHIN, or could it have filled the buffer on CATCHOUT and be waiting for someone to read it?
0
ghostingAuthor Commented:
I am not sure...

Let's try and approach both possibilities.  First how do I read CATCHOUT so that it is no longer full?  I am guessing this is more than likely the culprit, as the program I am executing can generate a fair amount of output quickly.

Secondly, if it is CATCHIN that is waiting for some sort of flush to say that the $cmd input is done, how do I send that?  I have but one lengthy command ($cmd) that I am trying to execute on multiple network hosts in a loop that I am running, so how do I tell CATCHIN that input is done, and to flush it's contents to CATCHOUT and CATCHERR?

This has really been beating me up for a couple of days now.  Any quick help is most appreciated.

Thanks in advance,
G
0
ozoCommented:
you can close(CATCHIN) to say that input is done, and
while( <CATCHOUT> ) { } to read CATCHOUT
but if you waitpid before doing any of that, you may be waiting for $pid while $pis is waiting for you
0
Cloud Class® Course: C++ 11 Fundamentals

This course will introduce you to C++ 11 and teach you about syntax fundamentals.

ghostingAuthor Commented:
OK,

I've tried modifying my code a bit, with closing CATCHIN and reading CATCHOUT and CATCHERR.  I am still having problems...  the code runs through the loop once, outputting everything CATCHERR finds the first time no problem, BUT on the second loop through, it stops / hangs about 5 lines into CATCHERR.

      local *CATCHIN = IO::File->new_tmpfile;
      local *CATCHOUT = IO::File->new_tmpfile;
      local *CATCHERR = IO::File->new_tmpfile;

    my $pid = open3(">&CATCHIN", ">&CATCHOUT", \*CATCHERR, $cmd);

       close (CATCHIN);

    while( <CATCHOUT> ) {
            push (@output, $_);
          print "CATCHOUT = ".$_."<br />\n";
    }

    while( <CATCHERR> ) {
            push (@lineresults, $_);
          print "CATCHERR = ".$_."<br />\n";
          }

    waitpid ($pid, 0);
    if ($?) {
          print "That child exited with wait status of $?<br />\n";
      }

      close (CATCHERR);
      close (CATCHOUT);

      sleep(3);


If you could please help me properly read / close CATCHERR such that I can read the results, and not have it hang on the 5th line of returned results on the second loop... I would be a very happy camper.  This is killing me, I have been stuck on this problem for days and must have it solved today.

Thanks in advance,
G
0
ozoCommented:
Could you give me an example of a $cmd that produces this problem?
I tried this example, and it worked for me

$cmd = qq(perl -le 'print while <>; for(1..10){ print STDERR; print;} exit +(localtime)[0]');
use IO::File;
use IPC::Open3;
for( 1..5 ){
local *CATCHIN = IO::File->new_tmpfile;
local *CATCHOUT = IO::File->new_tmpfile;
local *CATCHERR = IO::File->new_tmpfile;

my $pid = open3(">&CATCHIN", ">&CATCHOUT", \*CATCHERR, $cmd);

close (CATCHIN);

while( <CATCHOUT> ) {
    push (@output, $_);
    print "CATCHOUT = ".$_."<br />\n";
}

while( <CATCHERR> ) {
    push (@lineresults, $_);
    print "CATCHERR = ".$_."<br />\n";
}

waitpid ($pid, 0);
if ($?) {
    print "That child exited with wait status of $?<br />\n";
}

close (CATCHERR);
close (CATCHOUT);

sleep(3);
}
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
ghostingAuthor Commented:
Sure...

Although, the command I am using is a bit complex, and that might be part of the problem.  However, I have checked the command from a DOS prompt and it executes no problems.  So in order to get started, download PsExec from SysInternals @ http://www.microsoft.com/technet/sysinternals/utilities/psexec.mspx 

Once you've installed PsTools and added the PsTools directory to your system path, either at runtime or system wide, go ahead and try something along the lines of ....

$cmd = 'psexec \\\\remote_machine -u domain\\user_name -p password -n 45 -i -c -f "C:\\path_to_batch\\batch.bat"';

where batch.bat is a DOS batch file with something like

@echo off
copy \\host_machine\C$\path_to\md5sum.exe C:\
copy \\host_machine\C$\path_to\some_vbscript.vbs C:\
C:\some_vbscript.vbs
ping -n 3 127.0.0.1>nul
del D:\some_vbscript.vbs
del D:\md5sum.exe
exit

Basically the PsExec command will copy the DOS Batch file to the remote_machine, which will then execute the Batch file, copying over the needed VBScript and MD5sum files for my script, which get executed, then erased, and the program exits.  You can make the DOS Batch file do anything you want, but it should copy some files, execute them, then exit to be a fair test.

I have this all set up to run from a list of remote machines held in a file, changing the parameters for each target based on what I read in from my config files.  The program was working for a while until it got more complex and now it just hangs, rarely completing execution, which really sucks, considering this is a backup script designed for a large network.

I can't seem to figure out why it hangs, but any help on getting this run clean through without hanging would be most appreciated.  Thanks for taking the time to look into this with me.

Regards,
G
0
ghostingAuthor Commented:
OK,
I didn't acutal think anyone was going to try the example I posted, since it was more a bunch of pieces acting a one script.  I did get it working, as described in the example, but by changing psexec to not return a status code, but just a PID stating the process started.  

There is some sort of timeout error between waiting for psexec and stderr to connect and return on long execution times, more than a few seconds.  So that was my final solution that made everybody happy.

Thanks for all your input.
G
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Perl

From novice to tech pro — start learning today.