Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial Event support; new Tk test; more manpage revisions

  • Loading branch information...
commit 9573d8c607b647e1a43f293030f94e5a36e34342 1 parent d8788af
@rcaputo authored
View
24 Changes
@@ -16,18 +16,34 @@ make dist on it! 0.0910 is ``v0_0910''! For example:
,----- To Do -----
|
| Create a test program for fork and sigchld.
-| Still can't get Event to compile on 5.6.0+OS/2 or 5.005+61+FreeBSD;
-| be sure to mark Event experimental in the new documentation.
-| Make a test for Tk.
+| Turn SocketFactory's sample program into a test case
| Make a test for Event, when it can be made to work.
| Split the samples out into a separate distribution.
|
`-----------------
+
+0.1005 2000.??.??
+-----------------
+
+I forgot to document POE::Session's constructors. Big oops there.
+Now they are, sort of.
+
+Rewrote the POE::Wheel POD.
+
+Found the Perl symbols that weren't being exported for OS/2 and AIX
+(and maybe Windows). Fixed makedef.pl to export them, and now Event
+builds and tests ok. Sweet! Added initial Event support to
+POE::Kernel and removed the Event caveats throughout POE's
+documentation. This is experimental until a proper test can be made.
+
+Added t/06_tk.t to test Tk support.
+
+
0.1004 2000.05.21
-----------------
-Rewrote the POE, POE::Kernel and POE::Session manpages. Documented Tk
+Rewrote the POE, POE::Kernel and POE::Session PODs. Documented Tk
support. Documented Event support, but it's not in yet.
t/04_select.t assumed that two-argument syswrite was legal, but it
View
1  MANIFEST
@@ -62,3 +62,4 @@ t/02_alarms.t
t/03_aliases.t
t/04_selects.t
t/05_macros.t
+t/06_tk.t
View
2  lib/POE.pm
@@ -903,6 +903,7 @@ progress report:
README rewritten 2000.05.16
POE::Kernel rewritten 2000.05.19
POE::Session rewritten 2000.05.21
+ POE::Wheel rewritten 2000.05.22
POE::Component queued
POE::Component::Server::TCP queued
@@ -914,7 +915,6 @@ progress report:
POE::Filter::Reference queued
POE::Filter::Stream queued
POE::Preprocessor queued
- POE::Wheel queued
POE::Wheel::FollowTail queued
POE::Wheel::ListenAccept queued
POE::Wheel::ReadWrite queued
View
366 lib/POE/Kernel.pm
@@ -229,15 +229,19 @@ BEGIN {
{% define_assert SESSIONS %}
}
-# Determine whether Tk is loaded. If it is, set a constant that
-# enables Tk behaviors throughout POE::Kernel. If Tk isn't present,
-# then the support code won't run, but it still needs to compile. In
-# this case, we define a series of dummy constant functions that
-# replace the missing Tk calls.
+# Determine whether Tk or Event is loaded. If either is, set a
+# constant that enables its specific behaviors throughout POE::Kernel.
+# Replace the unused ones' methods with dummies; these won't ever be
+# called, but they need to be present so that POE::Kernel compiles.
BEGIN {
+ # Can't use Tk and Event at the same time.
+ if (exists $INC{'Tk.pm'} and exists $INC{'Event.pm'}) {
+ croak "POE: Tk and Event have incompatible event loops. Can't use both";
+ }
+
+ # Check for Tk.
if (exists $INC{'Tk.pm'}) {
- warn "POE: Tk version $Tk::VERSION is in use! Let's rock!\n";
eval <<' EOE';
sub POE_HAS_TK () { 1 }
EOE
@@ -249,6 +253,21 @@ BEGIN {
sub Tk::MainWindow::new () { undef }
EOE
}
+
+ # Check for Event.
+ if (exists $INC{'Event.pm'}) {
+ eval <<' EOE';
+ sub POE_HAS_EVENT () { 1 }
+ EOE
+ }
+ else {
+ eval <<' EOE';
+ sub POE_HAS_EVENT () { 0 }
+ sub Event::loop () { 0 }
+ sub Event::idle () { 0 }
+ sub Event::timer () { 0 }
+ EOE
+ }
}
#------------------------------------------------------------------------------
@@ -266,10 +285,10 @@ enum SH_HANDLE SH_REFCOUNT SH_VECCOUNT
# The Kernel object. KR_SIZE goes last (it's the index count).
enum KR_SESSIONS KR_VECTORS KR_HANDLES KR_STATES KR_SIGNALS KR_ALIASES
enum + KR_ACTIVE_SESSION KR_PROCESSES KR_ALARMS KR_ID KR_SESSION_IDS
-enum + KR_ID_INDEX KR_TK_TIMED KR_TK_IDLE KR_SIZE
+enum + KR_ID_INDEX KR_WATCHER_TIMER KR_WATCHER_IDLE KR_SIZE
# Handle structure.
-enum HND_HANDLE HND_REFCOUNT HND_VECCOUNT HND_SESSIONS HND_FILENO
+enum HND_HANDLE HND_REFCOUNT HND_VECCOUNT HND_SESSIONS HND_FILENO HND_WATCHERS
# Handle session structure.
enum HSS_HANDLE HSS_SESSION HSS_STATE
@@ -347,7 +366,9 @@ const FIFO_DISPATCH_TIME 0.01
# [ { $session => [ $handle, $session, $state ], .. },
# { $session => [ $handle, $session, $state ], .. },
# { $session => [ $handle, $session, $state ], .. }
-# ]
+# ],
+# fileno(),
+# [ $watcher_r, $watcher_w, $watcher_x ],
# ]
# };
#
@@ -409,6 +430,16 @@ sub _signal_handler_generic {
}
}
+# This is Event's generic signal handler.
+sub _event_signal_handler_generic {
+ my $event = shift;
+ $poe_kernel->_enqueue_state( $poe_kernel, $poe_kernel,
+ EN_SIGNAL, ET_SIGNAL,
+ [ $event->watcher->signas ],
+ time(), __FILE__, __LINE__
+ );
+}
+
# SIGPIPE is handled a little differently. It tends to be
# synchronous, so it's posted at the current active session. We can
# do this better by generating a pseudo SIGPIPE whenever a driver
@@ -429,6 +460,18 @@ sub _signal_handler_pipe {
}
}
+# This is Event's pipe handler. It's probably not valid, since Event
+# delays signals even longer than operating systems do. Pipe signals
+# should be depreciated in favor of EPIPE anyway.
+sub _event_signal_handler_pipe {
+ my $event = shift;
+ $poe_kernel->_enqueue_state( $poe_kernel->[KR_ACTIVE_SESSION], $poe_kernel,
+ EN_SIGNAL, ET_SIGNAL,
+ [ $event->watcher->signas ],
+ time(), __FILE__, __LINE__
+ );
+}
+
# SIGCH?LD are normalized to SIGCHLD and include the child process'
# PID and return code.
@@ -458,6 +501,28 @@ sub _signal_handler_child {
}
}
+# Event's SIGCH?LD handler.
+sub _event_signal_handler_child {
+ my $event = shift;
+
+ # Reap until there are no more children.
+ for (my $reap=0; $reap < $event->count; $reap++) {
+ my $pid = wait;
+ last if $pid < 0;
+
+ # Determine if the child process is really exiting and not just
+ # stopping for some other reason. This is per Perl Cookbook
+ # recipe 16.19.
+ if (WIFEXITED($?)) {
+ $poe_kernel->_enqueue_state( $poe_kernel, $poe_kernel,
+ EN_SIGNAL, ET_SIGNAL,
+ [ 'CHLD', $pid, $? ],
+ time(), __FILE__, __LINE__
+ );
+ }
+ }
+}
+
#------------------------------------------------------------------------------
# Register or remove signals.
@@ -535,8 +600,8 @@ sub new {
undef, # KR_ID
{ }, # KR_SESSION_IDS
1, # KR_ID_INDEX
- undef, # KR_TK_TIMED
- undef, # KR_TK_IDLE
+ undef, # KR_WATCHER_TIMER
+ undef, # KR_WATCHER_IDLE
], $type;
@@ -575,8 +640,22 @@ sub new {
# solution. At some point, POE will include a set of Curses
# widgets, and SIGWINCH will be needed...
if ($signal eq 'WINCH') {
- $SIG{$signal} = 'IGNORE';
- next;
+
+ # Event polls signals in some XS, which means they ought not
+ # kill Perl. Use an Event->signal watcher if Event is
+ # available.
+
+ if (POE_HAS_EVENT) {
+ Event->signal( signal => $signal,
+ cb => \&_event_signal_handler_generic
+ );
+ }
+
+ # Otherwise ignore WINCH.
+ else {
+ $SIG{$signal} = 'IGNORE';
+ next;
+ }
}
# Windows doesn't have a SIGBUS, but the debugger causes SIGBUS
@@ -591,14 +670,48 @@ sub new {
# Leave SIGCHLD alone if running under apache.
unless (exists $INC{'Apache.pm'}) {
- $SIG{$signal} = \&_signal_handler_child;
+
+ # Register an Event signal watcher on it. Rename the signal
+ # 'CHLD' regardless whether it's CHLD or CLD.
+ if (POE_HAS_EVENT) {
+ Event->signal( signal => $signal,
+ cb => \&_event_signal_handler_child
+ );
+ }
+
+ # Otherwise register a regular Perl signal handler.
+ else {
+ $SIG{$signal} = \&_signal_handler_child;
+ }
}
}
elsif ($signal eq 'PIPE') {
- $SIG{$signal} = \&_signal_handler_pipe;
+
+ # Register an Event signal watcher.
+ if (POE_HAS_EVENT) {
+ Event->signal( signal => $signal,
+ cb => \&_event_signal_handler_pipe
+ );
+ }
+
+ # Otherwise register a plain Perl signal handler.
+ else {
+ $SIG{$signal} = \&_signal_handler_pipe;
+ }
}
else {
- $SIG{$signal} = \&_signal_handler_generic;
+
+ # If Event is available, register a signal watcher with it.
+ if (POE_HAS_EVENT) {
+ Event->signal( signal => $signal,
+ cb => \&_event_signal_handler_generic
+ );
+ }
+
+ # Otherwise register a plain signal handler.
+ else {
+ $SIG{$signal} = \&_signal_handler_generic;
+ }
}
$self->[KR_SIGNALS]->{$signal} = { };
@@ -998,7 +1111,7 @@ sub _dispatch_state {
}
#------------------------------------------------------------------------------
-# POE's main loop! Now with Tk support!
+# POE's main loop! Now with Tk and Event support!
sub run {
my $self = shift;
@@ -1009,6 +1122,12 @@ sub run {
eval 'Tk::MainLoop';
}
+ # Use Event's main loop, if Event is loaded.
+
+ if (POE_HAS_EVENT) {
+ eval 'Event::loop()';
+ }
+
# Otherwise use POE's main loop.
else {
@@ -1279,6 +1398,9 @@ sub run {
}
}
+#------------------------------------------------------------------------------
+# Tk support.
+
# Tk idle callback to dispatch FIFO states. This steals a big chunk
# of code from POE::Kernel::run(). Make this function's guts a macro
# later, and use it in both places.
@@ -1303,9 +1425,9 @@ sub tk_fifo_callback {
# Perpetuate the dispatch loop as long as there are states enqueued.
- if (defined $self->[KR_TK_IDLE]) {
- $self->[KR_TK_IDLE]->cancel();
- $self->[KR_TK_IDLE] = undef;
+ if (defined $self->[KR_WATCHER_IDLE]) {
+ $self->[KR_WATCHER_IDLE]->cancel();
+ $self->[KR_WATCHER_IDLE] = undef;
}
# This nasty little hack is required because setting an afterIdle
@@ -1318,9 +1440,9 @@ sub tk_fifo_callback {
$poe_tk_main_window->after
( 0,
sub {
- $self->[KR_TK_IDLE] =
+ $self->[KR_WATCHER_IDLE] =
$poe_tk_main_window->afterIdle( \&tk_fifo_callback )
- unless defined $self->[KR_TK_IDLE];
+ unless defined $self->[KR_WATCHER_IDLE];
}
);
}
@@ -1356,15 +1478,15 @@ sub tk_alarm_callback {
if (@{$self->[KR_ALARMS]}) {
- if (defined $self->[KR_TK_TIMED]) {
- $self->[KR_TK_TIMED]->cancel();
- $self->[KR_TK_TIMED] = undef;
+ if (defined $self->[KR_WATCHER_TIMER]) {
+ $self->[KR_WATCHER_TIMER]->cancel();
+ $self->[KR_WATCHER_TIMER] = undef;
}
my $next_time = $self->[KR_ALARMS]->[0]->[ST_TIME] - time();
$next_time = 0 if $next_time < 0;
- $self->[KR_TK_TIMED] =
+ $self->[KR_WATCHER_TIMER] =
$poe_tk_main_window->after( $next_time * 1000,
\&tk_alarm_callback
);
@@ -1393,6 +1515,106 @@ sub tk_select_callback {
}
#------------------------------------------------------------------------------
+# Event support.
+
+# Event idle callback to dispatch FIFO states. This steals a big
+# chunk of code from POE::Kernel::run(). Make this functions guts a
+# macro later, and use it here, in POE::Kernel::run() and other FIFO
+# callbacks.
+
+sub event_fifo_callback {
+ my $self = $poe_kernel;
+
+ if ( @{ $self->[KR_STATES] } ) {
+
+ # Pull an event off the queue.
+
+ my $event = shift @{ $self->[KR_STATES] };
+ {% ses_refcount_dec2 $event->[ST_SESSION], SS_EVCOUNT %}
+
+ # Dispatch it, and see if that was the last thing the session
+ # needed to do.
+
+ $self->_dispatch_state(@$event);
+ {% collect_garbage $event->[ST_SESSION] %}
+
+ }
+
+ # Stop the idle watcher if there are no more state transitions in
+ # the Kernel's FIFO.
+
+ unless (@{$self->[KR_STATES]}) {
+ $self->[KR_WATCHER_IDLE]->stop();
+ }
+}
+
+# Event timer callback to dispatch alarm states. Same caveats about
+# macro-izing this code.
+
+sub event_alarm_callback {
+ my $self = $poe_kernel;
+
+ # Dispatch whatever alarms are due.
+
+ my $now = time();
+ while ( @{ $self->[KR_ALARMS] } and
+ ($self->[KR_ALARMS]->[0]->[ST_TIME] <= $now)
+ ) {
+
+ # Pull an alarm off the queue.
+
+ my $event = shift @{ $self->[KR_ALARMS] };
+ {% ses_refcount_dec2 $event->[ST_SESSION], SS_ALCOUNT %}
+
+ # Dispatch it, and see if that was the last thing the session
+ # needed to do.
+
+ $self->_dispatch_state(@$event);
+ {% collect_garbage $event->[ST_SESSION] %}
+
+ }
+
+ # Register the next timed callback if there are alarms left.
+
+ if (@{$self->[KR_ALARMS]}) {
+ $self->[KR_WATCHER_TIMER]->at( $self->[KR_ALARMS]->[0]->[ST_TIME] );
+ }
+}
+
+# Event filehandle callback to dispatch selects.
+
+sub event_select_callback {
+ my $self = $poe_kernel;
+
+ my $event = shift;
+ my $watcher = $event->w;
+ my $handle = $watcher->fd;
+ my $vector = ( ( $event->got eq 'r' )
+ ? VEC_RD
+ : ( ( $event->got eq 'w' )
+ ? VEC_WR
+ : ( ( $event->got eq 'e' )
+ ? VEC_EX
+ : return
+ )
+ )
+ );
+
+ my @selects =
+ values %{ $self->[KR_HANDLES]->{$handle}->[HND_SESSIONS]->[$vector] };
+
+ foreach my $select (@selects) {
+ $self->_dispatch_state
+ ( $select->[HSS_SESSION], $select->[HSS_SESSION],
+ $select->[HSS_STATE], ET_SELECT,
+ [ $select->[HSS_HANDLE] ],
+ time(), __FILE__, __LINE__, undef
+ );
+ {% collect_garbage $select->[HSS_SESSION] %}
+ }
+}
+
+#------------------------------------------------------------------------------
sub DESTROY {
# Destroy all sessions. This will cascade destruction to all
@@ -1607,10 +1829,17 @@ sub _enqueue_state {
# register a Tk idle callback to begin the dispatch loop.
if ( POE_HAS_TK ) {
- $self->[KR_TK_IDLE] =
+ $self->[KR_WATCHER_IDLE] =
$poe_tk_main_window->afterIdle( \&tk_fifo_callback );
}
+ # If using Event and the FIFO queue now has only one event, then
+ # start the Event idle watcher to begin the dispatch loop.
+
+ if ( POE_HAS_TK ) {
+ $self->[KR_WATCHER_IDLE]->start();
+ }
+
}
else {
warn ">>>>> ", join('; ', keys(%{$self->[KR_SESSIONS]})), " <<<<<\n";
@@ -1717,16 +1946,23 @@ sub _enqueue_alarm {
# register a Tk timed callback to dispatch it when it becomes due.
if ( POE_HAS_TK and @{$self->[KR_ALARMS]} == 1 ) {
- if (defined $self->[KR_TK_TIMED]) {
- $self->[KR_TK_TIMED]->cancel();
- $self->[KR_TK_TIMED] = undef;
+ if (defined $self->[KR_WATCHER_TIMER]) {
+ $self->[KR_WATCHER_TIMER]->cancel();
+ $self->[KR_WATCHER_TIMER] = undef;
}
my $next_time = $self->[KR_ALARMS]->[0]->[ST_TIME] - time();
$next_time = 0 if $next_time < 0;
- $self->[KR_TK_TIMED] = $poe_tk_main_window->after( $next_time * 1000,
- \&tk_alarm_callback
- );
+ $self->[KR_WATCHER_TIMER] =
+ $poe_tk_main_window->after( $next_time * 1000,
+ \&tk_alarm_callback
+ );
+ }
+
+ # If using Event and the alarm queue now has only one event, then
+ # start the Event timer to dispatch it when it becomes due.
+ if ( POE_HAS_EVENT and @{$self->[KR_ALARMS]} == 1 ) {
+ $self->[KR_WATCHER_TIMER]->at( $self->[KR_ALARMS]->[0]->[ST_TIME] );
}
# Manage reference counts.
@@ -1859,6 +2095,12 @@ sub alarm {
# -><- Remove the idle handler.
}
+ # If using Event and the alarm queue is empty, then ensure that the
+ # timer has stopped.
+ if (POE_HAS_EVENT and @{$self->[KR_ALARMS]} == 0) {
+ $self->[KR_WATCHER_TIMER]->stop();
+ }
+
# Add the new alarm if it includes a time.
if (defined $time) {
$self->_enqueue_alarm( $kr_active_session, $kr_active_session,
@@ -2006,6 +2248,25 @@ sub _internal_select {
[ \&tk_select_callback, $handle, $select_index ],
);
}
+
+ # If we're using Event, then we tell it to watch this
+ # filehandle for us. This is in lieu of our own select code.
+
+ if (POE_HAS_EVENT) {
+
+ $kr_handle->[HND_WATCHERS]->[$select_index] =
+ Event->io
+ ( fd => $handle,
+ poll => ( ( $select_index == VEC_RD )
+ ? 'r'
+ : ( ( $select_index == VEC_WR )
+ ? 'w'
+ : 'e'
+ )
+ ),
+ cb => \&event_select_callback,
+ );
+ }
}
# Increment the handle's overall reference count (which is the
@@ -2100,6 +2361,15 @@ sub _internal_select {
);
}
+ # If we're using Event, then we tell it to stop watching
+ # this filehandle for us. This is in lieu of our own select
+ # code.
+
+ if (POE_HAS_EVENT) {
+ $kr_handle->[HND_WATCHERS]->[$select_index]->cancel();
+ $kr_handle->[HND_WATCHERS]->[$select_index] = undef;
+ }
+
# Shrink the bit vector by chopping zero octets from the
# end. Octets because that's the minimum size of a bit
# vector chunk that Perl manages. Always keep at least one
@@ -2208,6 +2478,10 @@ sub select_pause_write {
);
}
+ if (POE_HAS_EVENT) {
+ $self->[KR_HANDLES]->{$handle}->[HND_WATCHERS]->[VEC_WR]->stop();
+ }
+
return 0;
}
@@ -2232,6 +2506,10 @@ sub select_resume_write {
);
}
+ if (POE_HAS_EVENT) {
+ $self->[KR_HANDLES]->{$handle}->[HND_WATCHERS]->[VEC_WR]->start();
+ }
+
return 1;
}
@@ -2320,8 +2598,7 @@ sub ID_session_to_id {
#==============================================================================
# Extra reference counts, to keep sessions alive when things occur.
# They take session IDs because they may be called from resources at
-# times where the session reference is otherwise unknown. This is
-# experimental until the Tk support is definitely working.
+# times where the session reference is otherwise unknown.
#==============================================================================
sub refcount_increment {
@@ -2514,8 +2791,7 @@ To have POE encapsulate Tk's event loop:
use Tk;
use POE;
-To have POE encapsulate Event's event loop (not yet implemented, since
-Event refuses to compile):
+To have POE encapsulate Event's event loop:
use Event;
use POE;
@@ -2661,12 +2937,6 @@ Exported symbols:
=head1 DESCRIPTION
-The "Event" module documentation is incorrect. I am having trouble
-building Event on FreeBSD or OS/2, so the Event support is only in the
-planning phase. The rest of the code should quickly fall into place
-once Event is working. This time documentation is ahead of
-development! :)
-
POE::Kernel is an event dispatcher and resource watcher. It provides
a consistent interface to the most common event loop features whether
the underlying architecture is its own, Perl/Tk's, or Event's. Other
@@ -2684,7 +2954,8 @@ interact with users through a graphical front end; and Event's loop,
which is written in C for maximum performance.
POE::Kernel uses its own loop by default, but it will adapt to
-whichever external event loop is loaded before it:
+whichever external event loop is loaded before it. POE's functions
+work the same regardless of the underlying event loop.
# Use POE's select loop.
use POE::Kernel;
@@ -2697,6 +2968,9 @@ whichever external event loop is loaded before it:
use Event;
use POE::Kernel;
+Please read about POE::Session's postback() method if you'd like Tk's
+widgets or Event's watchers to fire POE events at your sessions.
+
It also is possible to enable assertions and debugging traces by
defining the constants that enable them before POE::Kernel does.
Every definition follows the form:
@@ -3372,8 +3646,8 @@ spontaneously stop even if they are hold signal name maps. In other
words, signal name maps B<do not> keep sessions alive.
POE does not make Perl's signal handling safe by itself. The Event
-module, however, does implement safe signals, and POE can take
-advantage of this.
+module, however, does implement safe signals, and POE will take
+advantage of them when they're available.
Most signals propagate depth first through the sessions' parent/child
relationships. That is, they are delivered to grandchildren, then
View
114 lib/POE/Session.pm
@@ -1256,13 +1256,112 @@ IDs may collide after at 4.29 billion sessions have been created.
=item create LOTS_OF_STUFF
-POE::Session's create() constructor is preferred over the older new()
-constructor.
+Bundles some states together into a single machine, then starts it
+running.
+
+LOTS_OF_STUFF looks like a hash of parameter name/value pairs, but
+it's really just a list. It's preferred over the older, more DWIMmy
+new() constructor because each kind of parameter is explicitly named,
+and it can therefore unambiguously figure out what it is a program is
+trying to do.
+
+=over 2
+
+=item args => LISTREF
+
+Defines the arguments to give to the machine's _start state. They're
+passed in as @_[ARG0..$#_].
+
+ args => [ 'arg0', 'arg1', 'etc.' ],
+
+=item inline_states => HASHREF
+
+Defines inline coderefs that make up some or all of the session's
+states.
+
+ inline_states =>
+ { _start => sub { print "arg0=$_[ARG0], arg1=$_[ARG1], etc.=$_[ARG2]\n"; }
+ _stop => \&stop_state
+ },
+
+=item object_states => LISTREF
+
+Defines object methods that make up some or all of the session's
+states.
+
+LISTREF is a list of parameter pairs. The first member of each pair
+is an object reference. The second member is either a list reference
+or hash reference. When it's a list reference, the referenced list
+contains methods from the referenced object. The methods define
+states with the same names. When it's a hash reference, the
+referenced hash contains state/method pairs which map state names to
+methods that may have different names.
+
+Perhaps some examples are in order! This one defines two states,
+state_one and state_two, which are implemented as $object->state_one()
+and $object->state_two().
+
+ object_states =>
+ [ $object => [ 'state_one', 'state_two' ],
+ ],
+
+This second example defines two other states, state_five and
+state_six, which are implemented as $object->do_five() and
+$object->do_six().
+
+ object_states =>
+ [ $object => { state_five => 'do_five',
+ state_six => 'do_six',
+ },
+ ],
+
+It's a lot simpler to do than to describe.
+
+=item options => HASHREF
+
+Sets one or more initial session options before starting it. Please
+see the POE::Session option() method for a list of available session
+options and what they do.
+
+ option => { trace => 1, debug => 1 },
+
+=item package_states => LISTREF
+
+Defines package methods that make up some or all of the session's
+states.
+
+LISTREF is virtually identical to the one for object_states, so I'll
+just skip to the examples. Check out object_states' description if
+you'd like more details, replacing "object" and "object reference"
+with "package" and "package name", respectively.
+
+So, here's a package_states invocation that defines two states,
+state_one and state_two, which are implemented as Package->state_one()
+and Package->state_two.
+
+ package_states =>
+ [ Package => [ 'state_one', 'state_two' ],
+ ],
+
+And here's an invocation that defines two other states, state_five and
+state_six, to Package->do_five() and Package->do_six().
+
+ package_states =>
+ [ Package => { state_five => 'do_five',
+ state_six => 'do_six',
+ },
+ ],
+
+Easy-peasy!
+
+=back
=item new LOTS_OF_STUFF
POE::Session's new() constructor is slighly depreciated in favor of
-the newer create() constructor.
+the newer create() constructor. A detailed description of
+POE::Session->new() is not forthcoming, but POE::Session's SYNOPSIS
+briefly touches upon its use.
=item option OPTION_NAME
@@ -1312,9 +1411,12 @@ event at a session whenever it's pressed.
-command => $session->postback( 'ev_counters_begin' )
)->pack;
-While it was originally designed for Tk compatibility, this also can
-be used to post events from Event's watchers. Event currently isn't
-supported yet, because it doesn't seem to compile on FreeBSD or OS/2.
+It can also be used to post events from Event watchers' callbacks.
+
+ Event->flavor
+ ( cb => $session->postback( 'ev_flavor' ),
+ desc => 'post ev_flavor when Event->flavor occurs',
+ );
=back
View
109 lib/POE/Wheel.pm
@@ -18,7 +18,7 @@ __END__
=head1 NAME
-POE::Wheel - POE Protocol Logic Abstraction
+POE::Wheel - high-level protocol logic
=head1 SYNOPSIS
@@ -27,90 +27,81 @@ POE::Wheel - POE Protocol Logic Abstraction
=head1 DESCRIPTION
-Wheels provide standard, reusable protocol logic. They use filters
-and drivers to do the actual work. They are designed to manage the
-resources and objects they are given, so programs generally should not
-bother keeping separate references to them.
+Wheels contain reusable chunks of high-level logic. For example,
+Wheel::FollowTail contains the algorithm for reading data from the end
+of an ever growing file. Their logic is contained in bundles of
+reusable states which they insert into and remove from their owners
+during creation and destruction.
-Wheels mainly work with files. They usually add and remove states to
-handle select events in the sessions that create them. Creating a
-wheel on behalf of another session will not do what you expect.
-Likewise, calling another wheel's methods will do Strange Things,
-because a certain level of privacy was assumed while writing them.
+Giving a wheel to another session will not transfer related states.
+As a result, the original owner will continue receiving a wheel's
+events until it's destroyed.
-=head1 PUBLIC WHEEL METHODS
+=head1 COMMON PUBLIC WHEEL METHODS
-=over 4
+These are the methods that are common to every wheel.
-=item *
+=over 2
-POE::Wheel::new( ... )
+=item new LOTS_OF_STUFF
-The new() method creates and initializes a new wheel. Part of a
-wheel's initialization involves adding states to its parent session
-(the one that is calling the new() method) and registering them with
-the kernel (usually through POE::Kernel::select() calls).
-Instantiating wheels on behalf of other sessions will not work as
-expected, if at all.
+Creates a new wheel, returning its reference. The reference holder
+should keep the wheel reference around until it's ready for the wheel
+to stop.
-Because wheels have wildly different purposes, they tend also to have
-wildly different constructors.
+Every wheel has a different purpose and requires different parameters,
+so LOTS_OF_STUFF will vary from one to the next.
-=item *
+=item DESTROY
-POE::Wheel::DESTROY()
+Perl calls DESTROY when the wheel's reference is relinquished. This
+triggers the wheel's destruction, which releases whatever resources it
+was managing.
-The DESTROY() method removes the wheel's states from its parent
-session and cleans up the wheel's other resources. It's called
-implicitly when the parent session lets go of the wheel's reference.
+When passing resources from one wheel to another, it's important to
+destroy the old wheel before creating the new one. If the hand-off is
+not in this order, the old wheel's destruction will release the
+resource B<after> the new one has started watching it. The new wheel
+will then not be watching the resource, even though it ought to be.
-B<Important note:> When passing a filehandle between wheels, you must
-ensure that the old wheel is destroyed before creating the new one.
-This is necessary because destruction of the old wheel will remove all
-the selects for the filehandle. That will undo any selects set by a
-new wheel, preventing the new wheel from seeing any file activity.
+=item put LIST
-=item *
+Send a LIST of things through the wheel. The LIST may only contain
+one thing, and that's ok. Each thing in the LIST is serialized by the
+wheel's Filter, and then bufferend until the wheel's Driver can flush
+it to a filehandle.
-POE::Wheel::put()
+=item event TYPE => STATE_NAME, ...
-Wheels hide their resources behind a high-level interface. Part of
-that interface is the put() method, which calls Filter and Driver
-put() methods as needed.
+Changes the states that are called when a wheel notices certain types
+of events occurring.
-=item *
+The event() method's parameters are pairs of event TYPEs and the
+STATE_NAMEs to call when they occur. Event TYPEs differ for each
+wheel, and their manpages will discuss them in greater detail.
+STATE_NAMEs may be undef, in which case the wheel will stop invoking a
+state for that TYPE of event.
-POE::Wheel::event(...)
-
-Wheels emit events for different things. The event() method lets a
-session change the events its wheels emit at runtime.
-
-The event() method's parameters are pairs of event types (defined by
-wheels' /^.*State$/ constructor parameters) and events to emit. If
-the event to emit is undef, then the wheel won't emit an event for the
-condition.
-
-For example:
-
- $wheel->event( InputState => 'new_input_state',
- ErrorState => undef,
- FlushedState => 'new_flushed_state',
- );
+ $_[HEAP]->{wheel}->event( InputState => 'new_input_state',
+ ErrorState => undef,
+ FlushedState => 'new_flushed_state',
+ );
=back
=head1 SEE ALSO
-POE::Wheel; POE::Wheel::FollowTail; POE::Wheel::ListenAccept;
-POE::Wheel::ReadWrite; POE::Wheel::SocketFactory
+POE::Wheel::FollowTail; POE::Wheel::ListenAccept;
+POE::Wheel::ReadWrite; POE::Wheel::SocketFactory.
=head1 BUGS
-Wheels are fine for what they do, but they tend to be limiting when
-they're used in more interesting ways.
+Wheels really ought to be replaced with a proper stream-based I/O
+abstraction and POE::Component classes to replace FollowTail and
+SocketFactory.
=head1 AUTHORS & COPYRIGHTS
-Please see the POE manpage.
+Please see the POE manpage for authors and licenses.
=cut
View
35 tests/06_tk.t
@@ -0,0 +1,35 @@
+#!/usr/bin/perl -w
+# $Id$
+
+# Tests FIFO, alarm, select and Tk postback events using Tk's event
+# loop.
+
+use strict;
+use lib qw(./lib ../lib);
+use TestSetup qw(99);
+
+# Turn on all asserts.
+sub POE::Kernel::ASSERT_DEFAULT () { 1 }
+
+# Skip if Tk isn't here.
+BEGIN {
+ eval 'use Tk';
+ unless (exists $INC{'Tk.pm'}) {
+ for (my $test=1; $test <= 1; $test++) {
+ print "skip $test # no Tk support\n";
+ }
+ }
+}
+
+use POE;
+
+# Congratulate ourselves for getting this far.
+print "ok 1\n";
+
+$poe_kernel->run();
+
+# Congratulate ourselves on a job completed, regardless of how well it
+# was done.
+print "ok N\n";
+
+exit;
Please sign in to comment.
Something went wrong with that request. Please try again.