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

Is there a way to get a perl script to close all files handles and exit cleanly no matter what? Or to get it to spawn a process without passing any file handles or pointers to file handles to the child? So that the child process is completely free from the parent script that called it? Because exec($cmd), system(1,$cmd) Win32::Process::Create() don't work.

I am on windows server 2003. I have a bat file that is used at start up to run a java applet that sits on the machine and monitors a file for changes.

Lets say that StartJava.bat calls the command :

start /min d\java\jdk\1.4\bin\java -classpath d:\java\Thingy.jar Thingy d:\Thingything.dat

And Thingy.jar sits open in a command prompt and monitors a file.

I decided that it would be handy to have this java app started by a perl script instead of a bat file, so I could add some functionality to the startup script as well as better error handling. So now I have:

perl StartJava.pl

It works, and the app runs fine, however, when I start the java applet with perl the perl script gets locked and cannot be changed until the java applet is closed.

The thing is that when I run the bat file to start the java applet I can make changes to the bat file that started it.

This happens even if I Have StartJave.pl call the orriginal StarJava.bat which in turn calls the jar file and the StartJava.bat file closes.

Seems like perl still realizes that somewhere down the line the java app is still running. And won't let me rename or change StartJava.pl. Even though the perl process and the cmd prompt which started it have both closed.

I read some docs on perl process creation that perl passes pointers or some such to child processes back to the parents STDERR and STDOUT

I have tries several things to get perl to let go, but nothing works.

I tried using exec (StartJava.bat), I tried system(1, $cmd) I tried Win32::Process::Create()

Any ideas?

Replies are listed 'Best First'.
Re: Perl file handles
by ikegami (Patriarch) on Mar 06, 2009 at 18:32 UTC

    Is there a way to get a perl script to close all files handles and exit cleanly no matter what?

    exit

    Seems like perl still realizes that somewhere down the line the java app is still running. And won't let me rename or change StartJava.pl.

    Perl has an open file handle to the script if the script contains a __DATA__ or __END__.

    While Perl gives up it's shared and exclusive lock on the file (allowing the file to be read and written by others), it doesn't give up the delete lock on the file (preventing others from deleting or renaming the file).

    The solution is simple. As Corion told you in the CB, simply do close(DATA);

    #!perl -l system qq{del "$0" >nul 2>&1}; print(-e $0 ? "not deleted" : "deleted"); close(DATA); system qq{del "$0" >nul 2>&1}; print(-e $0 ? "not deleted" : "deleted"); __DATA__
    not deleted deleted

    Even though the perl process and the cmd prompt which started it have both closed.

    That's not possible. A process automatically relinquishes its file handles and file locks when it exits. Something else must have a lock on the file if Perl isn't running.

    Update: Added code.

      I appreciate the response, and I guess I did not catch the mention of using close(DATA). All CB showed me was "All is quiet".

      That being said, the above code and it doesn't work.

      I use :

      system qq{$Command "$0" >nul 2>&1};

      close(DATA);

      Same as usual. File cannot be deleted or renamed.

        Wrong order. Closing DATA after the child has finished running will have little effect on the child.
Re: Perl file handles
by Marshall (Canon) on Mar 06, 2009 at 21:25 UTC
    I think that Win32::Process::Create() with the proper parms will work. Of course your mileage may vary..

    But here is rule of thumb to start a "detached process" perl program from another perl program (I use this to start GUI programs without the command window, eg no STDIN, no STDOUT). A key buzz word here is DETACHED_PROCESS. You will have to modify this to get Perl to start a Java app, but this is an idea to work from (or so I hope).

    #!/usr/bin/perl -w use strict; use Win32; use Win32::Process; Win32::Process::Create($Win32::Process::Create::ProcessObj, 'C:/perl/bin/perl.exe', 'perl SOMEPROGRAM', '0', #don't inherit file handles DETACHED_PROCESS, ".") #CURRENT DIR or die "some message";