Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Ton Hospel discovered that stop() from some event handlers causes the

session that called it to be reaped twice.  The second reap triggers
an inconsistency error when ASSERT_DEFAULT is enabled.  This patch
adds a check to see whether a session is dead by the time its handler
returns (and bypasses a lot of moot garbage collection in the rare
cases that it is).  It adds a performance penalty across the board.
There's probably a better way, but this is more immediate.  This patch
also includes Ton's test case as a proper regression test.
  • Loading branch information...
commit fdf923a2d39a72d18c189b879aa76b0ecf337d1e 1 parent cddf9ba
@rcaputo authored
View
1  MANIFEST
@@ -158,3 +158,4 @@ t/30_loops/00_base/wheel_sf_unix.pm
t/30_loops/00_base/wheel_tail.pm
t/90_regression/neyuki_detach.t
t/90_regression/suzman_windows.t
+t/90_regression/ton-stop-corruption.t
View
22 lib/POE/Kernel.pm
@@ -895,8 +895,9 @@ sub _dispatch_event {
}
my $return;
if (wantarray) {
- $return =
- [ $session->_invoke_state($source_session, $event, $etc, $file, $line) ];
+ $return = [
+ $session->_invoke_state($source_session, $event, $etc, $file, $line)
+ ];
}
else {
$return =
@@ -924,14 +925,19 @@ sub _dispatch_event {
# Pop the active session, now that it's not active anymore.
$kr_active_session = $hold_active_session;
+ # Recover the event being processed.
+ $kr_active_event = $hold_active_event;
+
if (TRACE_EVENTS) {
my $string_ret = $return;
$string_ret = "undef" unless defined $string_ret;
_warn("<ev> event $seq ``$event'' returns ($string_ret)\n");
}
- # Post-dispatch processing.
- #
+ # Bail out of post-dispatch processing if the session has been
+ # stopped. -><- This is extreme overhead.
+ return unless $self->_data_ses_exists($session);
+
# If this invocation is a user event, see if the destination session
# needs to be garbage collected. Also check the source session if
# it's different from the destination.
@@ -970,9 +976,6 @@ sub _dispatch_event {
$self->_data_ses_collect_garbage($session);
}
- # Recover the event being processed.
- $kr_active_event = $hold_active_event;
-
# Return what the handler did. This is used for call().
return @$return if wantarray;
return $return;
@@ -1049,8 +1052,9 @@ sub run {
# Stops the kernel cold. XXX Experimental!
# No events happen as a result of this, all structures are cleaned up
-# except the current session which will be cleaned up when the current
-# state handler returns.
+# except the kernel's. Even the current session is cleaned up, which
+# may introduce inconsistencies in the current session... as
+# _dispatch_event() attempts to clean up for a defunct session.
sub stop {
# So stop() can be called as a class method.
my $self = $poe_kernel;
View
16 lib/POE/Resource/FileHandles.pm
@@ -228,14 +228,14 @@ sub _data_handle_enqueue_ready {
# Emit them.
foreach my $select (@selects) {
- $self->_data_ev_enqueue
- ( $select->[HSS_SESSION], $select->[HSS_SESSION],
- $select->[HSS_STATE], ET_SELECT,
- [ $select->[HSS_HANDLE], # EA_SEL_HANDLE
- $mode, # EA_SEL_MODE
- ],
- __FILE__, __LINE__, time(),
- );
+ $self->_data_ev_enqueue(
+ $select->[HSS_SESSION], $select->[HSS_SESSION],
+ $select->[HSS_STATE], ET_SELECT,
+ [ $select->[HSS_HANDLE], # EA_SEL_HANDLE
+ $mode, # EA_SEL_MODE
+ ],
+ __FILE__, __LINE__, time(),
+ );
# Count the enqueued event. This increments FMO_EV_COUNT
# because an event has just been enqueued. This makes sense.
View
43 tests/90_regression/ton-stop-corruption.t
@@ -0,0 +1,43 @@
+#!/usr/bin/perl -w
+# $Id$
+
+# Test that stop() does not result in a double garbage collection on
+# the session that called it. This test case provided by Ton Hospel.
+
+use strict;
+
+use Test::More tests => 5;
+
+BEGIN { use_ok("POE") }
+BEGIN { use_ok("POE::Pipe::OneWay") }
+
+BEGIN { $^W = 1 };
+
+my ($rd, $wr) = POE::Pipe::OneWay->new();
+ok(defined($rd), "created a pipe for testing ($!)");
+
+my $stop_was_called = 0;
+
+POE::Session->create(
+ inline_states => {
+ _start => sub {
+ $poe_kernel->select_read($rd, "readable");
+ },
+ readable => sub {
+ pass("got readable callback; calling stop");
+ $poe_kernel->select_read($rd);
+ $poe_kernel->stop();
+ },
+ _stop => sub { $stop_was_called++ },
+ _parent => sub { },
+ _child => sub { },
+ }
+);
+
+close $wr;
+
+POE::Kernel->run();
+
+ok( !$stop_was_called, "stop was not called" );
+
+exit;
Please sign in to comment.
Something went wrong with that request. Please try again.