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

Hi Folks. I have a lot of different perl processes that run as scheduled jobs on a server. Im working under Win32 and so I often login via terminal services to check things out. One annoyance is that in the Win32 process list you see perl.exe and not the script name. And the tricks with setting $0 as far as I can tell dont work. But I know that the Win32 perl build is actualyl composed of two parts. The exe, which is about 20k and the dll which is much larger. The exe is in fact normally copied under two names perl.exe and perl5.6.1.exe for example. So I thought that if I used exec and a bit of cleverness I could simply make sure that for each of my scripts there was a custom named perl.exe for them to use. I came up with this:

package ex::NameExe; use strict; use warnings; use File::Spec::Functions qw(splitpath splitdir catdir catpath catfile +); use File::Copy; $|++; my (undef,undef,$script)=splitpath($0); $script or die $0; my ($v,$path,$exe)=splitpath($^X); $path=$v.$path; $script.=".exe"; my $new_exe=catfile($path,$script); unless ($exe eq $script) { copy $^X,$new_exe or die "$^X = > $new_exe:$!" unless -e $new_exe; exec $new_exe,'"-Mstrict;BEGIN{$|++};"',$0,@ARGV; die "Failed to re-execute as $new_exe!"; } 1;

The idea being that you can say perl -Mex::NameExe some_script.pl and magically what will happen is some_script.pl.exe will get created and the exec'ed like some_script.pl.exe some_script.pl but all behind the scenes. This appears to work, with the one problem that if I do it from the command line the first perl immediately exits and I dont see any of the output of the newly execed process. (This doesnt actually matter for most of the cron jobs, but a few of them are batch files and this behaviour of immediately returning will cause problems.)

Maybe im fundamentally misunderstanding things here, but this isnt the behaviour I was expecting, and the docs so far haven't clarified things. Any help would be appreciated.

I should say that what i thought would happen is that the new process would take over as though it had been run in the first place. If this is wrong then hopefully people will clarify. Cheers.


---
demerphq

    First they ignore you, then they laugh at you, then they fight you, then you win.
    -- Gandhi


• Update:  
Ive added in the $0 that PodMaster noticed was missing. So the problem wasnt to do with stdout/stderr at all. :-( But! I still dont understand the behaviour properly here. Why does it return immediately?


Replies are listed 'Best First'.
Re: exec()ed process dont write to std(?:err|out)
by PodMaster (Abbot) on Apr 13, 2004 at 11:17 UTC
    All you're doing with that exec statement is starting a perl interactively. Try exec $new_exe, '-Mstrict', $0, @ARGV; (note the $0).

    update: If you ever plan on distributing this, I reccomend you place the newly named binary in a different spot, like user directory or something (only admins have write perms to my perl -V:bin).

    MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!"
    I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README).
    ** The third rule of perl club is a statement of fact: pod is sexy.

      Gah. Thank you. I totally missed that.

      But this still doesnt clarify in my mind why it returns immediately. For instance check this output:

      D:\Development>type test.pl print "hello world!\n"; #sleep(999999); D:\Development>perl -I. -MNameExe test.pl && echo boo boo D:\Development>hello world! [cursor blinks here]

      Is this what I should have expected?! (Update: I mean should the echo statement complete before the newly spawned perl process? I would expect the output to be reversed.)


      ---
      demerphq

        First they ignore you, then they laugh at you, then they fight you, then you win.
        -- Gandhi


        Now that I think about it, I'd it's all about timing. Consider
        perl -e"exec $^X,qw[ -e sleep(1);warn(666)];die 55" && echo BOO perl -e'exec $^X,qw[ -e sleep(1);warn(666)];die 55' && echo BOO
        and vary the sleep duration (0 and up). On Win2000 I get
        E:\>perl -e"exec $^X,qw[ -e sleep(0);warn(666)];die 55" && echo BOO 666 at -e line 1. BOO E:\>perl -e"exec $^X,qw[ -e sleep(1);warn(666)];die 55" && echo BOO BOO E:\>666 at -e line 1.
        and on debian with bash I get
        crazyinsomniac@perlmonk:~$ perl -e'exec $^X,qw[ -e sleep(1);warn(666)] +;die 55' && echo BOO 666 at -e line 1. BOO
        regardless of the sleep duration (the sleep just delays the output). The bash might be fixing the results with some kind of buffering but I can't tell.

        MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!"
        I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README).
        ** The third rule of perl club is a statement of fact: pod is sexy.

Re: exec()ed process dont write to std(?:err|out) (system)
by tye (Sage) on Apr 13, 2004 at 14:57 UTC
    the first perl immediately exits

    Yes, exec ends the life of the executable that calls it, as documented. On systems that don't have fork, a call to exec spawns a subprocess and then tells the parent process to exit. If you want the grandparent (the process that started the process that ends up calling exec) to wait for the exec'd program to finish, then you need to have the middle process hang around.

    On systems with fork, using exec works for that since the running executable is replaced with the new executable in the same process. On systems without fork, if you want to wait, then you should just use system then exit.

    - tye        

      Ok, and just to make this clear, Win32 simulates fork, and is thus in the category where it doesnt have a fork right?

      If I do use system am I going to be wasting a lot of resources by having an outer normal perl running a system() call to another perl invocation? Also in your opinion is this a bad idea?


      ---
      demerphq

        First they ignore you, then they laugh at you, then they fight you, then you win.
        -- Gandhi


        Yes, Win32 doesn't have fork.

        Since most uses of system() (which are done outside of Perl, I'd guess) end up calling /bin/sh just to interpret the command-line syntax and then have /bin/sh just sitting around the entire time waiting for the program you really wanted to run to exit, I don't think it can be too awful to have a similar situation with perl sitting around.

        As for the bigger picture of what you are really trying to do, I won't pretend to understand it.

        - tye