Hello all...

I'm working on a POE project that uses POE::Wheel::Run to start external
programs at specified times. (Background: it's going to be broadcasting
TV programs.) My test code passes all tests, but once I've run all my
tests, the POE::Kernel::run method keeps on running, and doesn't return.

Obviously, I'm failing to clean something up, so the POE kernel thinks
I'm not finished with all my event processing, but I can't figure out
what. I'm hoping that sharper eyes and minds here can spot what I've
missed.

I'm running Perl 5.8.0 compiled WITHOUT threads on a Red Hat 8 system,
and I've got POE version 0.24.

When I turn on POE garbage-collection debugging, after the main
processing completes, the POE kernel prints out an endless stream of:

<rc> decrementing refcount for session
rincewind.doyle-nelson.com-3e32b2940000090c
(POE::Kernel=ARRAY(0x82a3764)) at
/usr/lib/perl5/site_perl/5.8.0/POE/Kernel.pm line 1872.
<rc> decrementing refcount for session
rincewind.doyle-nelson.com-3e32b2940000090c
(POE::Kernel=ARRAY(0x82a3764)) at
/usr/lib/perl5/site_perl/5.8.0/POE/Kernel.pm line 1872.
<rc> incrementing refcount for session
rincewind.doyle-nelson.com-3e32b2940000090c
(POE::Kernel=ARRAY(0x82a3764)) at
/usr/lib/perl5/site_perl/5.8.0/POE/Kernel.pm line 1893.
<rc> incrementing refcount for session
rincewind.doyle-nelson.com-3e32b2940000090c
(POE::Kernel=ARRAY(0x82a3764)) at
/usr/lib/perl5/site_perl/5.8.0/POE/Kernel.pm line 1893.
<rc> ,----- Kernel Activity -----
<rc> | Events : 1
<rc> | Files  : 1
<rc> | Extra  : 0
<rc> | Procs  :
<rc> `---------------------------
<rc> ... at /usr/lib/perl5/site_perl/5.8.0/POE/Kernel.pm line 2038.

I'm not setting any alarms, and I'm not watching any filehandles that
I know about, so the "Events" and "Files" scores up there refer to
something I don't know about. Running with '-w' gives me no warnings.

To summarize what the code is supposed to be doing: First, it spawns a
controller session that has Test::More hooks. That session immediately
spawns a second session (the "Handler" session), which then spawns off
a Wheel::Run that runs the sleep command for a certain number of
seconds. When the Wheel::Run is done, the Handler fires a callback
event and continues.

Here's the code:

$| = 1;
use strict;
use Test::More tests => 1;

use POE;
use Data::Dumper;

#######################
# Spins off a secondary process that just sleeps for a while, then
returns, and
# tests that 'content_ended' was fired after the return, and that
# the subsession we spawned sent its callback event
('test_content_end').
{
  POE::Session->create(
                       args => [ BCTV::ContentHandler::Sleep->new()->spawn() ],
                       inline_states => {
                                         _start => sub {
                                           my ($heap, $kernel, $session, 
$handler_session) = @_[HEAP,
KERNEL, SESSION, ARG0];
                                           $heap->{'Start Time'} = time();
                                           $kernel->post( $handler_session, 'play', 
[3],
$session->postback( 'test_content_end' ));
                                         },
                                         
                                         test_content_end => sub {
                                           my ($kernel, $heap) = @_[KERNEL, HEAP];
                                           ok( (time() - $heap->{'Start Time'} ) <= 4);
                                           delete $heap->{'Start Time'};
                                           $kernel->state('test_content_end');
                                           print "Controller heap: ", Dumper($heap), 
"\n";
                                         }
                                        },
                      );
  $poe_kernel->run();
}

BEGIN {

package BCTV::ContentHandler::Sleep;

use POE;
use POE::Wheel::Run;
use Data::Dumper;

##
## new()
##
sub new {
  my $type = shift;
  my $self = {};

  bless $self, $type;
}

##
## play()
##
## Plays. When content is ended, we fire off the callback.
##
sub play {
  my ($self, $heap, $play_args, $callback) = @_[OBJECT, HEAP, ARG0,
ARG1];

  $self->{'run'} = POE::Wheel::Run->new(
                                        Program => [ '/bin/sleep', $play_args->[0] ],
                                        StderrEvent => 'nullevent',
                                        );
  $poe_kernel->sig('CHLD', 'content_ended');
  $heap->{'Callback'} = $callback;
}

sub _start { }


##
## spawn()
##
## Creates the ContentHandler as a POE session.
##
sub spawn {
  my $self = shift;

  return POE::Session->create(
                              object_states => [
                                                $self => [ '_start',
                                                           'play',
                                                           'content_ended'
                                                         ]
                                                ]
                             );
}

sub content_ended {
  my ($kernel, $heap) = @_[KERNEL, HEAP];
  wait;
  &{ $heap->{'Callback'} }();
  delete $heap->{'Callback'};
  $kernel->sig_handled();
  delete $heap->{'run'};
  print "Handler heap: ", Dumper($heap);
}

}
__END__

This prints out:

1..1
Handler heap: $VAR1 = {};
ok 1
Controller heap: $VAR1 = {};


(The print statements are just to verify that the heaps in the
sessions I've created are empty.)

Afterwards it just sits there until the heat death of the universe, or
until I get bored, whichever comes first. Perhaps I should forget
about using Run and just handle the forking code myself. Any ideas?

Thanks,

Stephen Nelson
[EMAIL PROTECTED]




Reply via email to