Re: POE::Wheel::Run::Win32 and Win32::Daemon
[email protected] (Andrew Feren)
| Newsgroups | perl.poe |
|---|---|
| Message-ID | <[email protected]> |
While I have several unresolved issues with fork on Windows I think they
biggest problem with your script is that the fork logic backwards.
Something like the following will give you better results.
my $pid;
if($pid = fork()) {
print(FOUT "running ($pid)\n");
wait();
} else {
open(FOR, '>>', 'C:\delme-kid.txt');
thread();
close(FOR);
sleep(10);
exit(0);
}
-Andrew
Andreas Altergott wrote:
> Hi,
>
> this will be especially interesting for dolman :-)
>
> as already described in previous emails there is a big problem when
> using POE::Wheel::Run::Win32 with Win32::Daemon as a windows service.
> Your service will get a termination request from windows, as soon as any
> child process terminates.
>
> This happens because POE::Wheel::Run::Win32 is using the fork() method.
> I do not know how exactly ActiveStates Perl handles the fork() method,
> but it does it different than the system() method. The system() method
> also creates a child process, but it waits for the child until it
> terminates. This does not initiate a termination request to the
> service. Although both do create sub processes.
>
> Speaking in windows terminology one has to say threads instead of
> processes. So system() is using fork() according to the perldocs. And
> fork() tries to do a real fork() if it is available. On windows it is
> not. So it has to create a thread. I don't know how it does terminate
> a thread though. It must be different when you use system(), else it
> wouldn't terminate your service.
>
> Here's some more detailed information on perls fork() and system()
>
> o http://perldoc.perl.org/perlfork.html
>
> o http://perldoc.perl.org/functions/fork.html
>
> o http://perldoc.perl.org/functions/system.html
>
> Luckily, using threads is not a blocking process. It means that your
> POE program can continue working, while the thread is also doing it's
> work. The only drawback is, that your programs will be windows
> specific. You can not do a 'use threads;' inside of eval, require or
> any other trick to make it system independent.
>
> o http://perldoc.perl.org/threads.html
>
> The fast solution is to use threads instead of POE::Wheel::Run::Win32.
>
> use threads;
>
> my $thr = 0;
>
> sub thread {
> return(system("C:/Progs/any.exe"));
> }
>
> ...
>
> # inside a POE subroutine that's getting called over and over again
> unless ($thr) {
> print("creating thread\n");
> $thr = threads->create('thread');
> }
>
> if ($thr->is_joinable()) {
> print("thread returned " . $thr->join() . "\n");
> $thr = 0;
> }
>
> ...
>
> I've been reading in some previous mails, that POE::Wheel::Run and
> POE::Wheel::Run::Win32 have been merged. This is nice to hear :-)
> But in this case it complicates things. Because now POE::Wheel::Run is
> system independent by using fork(). As described this is not possible
> with Win32::Daemon. So either it should be noted somewhere, that
> POE::Wheel::Run is not usable from a windows service, or it should be
> split again :-p into POE::Wheel::Run::Win32 using threads instead of
> fork(). ;-)
>
> Maybe this issue is easier to fix, by attacking fork() itself.
> Well, you do not strictly need POE::Wheel::Run, if you do use threads.
> They are not blocking anyway, by doing the test is_joinable().
>
> I'm not sure if this concerns only Win32::Daemon or if it is a global
> windows service problem with Perl using fork().
>
> This is not POE, but the core of the /fork()/ is the same. You can use
> POE::Component::Daemon::Win32 to simplify things, but don't forget to
> use threads.
>
> #!/usr/bin/perl
> ########################################################################
> # parent.pl
>
> use strict;
> use warnings;
>
> use threads;
> use Win32;
> use Win32::Daemon;
>
> sub thread {
> return(system("C:/Perl/bin/perl.exe C:/kid.pl"));
> }
>
> my $SERVICE_SLEEP_TIME = 20;
> my $PrevState = SERVICE_START_PENDING;
> my $thr = 0;
>
> Win32::Daemon::StartService();
>
> open(FOUT, '>', 'C:/delme-parent.txt');
>
> while (SERVICE_STOPPED != (my $State = Win32::Daemon::State())) {
> if (SERVICE_START_PENDING == $State) {
> print(FOUT "start pending\n");
> Win32::Daemon::State(SERVICE_RUNNING);
> $PrevState = SERVICE_RUNNING;
> } elsif ( SERVICE_STOP_PENDING == $State ) {
> print(FOUT "stop pending\n");
> Win32::Daemon::State(SERVICE_STOPPED);
> } elsif (SERVICE_PAUSE_PENDING == $State) {
> print(FOUT "pause pending\n");
> Win32::Daemon::State(SERVICE_PAUSED);
> $PrevState = SERVICE_PAUSED;
> next;
> } elsif (SERVICE_CONTINUE_PENDING == $State) {
> print(FOUT "continue pending\n");
> Win32::Daemon::State(SERVICE_RUNNING);
> $PrevState = SERVICE_RUNNING;
> next;
> } elsif (SERVICE_STOP_PENDING == $State) {
> print(FOUT "stop pending\n");
> Win32::Daemon::State(SERVICE_STOPPED);
> $PrevState = SERVICE_STOPPED;
> next;
> } elsif (SERVICE_RUNNING == $State) {
> print(FOUT "running\n");
>
> # Runs as it should run :-)
> unless ($thr) {
> print(FOUT "creating thread\n");
> $thr = threads->create('thread');
> }
>
> if ($thr->is_joinable()) {
> print(FOUT "thread returned " . $thr->join() . "\n");
> $thr = 0;
> }
>
> # Runs only once and kills the parent process on sigchld.
> # One should use child signals to harvest children, so that it
> # does not block the parent process. This here is only to
> # demonstrate the termination of the parent process.
> #if(fork()) {
> # open(FOR, '>>', 'C:/delme-kid.txt');
> # print(FOR "running\n");
> # close(FOR);
> # sleep(10);
> # exit(0);
> #} else {
> # wait();
> #}
>
> # Runs perfectly, but freezes the parent process.
> #system("C:/Perl/bin/perl.exe C:/kid.pl");
> } else {
> print(FOUT "unknown request\n");
> Win32::Daemon::State($PrevState);
> }
>
> if (SERVICE_CONTROL_NONE != (my $Message =
> Win32::Daemon::QueryLastMessage(1))) {
> if (SERVICE_CONTROL_INTERROGATE == $Message) {
> print(FOUT "request received\n");
> Win32::Daemon::State($PrevState);
> } elsif (SERVICE_CONTROL_SHUTDOWN == $Message) {
> print(FOUT "shutdown!!!\n");
> Win32::Daemon::State(SERVICE_STOP_PENDING, 25000);
> }
> }
>
> Win32::Sleep( $SERVICE_SLEEP_TIME );
> }
>
> Win32::Daemon::StopService();
> close(FOUT);
>
> # EOF
> ########################################################################
>
> #!/usr/bin/perl
> ########################################################################
> # C:\kid.pl
>
> use strict;
> use warnings;
>
> open(FOR, '>>', 'C:/delme-kid.txt');
>
> print(FOR "starting\n");
>
> for (my $i = 0; $i < 10; $i++) {
> print(FOR "running\n");
> sleep(1);
> }
>
> print(FOR "terminating\n");
>
> close(FOR);
>
> # EOF
> ########################################################################
>
>
> Regards,
> Andreas
>
>