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

Hi again.

This has to do with my yesterday's problem, but it's even a bit more complicate ;-)

My script.pl opens an application.exe in the background with open3, but as it is given a pipe to logger.bat (look at the code:
$pid=open3(NULL,\*NULL,\*NULL, "application.exe 2>&1 | logger.bat");
it doesn't return the PID of application.exe to $pid, but the PID of CMD.exe, which is opened automatically for running the pipe and logger.bat.

So here's the problem:
1. I need to know the PID of application.exe - but: there are several instances of application.exe running at the same time, so looking for application.exe in the Win32::Process names doesn't make sense.
2. My script.pl is started over srvany.exe as a Win32 service. So I'll start it with "net start script" and stop it with "net stop script". The problem is, I have to kill application.exe before my script is killed. In other words: killing my script, will leave the application.exe running.
So I need to catch the "net stop" within my script.pl, so that I can kill application.exe before script.pl exits.

I tried so many ways now, but I don't think that there is another possibility to run application.exe the way I want than the way I have given in the piece of code.
(Yes, I tried out all the things you gave me yesterday. Thanks again for that.)

One possibility could be, that application.exe looks that his parent, my script.pl, is running, and if not, it will quit. But I'd prefer not to change the sources of application.exe.

Any ideas?

Thorsten

Replies are listed 'Best First'.
Re: kill a child / parent process
by AcidHawk (Vicar) on Apr 10, 2003 at 09:26 UTC

    I have done a similar thing to what you describe. Although I have never used open3. I always use Win32::Process to spawn my "children" processes. Below is some code I ripped from some production code which launches several process that all have the same NAME but will obviously have different PIDS. I have to keep the PIDS in an array, each process that I launch also has some kind of unique identifier.

    foreach my $md (@chk_mds) { #@chk_mds is a list of the unique ident +ifiers (I.e SrvA, SrvB, SrvC etc) #Read What Kind of Process to Start. if (!&Spawn($md)) { &Update_Log("Problems Spawning $proc[0] Process for $md"); } sleep(1); } #Re-Spawn the broken Process sub Spawn { my $rc = 0; my $md = shift; my $result = Win32::Process::Create( $ProcessObj, "$xcall_path/bin/application.exe", "application.exe $md", 1, #Inherit Handles. NORMAL_PRIORITY_CLASS, ".") or &Update_Log("DEBUG - Cannot Launch the X-$ +proc process: $!"); if ($result) { my $pid = $ProcessObj->GetProcessID(); $proclst{$md} = $pid; push (@pids, $pid); &Update_Log("\@pids = @pids"); &Update_Log("Launching Call Logger Process for $md with PI +D - $proclst{$md}"); $rc = $pid; } else { &Update_Log("Process for $md NOT successfully Created:" . +Win32::FormatMessage(GetLastError())); } return($rc); } #Update Log file sub Update_Log { my ($ss, $mm, $hh, $d, $mon, $yr) = localtime(); my $date = sprintf("%02d-%02d-%04d", $mon+1, $d, $yr+1900); my $time = sprintf("%02d:%02d:%02d", $hh, $mm, $ss); #Specify the Logfile Name my $logfile = "$xcall_path/log/X-CallServer$date.log"; if (open( LOG, ">>$logfile" ) ) { my $TempSelect = select( LOG ); $| = 1; select( $TempSelect ); if (! $_[0]) { return (0); } print LOG "$time - $_[0]"; } else { &Event(EVENTLOG_ERROR_TYPE, "X-CallServer Could Not Open Logfi +le $logfile: $!"); exit(5); } close(LOG); return(1); }

    So what I have is a hash (%proclst) of all my application.exe's PIDS. I then have a piece of code that kills these PIDS when the service stops.

    foreach my $pid (keys %proclst) { Win32::Process::KillProcess($proclst{$pid}, 255); &Update_Log("Service Stopping - Stopping $proclst{$pid}"); } undef %proclst;
    These are only snippets from a larger piece of code, I am using Win32::Daemon for all my service requirements on Win32 also. The Update_Log is a routine that I use to update log files etc.. Really only included so you dont get confused when you see me call it from the Spawn function.

    HTH..

    -----
    Of all the things I've lost in my life, its my mind I miss the most.
Re: kill a child / parent process
by benn (Vicar) on Apr 10, 2003 at 10:20 UTC
    I refrained from suggesting this yesterday as it looked like you didn't have access to the source for application.exe, but as it appears that you do, how about simply adding 'write-to-a-daily-rotated-log-filename' routine to application.exe instead, rather than having to write more-and-more complicated external control routines? I realise this may be not what you want for other reasons, but it sounds like this is becoming a bit of a monster <g>. Or of course, you could switch to 'nix... :)

    Cheers
    Ben
      Hi Ben,

      well, of course you're right. The thing is, that I'm a trainee and I'm only working in this department of my company for 5 weeks...tomorrow will be the last day ;-)

      At the beginning, I was told, that I should rewrite a korn shell script into something for Windows. I always wanted to learn Perl, so I thought, this might be a good chance.
      From time to time, the professionals here asked me, if i could implement this and that in my script and I was glad of having chosen Perl, but meanwhile there is so much, my script shall do, that I also think it would have been better to edit the application.exe, but it's written in C++.

      For this afternoon, I think I'll give the process creation with Win32::Process another try, but if it doesn't work, I don't mind too much. My script is starting application.exe very well, handles logfiles, links some server shares and monitors them...there's really only the problem with shutting it all down left.


      Bye.
      Thorsten
        Nice work! Maybe you can persuade the 'professionals' to let you rewrite application.exe in perl for them - or give them some training...:)

        Cheers
        Ben
Re: kill a child / parent process
by Thelonius (Priest) on Apr 10, 2003 at 17:05 UTC
    I don't think that srvany gives you any way to catch the "NET STOP". However, there is a similar program in the cygwin package called "cygrunsrv" that sends a signal to the program when NET STOP is used. It worked for me with cygwin perl, but not with ActivePerl 5.8.0 (I think that signal handling is generally screwed up in the latest activeperl). I installed my program like this:
    cygrunsrv -I testsrv -p c:/bin/perl.exe -a /home/hirschk/testsrv.pl
    and the program testsrv.pl looked like this:
    #!perl -w use strict; my $quit = 0; $SIG{TERM} = sub { $quit = 1; }; open OUT, ">>/home/hirschk/srvout"; select(OUT); $|++; print OUT "start time = ", scalar(localtime(time)), "\n"; select(STDOUT); while (1) { sleep(15); if ($quit) { print OUT "quitting at ", scalar(localtime(time)), "\n"; exit(0); } print OUT "time = ", scalar(localtime(time)), "\n"; }
Re: kill a child / parent process (Service Skeleton)
by AcidHawk (Vicar) on Apr 10, 2003 at 18:36 UTC