On Mon, Aug 19, 2002 at 01:56:34PM -0400, L. Leo wrote:
> 
> The following program demonstrates a bug I found in POE v0.22 . I
> was trying to benchmark event calling (inline_states vs. package_states
> vs. object_stats). The benchmark program took a long time the the first
> test and then exited quickly on the second and following tests.
> 
> It turns out that for the first time $poe_kernel->run() is called
> the 'iterate' event will be called 11 times (as is expected). However,
> on the second call to $poe_kernel->run(), the 'iterate' event handler
> will only be run twice. The '_start' handler posts an 'iterate' event
> and it is executed by the kernel. The 'iterate' handler yields an
> 'iterate' event and it is run. But the second yield to 'iterate'
> from the 'iterate' handler fails to be executed.
> 
> The workaround I found was that if you use the Event module the sessions
> executes correctly twice. I haven't had the time to chase down the real
> cause.
> 
> BTW, I found the bug on Redhat 7.3 with perl v5.6.1 and POE v0.22 .

[test case]

Thank you for the test case.  I was able to verify the problem here
with POE from CVS (a little beyond v0.22) and FreeBSD.

The problem stems from the fact that the Kernel does some serious
one-time initialization in its new() method, and it must clean things
up after run() returns.

The problem is mainly to do with signals, actually.  Handlers are set
up in new() and reset after run() returns.  The signal handlers are
reset so other code can set them after run().  I think Arthur
requested it or mentioned it was a problem, perhaps when running out
of mod_perl.  The exact reasons for it are probably in the CHANGES
file somewhere.

Anyway, I added a flag to POE::Kernel that tracks when run() returns.
If it's called again after that, it resets its signal handlers.  That
causes your test case to succeed, but it introduces yet another
signal-related function.  Namely, if POE exits on a terminal signal
(IDLE, ZOMBIE, UIDESTROY, TERM, etc.), then $poe_kernel will be
invalidated.  This happens because the Kernel itself is considered a
session for signal dispatch purposes.  In Unix terms, $poe_kernel acts
like init(8).

When a terminal signal kills off POE, it first must destroy all POE's
sessions.  That includes POE::Kernel itself, which means it's not
recognized (it's not running) when $poe_kernel->run() is called again.
That causes a failure in POE's regression tests, which actually do
call run() twice in at least one place.

A better solution will be to abstract POE::Kernel's session-like code
into an actual session that can be killed off and restarted.  That
will take some time to do right, but it seems like the right thing to
do.

I should also change POE::Kernel not to register %SIG handlers-- or
the equivalents for whichever event loop is active-- until a session
requests the handler with sig().  That will require _signal to be
deprecated, as is scheduled in the "Signal Reforms" document at
http://poe.perl.org/?POE_RFCs/Signal_Reforms

I'm surprised using Event worked around this for you.  It doesn't
solve the problem here on FreeBSD, and I can't see why it would work.

-- Rocco Caputo / [EMAIL PROTECTED] / poe.perl.org / poe.sf.net

Reply via email to