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

Hi, I would like to use one perl script to start a processes at a background using Win32:Process and another script to check if the background processes are still running, eventually with what exit code had the process finished. But I do not know whether there is an apparatus in perl to build something like this. My idea was "somehow" to save reference to an object I get by Win32::Process::Create and later use this reference in another script. My question might be pretty naive but I want to ask anyway :-) Thanks Tomas
  • Comment on Use another script to check bacground process

Replies are listed 'Best First'.
Re: Use another script to check bacground process
by cdarke (Prior) on Dec 27, 2010 at 09:55 UTC
    Win32 handles can be passed between processes in a number of ways. The easiest is to make sure the handle is inheritable. The second process should be a child of the first, and make sure InheritHandles is set to TRUE. The handle itself can be passed on the command-line.

    The second method is using the Win32 API DuplicateHandle, which can pass handles between unrelated processes. Although the API for DuplicateHandle looks straightforward there are concurrency issues that you have to be careful with - this is BrowserUK's comment about storing a handle when the owning process has ended. You also have to figure out an IPC mechanism to pass the handle (which is just an unsigned int) from one process to the other.

    That might sound like I am contradicting BrowserUK above, but I'm not. You are using Win32::Process which returns a Perl reference to a process object - it does not expose the handle. This Perl reference cannot be shared between processes. You will have to find another mechanism.

    One alternative is to pass the PID to the second script, and then open your own process object using Win32::Process::Open. Sounds easy? There is a possible race condition. The problem is that if the child process ends while all this is going on, the next process to start might use the same PID (PIDs are reused on Windows), then you end up waiting on the wrong process. You might have to check you are waiting on the right one.
Re: Use another script to check bacground process
by BrowserUk (Patriarch) on Dec 27, 2010 at 06:22 UTC
    My idea was "somehow" to save reference to an object I get by Win32::Process::Create and later use this reference in another script.

    It won't work.

    Update:

    To elaborate. If you "store" a system handle given to one process, in some persistent storage, and then try to retrieve that handle and use it from another process some time after the first process has ended, the handle will be invalid.

    Ie. It won't work.


    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".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Use another script to check bacground process
by afoken (Chancellor) on Dec 27, 2010 at 14:56 UTC

    Think about a different approach. Windows is a painful environment, but it has an API for background processes. They are called services, and it is possible to write services in Perl. Services can be monitored easily and with a predefined API. No need to re-invent the wheel.

    On a Unix system, I would (and do) use daemontools to run and monitor "background" processes, with much less pain. Should a process exit unexpectedly, daemontools will report that and restart the process (unless configured otherwise), thanks to SIGCHLD.

    Windows has no signals, not even SIGCHLD, but you can (painfully) construct similar mechanisms, typically using atoms, semaphores, and other API functions not originally intended to do so.

    The important trick in both cases is that the script starter does not exit, but keeps track of its child processes. With daemontools, you don't even start the child process, but instead tell the monitor to start (or stop or signal) the script. This is very similar to how Windows Services behave.

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
Re: Use another script to check bacground process
by Anonymous Monk on Dec 27, 2010 at 01:51 UTC
    See documentation for Win32::Process::Open

    Its amazing how often the answer to a question is right in the docs

Re: Use another script to check bacground process
by Anonymous Monk on Dec 28, 2010 at 01:14 UTC

    Thank all of you for advice. Win32::Process::Open seem to be very promissing, only that I do some mistake. I have writen 2 short scripts:

    # SCRIPT TO START NOTEPAD.EXE #!/usr/bin/perl -w use Win32; use Win32::Process; $ApplicationName = 'c:\\windows\\notepad.exe'; $CommandLine = 'notepad'; $CreateOptions = NORMAL_PRIORITY_CLASS | DETACHED_PROCESS; Win32::Process::Create($ProcessObj,$ApplicationName,$CommandLine, 0, # Don't inherit. $CreateOptions, ".") # current dir. or die print_error(); #$ProcessObj->Wait(INFINITE) or warn print_error(); $ProcessObj->Wait(500) or warn print_error(); $ProcessObj->GetExitCode($ExitCode) or warn print_error(); print "[$CommandLine] exited with $ExitCode\n"; sub print_error { print Win32::FormatMessage( Win32::GetLastError() ); } $pid = $ProcessObj->GetProcessID(); print "PID: $pid\n\n"; > PID: 3052 >

    *******************************************************************************

    The PID I get from the running process I pass to the second script:

    # SCRIPT TO CHECK RUNNING PROCESS #!/usr/bin/perl -w use Win32; use Win32::Process; $pid = shift; Win32::Process::Open($ProcessObj,$pid,1); $ProcessObj->Wait(INFINITE) or warn print_error(); print "END \n"; $ProcessObj->GetExitCode($ExitCode) or warn print_error(); print "...exited with $ExitCode\n"; sub print_error { print Win32::FormatMessage( Win32::GetLastError() ); }

    ----------------------------------------------------------------------------------

    Unfortunately I get this message:

    >PID: 3052 > >Access is denied. > >END >...exited with 259

    *******************************************************************************

    Have you any idea why I keep getting the massage: Access is denied?

    I was thinking about windows services as afoken has suggested as well. I need to start about 20000 processes in about 12 hours with about 100 types of command lines - perl scripts, BAT scripts, executables. Some of them run few seconds, some of them run few hours. Is stil this type of tasks suitable to run via Win32::Daemon?

    Thanks

    Tomas