POE::Kernel - an event driven threaded application kernel in Perl |
POE::Kernel - an event driven threaded application kernel in Perl
POE comes with its own event loop, which is based on select()
and
written entirely in Perl. To use it, simply:
use POE;
POE can adapt itself to work with other event loops and I/O multiplex systems. Currently it adapts to Gtk, Tk, Event.pm, or IO::Poll when one of those modules is used before POE::Kernel.
use Gtk; # Or Tk, Event, or IO::Poll; use POE;
or
use POE qw(Loop::Gtk);
or
use POE::Kernel { loop => "Gtk" }; use POE::Session;
Methods to manage the process' global Kernel instance:
# Retrieve the kernel's unique identifier. $kernel_id = $kernel->ID;
# Run the event loop, only returning when it has no more sessions to # dispatch events to. Supports two forms. $poe_kernel->run(); POE::Kernel->run();
FIFO event methods:
# Post an event to an arbitrary session. $kernel->post( $session, $event, @event_args );
# Post an event back to the current session. $kernel->yield( $event, @event_args );
# Call an event handler synchronously. Bypasses POE's event queue # and returns the handler's return value. $handler_result = $kernel->call( $session, $event, @event_args );
Original alarm and delay methods:
# Post an event which will be delivered at a given Unix epoch time. # This clears previous timed events with the same state name. $kernel->alarm( $event, $epoch_time, @event_args );
# Post an additional alarm, leaving existing ones in the queue. $kernel->alarm_add( $event, $epoch_time, @event_args );
# Post an event which will be delivered after a delay, specified in # seconds hence. This clears previous timed events with the same # name. $kernel->delay( $event, $seconds, @event_args );
# Post an additional delay, leaving existing ones in the queue. $kernel->delay_add( $event, $seconds, @event_args );
June 2001 alarm and delay methods:
# Post an event which will be delivered at a given Unix epoch # time. This does not clear previous events with the same name. $alarm_id = $kernel->alarm_set( $event, $epoch_time, @etc );
# Post an event which will be delivered a number of seconds hence. # This does not clear previous events with the same name. $alarm_id = $kernel->delay_set( $event, $seconds_hence, @etc );
# Adjust an existing alarm by a number of seconds. $kernel->alarm_adjust( $alarm_id, $number_of_seconds );
# Refresh an existing delay to a number of seconds in the future. $kernel->delay_adjust( $delay_id, $number_of_seconds_hence );
# Remove a specific alarm, regardless whether it shares a name with # others. $kernel->alarm_remove( $alarm_id );
# Remove all alarms for the current session. $kernel->alarm_remove_all( );
Symbolic name, or session alias methods:
# Set an alias for the current session. $status = $kernel->alias_set( $alias );
# Clear an alias for the current session: $status = $kernel->alias_remove( $alias );
# Resolve an alias into a session reference. Most POE::Kernel # methods do this for you. $session_reference = $kernel->alias_resolve( $alias );
# Resolve a session ID to a session reference. The alias_resolve # method does this as well, but this is faster. $session_reference = $kernel->ID_id_to_session( $session_id );
# Return a session ID for a session reference. It is functionally # equivalent to $session->ID. $session_id = $kernel->ID_session_to_id( $session_reference );
# Return a list of aliases for a session (or the current one, by # default). @aliases = $kernel->alias_list( $session );
Filehandle watcher methods:
# Watch for read readiness on a filehandle. $kernel->select_read( $file_handle, $event, @optional_args );
# Stop watching a filehandle for read-readiness. $kernel->select_read( $file_handle );
# Watch for write readiness on a filehandle. $kernel->select_write( $file_handle, $event, @optional_args );
# Stop watching a filehandle for write-readiness. $kernel->select_write( $file_handle );
# Watch for out-of-bound (expedited) read readiness on a filehandle. $kernel->select_expedite( $file_handle, $event, @optional_args );
# Stop watching a filehandle for out-of-bound data. $kernel->select_expedite( $file_handle );
# Pause and resume write readiness watching. These have lower # overhead than full select_write() calls. $kernel->select_pause_write( $file_handle ); $kernel->select_resume_write( $file_handle );
# Pause and resume read readiness watching. These have lower # overhead than full select_read() calls. $kernel->select_pause_read( $file_handle ); $kernel->select_resume_read( $file_handle );
# Set and/or clear a combination of selects in one call. $kernel->select( $file_handle, $read_event, # or undef to clear it $write_event, # or undef to clear it $expedite_event, # or undef to clear it @optional_args, );
Signal watcher and generator methods:
# Watch for a signal, and generate an event when it arrives. $kernel->sig( $signal_name, $event );
# Stop watching for a signal. $kernel->sig( $signal_name );
# Handle a signal, preventing the program from terminating. $kernel->sig_handled();
# Post a signal through POE rather than through the underlying OS. # This only works within the same process. $kernel->signal( $session, $signal_name, @optional_args );
State (event handler) management methods:
# Remove an existing handler from the current Session. $kernel->state( $event_name );
# Add a new inline handler, or replace an existing one. $kernel->state( $event_name, $code_reference );
# Add a new object or package handler, or replace an existing # one. The object method will be the same as the eventname. $kernel->state( $event_name, $object_ref_or_package_name );
# Add a new object or package handler, or replace an existing # one. The object method may be different from the event name. $kernel->state( $event_name, $object_ref_or_package_name, $method_name );
External reference count methods:
# Increment a session's external reference count. $kernel->refcount_increment( $session_id, $refcount_name );
# Decrement a session's external reference count. $kernel->refcount_decrement( $session_id, $refcount_name );
Kernel data accessors:
# Return a reference to the currently active session, or to the # kernel if called outside any session. $session = $kernel->get_active_session();
# Return the currently active event name, or an empty string if # called outside any event. $event = $kernel->get_active_event();
Exported symbols:
# A reference to the global POE::Kernel instance. $poe_kernel
# Some graphical toolkits (Tk) require at least one active widget in # order to use their event loops. POE allocates a main window so it # can function when using one of these toolkits. $poe_main_window
POE::Kernel is an event application kernel. It provides a lightweight, cooperatively-timesliced process model in addition to the usual basic event loop functions.
POE::Kernel cooperates with three external event loops. This is discussed after the public methods are described.
The POE manpage describes a shortcut for using several POE modules at once. It also includes a complete sample program with a brief walkthrough of its parts.
This section discusses in more detail the POE::Kernel methods that appear in the SYNOPSIS.
These functions manipulate the Kernel itself or retrieve information from it.
ID()
returns the kernel's unique identifier.
print "The currently running Kernel is: $kernel->ID\n";
Every POE::Kernel instance is assigned an ID at birth. This ID tries to differentiate any given instance from all the others, even if they exist on the same machine. The ID is a hash of the machine's name and the kernel's instantiation time and process ID.
~/perl/poe$ perl -wl -MPOE -e 'print $poe_kernel->ID' rocco.homenet-39240c97000001d8
run()
starts the kernel's event loop. It returns only after every
session has stopped, or immediately if no sessions have yet been
started.
#!/usr/bin/perl -w use strict; use POE;
# ... start bootstrap session(s) ...
$poe_kernel->run(); exit;
The run()
method may be called on an instance of POE::Kernel.
my $kernel = POE::Kernel->new(); $kernel->run();
It may also be called as class method.
POE::Kernel->run();
The run()
method does not return a meaningful value.
run_one_timeslice()
checks for new events, which are enqueued, then
dispatches any events that were due at the time it was called. Then
it returns.
It is often used to emulate blocking behavior for procedural code.
my $done = 0;
sub handle_some_event { $done = 1; }
while (not $done) { $kernel->run_one_timeslice(); }
Note: The above example will ``spin'' if POE::Kernel is done but $done isn't set.
stop()
forcibly stops the kernel. The event queue is emptied, all
resources are released, and all sessions are deallocated.
POE::Kernel's run()
method returns as if everything ended normally,
which is a lie.
This function has a couple serious caveats. Use it with caution.
The session running when stop()
is called will not fully destruct
until it returns. If you think about it, there's at least a reference
to the session in its call stack, plus POE::Kernel is holding onto at
least one reference so it can invoke the session.
Sessions are not notified about their destruction. If anything relies on _stop being delivered, it will break and/or leak memory.
stop()
has been added as an experimental function to support
forking child kernels with POE::Wheel::Run. We may remove it without
notice if it becomes really icky. If you have good uses for it,
please mention them on POE's mailing list.
FIFO events are dispatched in the order in which they were queued. These methods queue new FIFO events. A session will not spontaneously stop as long as it has at least one FIFO event in the queue.
post()
enqueues an event to be dispatched to EVENT_NAME in SESSION.
If a PARAMETER_LIST is included, its values will be passed as
arguments to EVENT_NAME's handler.
$_[KERNEL]->post( $session, 'do_this' ); $_[KERNEL]->post( $session, 'do_that', $with_this, $and_this ); $_[KERNEL]->post( $session, 'do_that', @with_these );
POE::Session->create( inline_states => { do_this => sub { print "do_this called with $_[ARG0] and $_[ARG1]\n" }, do_that => sub { print "do_that called with @_[ARG0..$#_]\n" }, } );
The post()
method returns a boolean value indicating whether the event
was enqueued successfully. $! will explain why the post()
failed:
ESRCH: The SESSION did not exist at the time of the post()
call.
Posted events keep both the sending and receiving session alive until they're dispatched.
yield()
enqueues an EVENT_NAME event for the session that calls it.
If a PARAMETER_LIST is included, its values will be passed as
arguments to EVENT_NAME's handler.
yield()
is shorthand for post()
where the event's destination is the
current session.
Events posted with yield()
must propagate through POE's FIFO before
they're dispatched. This effectively yields timeslices to other
sessions which have events enqueued before it.
$kernel->yield( 'do_this' ); $kernel->yield( 'do_that', @with_these );
The previous yield()
calls are equivalent to these post()
calls.
$kernel->post( $session, 'do_this' ); $kernel->post( $session, 'do_that', @with_these );
The yield()
method does not return a meaningful value.
Sometimes it's necessary to invoke an event handler right away, for
example to handle a time-critical external event that would be spoiled
by the time an event propagated through POE's FIFO. The kernel's
call()
method provides for time-critical events.
call()
bypasses the FIFO to call EVENT_NAME in a SESSION, optionally
with values from a PARAMETER_LIST. The values will be passed as
arguments to EVENT_NAME at dispatch time.
call()
returns whatever EVENT_NAME's handler does. The call()
call's
status is returned in $!, which is 0 for success or a nonzero reason
for failure.
$return_value = $kernel->call( $session, 'do_this_now' ); die "could not do_this_now: $!" if $!;
POE uses call()
to dispatch some resource events without FIFO latency.
Filehandle watchers, for example, would continue noticing a handle's
readiness until it was serviced by a handler. This could result in
several redundant readiness events being enqueued before the first one
was dispatched.
Reasons why call()
might fail:
ESRCH: The SESSION did not exist at the time call()
was called.
POE also manages timed events. These are events that should be dispatched after at a certain time or after some time has elapsed. A session will not spontaneously stop as long as it has at least one pending timed event. Alarms and delays always are enqueued for the current session, so a SESSION parameter is not needed.
The kernel manages two types of timed event. Alarms are set to be dispatched at a particular time, and delays are set to go off after a certain interval.
If Time::HiRes is installed, POE::Kernel will use it to increase the
accuracy of timed events. The kernel will use the less accurate
built-in time()
if Time::HiRes isn't available.
If the use of Time::HiRes is not desired, for whatever reason, it can be disabled like so:
sub POE::Kernel::USE_TIME_HIRES () { 0 } use POE;
alarm()
is a single-shot alarm. It first clears all the
timed events destined for EVENT_NAME in the current session. It then
may set a new alarm for EVENT_NAME if EPOCH_TIME is included,
optionally including values from a PARAMETER_LIST.
It is possible to post an alarm with an EPOCH_TIME in the past; in that case, it will be placed towards the front of the event queue.
To clear existing timed events for 'do_this' and set a new alarm with parameters:
$kernel->alarm( 'do_this', $at_this_time, @with_these_parameters );
Clear existing timed events for 'do_that' and set a new alarm without parameters:
$kernel->alarm( 'do_that', $at_this_time );
To clear existing timed events for 'do_the_other_thing' without setting a new delay:
$kernel->alarm( 'do_the_other_thing' );
This method will clear all types of alarms without regard to how they were set.
POE::Kernel's alarm()
returns 0 on success or EINVAL if EVENT_NAME is
not defined.
alarm_add()
sets an additional timed event for EVENT_NAME in the
current session without clearing pending timed events. The new alarm
event will be dispatched no earlier than EPOCH_TIME.
To enqueue additional alarms for 'do_this':
$kernel->alarm_add( 'do_this', $at_this_time, @with_these_parameters ); $kernel->alarm_add( 'do_this', $at_this_time );
Additional alarms can be cleared with POE::Kernel's alarm()
method.
alarm_add()
returns 0 on success or EINVAL if EVENT_NAME or EPOCH_TIME
is undefined.
delay()
is a single-shot delayed event. It first clears all the timed
events destined for EVENT_NAME in the current session. If SECONDS is
included, it will set a new delay for EVENT_NAME to be dispatched
SECONDS seconds hence, optionally including values from a
PARAMETER_LIST. Please note that delay()ed event are placed on the
queue and are thus asynchronous.
delay()
uses whichever time(2)
is available within POE::Kernel. That
may be the more accurate Time::HiRes::time(), or perhaps not.
Regardless, delay()
will do the right thing without sessions testing
for Time::HiRes themselves.
It's possible to post delays with negative SECONDS; in those cases, they will be placed towards the front of the event queue.
To clear existing timed events for 'do_this' and set a new delay with parameters:
$kernel->delay( 'do_this', $after_this_much_time, @with_these );
Clear existing timed events for 'do_that' and set a new delay without parameters:
$kernel->delay( 'do_this', $after_this_much_time );
To clear existing timed events for 'do_the_other_thing' without setting a new delay:
$kernel->delay( 'do_the_other_thing' );
delay()
returns 0 on success or a reason for its failure: EINVAL if
EVENT_NAME is undefined.
delay_add()
sets an additional delay for EVENT_NAME in the current
session without clearing pending timed events. The new delay will be
dispatched no sooner than SECONDS seconds hence.
To enqueue additional delays for 'do_this':
$kernel->delay_add( 'do_this', $after_this_much_time, @with_these ); $kernel->delay_add( 'do_this', $after_this_much_time );
Additional alarms can be cleared with POE::Kernel's delay()
method.
delay_add()
returns 0 on success or a reason for failure: EINVAL if
EVENT_NAME or SECONDS is undefined.
These functions were finally added in June of 2001. They manage alarms and delays by unique IDs, allowing existing alarms to be moved around, added, and removed with greater accuracy than the original interface.
The June 2001 interface provides a different set of functions for alarms, but their underlying semantics are the same. Foremost, they are always set for the current session. That's why they don't require a SESSION parameter.
For more information, see the previous section about the older alarms interface.
alarm()
in that it
lets programs set alarms without clearing them. Furthermore, it
returns an alarm ID which can be used in other new-style alarm
functions.
$alarm_id = $kernel->alarm_set( party => 1000000000 ) $kernel->alarm_remove( $alarm_id );
alarm_set sets $! and returns false if it fails. $! will be EINVAL if one of the function's parameters is bogus.
See: alarm_remove,
# Move the alarm 10 seconds back in time. $new_time = $kernel->alarm_adjust( $alarm_id, -10 );
On failure, it returns false and sets $! to a reason for the failure. That may be EINVAL if the alarm ID or the delta are bad values. It could also be ESRCH if the alarm doesn't exist (perhaps it already was dispatched). $! may also contain EPERM if the alarm doesn't belong to the session trying to adjust it.
alarm_set()
call, or you could hunt
at random for alarms to remove.
Upon success, alarm_remove()
returns something true based on its
context. In a list context, it returns three things: The removed
alarm's event name, its scheduled time, and a reference to the list of
parameters that were included with it. This is all you need to
re-schedule the alarm later.
my @old_alarm_list = $kernel->alarm_remove( $alarm_id ); if (@old_alarm_list) { print "Old alarm event name: $old_alarm_list[0]\n"; print "Old alarm time : $old_alarm_list[1]\n"; print "Old alarm parameters: @{$old_alarm_list[2]}\n"; } else { print "Could not remove alarm $alarm_id: $!\n"; }
In a scalar context, it returns a reference to a list of the three things above.
my $old_alarm_scalar = $kernel->alarm_remove( $alarm_id ); if ($old_alarm_scalar) { print "Old alarm event name: $old_alarm_scalar->[0]\n"; print "Old alarm time : $old_alarm_scalar->[1]\n"; print "Old alarm parameters: @{$old_alarm_scalar->[2]}\n"; } else { print "Could not remove alarm $alarm_id: $!\n"; }
Upon failure, it returns false and sets $! to the reason it failed. $! may be EINVAL if the alarm ID is undefined, or it could be ESRCH if no alarm was found by that ID. It may also be EPERM if some other session owns that alarm.
alarm_remove_all()
removes all alarms from the current session. It
obviates the need for queue_peek_alarms(), which has been deprecated.
This function takes no arguments. In scalar context, it returns a reference to a list of alarms that were removed. In list context, it returns the list of removed alarms themselves.
Each removed alarm follows the same format as in alarm_remove().
my @removed_alarms = $kernel->alarm_remove_all( ); foreach my $alarm (@removed_alarms) { print "-----\n"; print "Removed alarm event name: $alarm->[0]\n"; print "Removed alarm time : $alarm->[1]\n"; print "Removed alarm parameters: @{$alarm->[2]}\n"; }
my $removed_alarms = $kernel->alarm_remove_all( ); foreach my $alarm (@$removed_alarms) { ...; }
delay_set()
is a handy way to set alarms for a number of seconds
hence. Its EVENT_NAME and PARAMETER_LIST are the same as for
alarm_set, and it returns the same things as alarm_set, both as a
result of success and of failure.
It's only difference is that SECONDS is added to the current time to
get the time the delay will be dispatched. It uses whichever time()
POE::Kernel does, which may be Time::HiRes' high-resolution timer, if
that's available.
# Refresh a delay for 10 seconds into the future. $new_time = $kernel->delay_adjust( $delay_id, 10 );
On failure, it returns false and sets $! to a reason for the failure. That may be EINVAL if the delay ID or the seconds are bad values. It could also be ESRCH if the delay doesn't exist (perhaps it already was dispatched). $! may also contain EPERM if the delay doesn't belong to the session trying to adjust it.
Every session is given a unique ID at birth. This ID combined with the kernel's own ID can uniquely identify a particular session anywhere in the world.
Sessions can also use the kernel's alias dictionary to give themselves symbolic names. Once a session has a name, it may be referred to by that name wherever a kernel method expects a session reference or ID.
Sessions with aliases are treated as daemons within the current program. They are kept alive even without other things to do. It's assumed that they will receive events from some other session.
Aliases are passive work. A session with just an alias to keep it alive can't do anything if there isn't some other active session around to send it messages. POE knows this, and it will gladly kill off aliased sessions if everything has become idle. This prevents ``zombie'' sessions from keeping an otherwise dead program running.
alias_set()
sets an ALIAS for the current session. The ALIAS may then
be used nearly everywhere a session reference or ID is expected.
Sessions may have more than one alias, and each must be defined in a
separate alias_set()
call.
$kernel->alias_set( 'ishmael' ); # o/` A name I call myself. o/`
Aliases allow sessions to stay alive even when they may have nothing to do. Sessions can use them to become autonomous services that other sessions refer to by name.
Aliases keep sessions alive as long as the program has work to do. If a program's remaining sessions are being kept alive solely by aliases, they will be terminated. This prevents running, the remaining sessions will be terminated. This prevents deadlocks where two or more sessions are idly waiting for events from each other.
$kernel->alias_set( 'httpd' ); $kernel->post( httpd => set_handler => $uri_regexp => 'callback_event' );
alias_set()
returns 0 on success, or a nonzero failure indicator:
alias_remove()
clears an existing ALIAS from the current session. The
ALIAS will no longer refer to this session, and some other session may
claim it.
$kernel->alias_remove( 'Shirley' ); # And don't call me Shirley.
If a session is only being kept alive by its aliases, it will stop once they are removed.
alias_remove()
returns 0 on success or a reason for its failure:
ESRCH: The Kernel's dictionary does not include the ALIAS being removed.
EPERM: ALIAS belongs to some other session, and the current one does not have the authority to clear it.
alias_resolve()
returns a session reference corresponding to its given
ALIAS. This method has been overloaded over time, and now ALIAS may
be several things:
An alias:
$session_reference = $kernel->alias_resolve( 'irc_component' );
A stringified session reference. This is a form of weak reference:
$blessed_session_reference = $kernel->alias_resolve( "$stringified_one" );
A numeric session ID:
$session_reference = $kernel->alias_resolve( $session_id );
alias_resolve()
returns undef upon failure, setting $! to explain the
error:
ESRCH: The Kernel's dictionary does not include ALIAS.
These functions work directly with session IDs. They are faster than
alias_resolve()
in the specific cases where they're useful.
ID_id_to_session()
returns a session reference for a given numeric
session ID.
$session_reference = ID_id_to_session( $session_id );
It returns undef if a lookup fails, and it sets $! to explain why the lookup failed:
ESRCH: The session ID does not refer to a running session.
alias_list()
returns a list of alias(es)
associated with a SESSION, or
with the current session if a SESSION is omitted.
SESSION may be a session reference (either blessed or stringified), a session ID, or a session alias. It will be resolved into a session reference internally, and that will be used to locate the session's aliases.
alias_list()
returns a list of aliases associated with the session.
It returns an empty list if none were found.
ID_session_to_id()
returns the ID associated with a session reference.
This is virtually identical to SESSION_REFERENCE->ID, except that
SESSION_REFERENCE may have been stringified. For example, this will
work, provided that the session exists:
$session_id = ID_session_to_id( "$session_reference" );
ID_session_to_id()
returns undef if a lookup fails, and it sets $! to
explain why the lookup failed.
ESRCH: The session reference does not describe a session which is currently running.
Filehandle watchers emit events when files become available to be read from or written to. As of POE 0.1702 these events are queued along with all the rest. They are no longer ``synchronous'' or ``immediate''.
Filehandle watchers are often called ``selects'' in POE because they
were originally implemented with the select(2)
I/O multiplexing
function.
File I/O event handlers are expected to interact with filehandles in a
way that causes them to stop being ready. For example, a
select_read()
event handler should try to read as much data from a
filehandle as it can. The filehandle will stop being ready for
reading only when all its data has been read out.
Select events include two parameters.
ARG0
holds the handle of the file that is ready.
ARG1
contains 0, 1, or 2 to indicate whether the filehandle is
ready for reading, writing, or out-of-band reading (otherwise knows as
``expedited'' or ``exception'').
ARG2..$#_
contain optional additional parameters passed to
POE::Kernel's various I/O watcher methods.
ARG0
and the other event handler parameter constants is covered in
the POE::Session manpage.
Sessions will not stop if they have active filehandle watchers.
select_read()
starts or stops the kernel from watching to see if a
filehandle can be read from. An EVENT_NAME event will be enqueued
whenever the filehandle has data to be read.
The optional ADDITIONAL_PARAMETERS will be passed to the input
callback after the usual I/O parameters.
# Emit 'do_a_read' event whenever $filehandle has data to be read. $kernel->select_read( $filehandle, 'do_a_read' );
# Stop watching for data to be read from $filehandle. $kernel->select_read( $filehandle );
select_read()
does not return a meaningful value.
select_write()
starts or stops the kernel from watching to see if a
filehandle can be written to. An EVENT_NAME event will be enqueued
whenever it is possible to write data to the filehandle. The optional
ADDITIONAL_PARAMETERS will be passed to the input callback after the
usual I/O parameters.
# Emit 'flush_data' whenever $filehandle can be written to. $kernel->select_writ( $filehandle, 'flush_data' );
# Stop watching for opportunities to write to $filehandle. $kernel->select_write( $filehandle );
select_write()
does not return a meaningful value.
select_expedite()
starts or stops the kernel from watching to see if a
filehandle can be read from ``out-of-band''. This is most useful for
datagram sockets where an out-of-band condition is meaningful. In
most cases it can be ignored. An EVENT_NAME event will be enqueued
whatever the filehandle can be read from out-of-band. The optional
ADDITIONAL_PARAMETERS will be passed to the input callback after the
usual I/O parameters.
Out of band data is called ``expedited'' because it's often available
ahead of a file or socket's normal data. It's also used in socket
operations such as connect()
to signal an exception.
# Emit 'do_an_oob_read' whenever $filehandle has OOB data to be read. $kernel->select_expedite( $filehandle, 'do_an_oob_read' );
# Stop watching for OOB data on the $filehandle. $kernel->select_expedite( $filehandle );
select_expedite()
does not return a meaningful value.
select_pause_read()
and select_pause_write()
temporarily pause events
that are generated when a FILE_HANDLE can be read from or written to,
respectively.
select_resume_read()
and select_resume_write()
turn events back on.
These functions are more efficient than select_read()
and
select_write()
because they don't perform full resource management
within POE::Kernel.
Pause and resume a filehandle's readable events:
$kernel->select_pause_read( $filehandle ); $kernel->select_resume_read( $filehandle );
Pause and resume a filehandle's writable events:
$kernel->select_pause_write( $filehandle ); $kernel->select_resume_write( $filehandle );
These methods don't return meaningful values.
select()
method alters a filehandle's read, write, and
expedite selects at the same time. It's one method call more
expensive than doing the same thing manually, but it's more convenient
to code.
Defined event names set or change the events that will be emitted when the filehandle becomes ready. Undefined names clear those aspects of the watcher, stopping it from generating those types of events.
This sets all three types of events at once.
$kernel->select( $filehandle, 'do_read', 'do_flush', 'do_read_oob' );
This clears all three types of events at once. If this filehandle is the only thing keeping a session alive, then clearing its selects will stop the session.
$kernel->select( $filehandle );
This sets up a filehandle for read-only operation.
$kernel->select( $filehandle, 'do_read', undef, 'do_read_oob' );
This sets up a filehandle for write-only operation.
$kernel->select( $filehandle, undef, 'do_flush' );
This method does not return a meaningful value.
First some general notes about signal events and handling them.
Sessions only receive signal events that have been registered with
sig()
. In the past, they also would receive ``_signal'' events, but
this is no longer the case.
Child sessions are the ones created by another session. Signals are dispatched to children before their parents. By the time a parent receives a signal, all its children have already had a chance to handle it.
The Kernel acts as the parent of every session. Signaling it causes every interested session to receive the signal. This is how operating system signals are implemented.
It is possible to post signals in POE that don't exist in the operating system. They are placed into the queue as if they came from the operating system, but they are not limited to signals recognized by kill(). POE uses a few of these ``fictitious'' signals to notify programs about certain global events.
It is also possible to post signals to particular sessions. In those cases, POE only calls the handlers for that session and its children.
Some signals are considered terminal. They will terminate the sessions they touch if they are not marked as ``handled''. A signal is considered handled (or not) for all the sessions it touches. Therefore, one session can handle a signal for the entire program. All the other sessions will still receive notice of the signal, but none of them will be terminated if it's handled by the time it's fully dispatched.
The sig_handled()
method is used to mark signals as handled.
POE also recognizes ``non-maskable'' signals. These will terminate a program even when they are handled. For example, POE sends a non-maskable UIDESTROY signal to indicate when the program's user interface has been shut down.
Signal handling in older versions of Perl is not safe by itself. POE
is written to avoid as many signal problems as it can, but they still
may occur. SIGCHLD is a special exception: POE polls for child
process exits using waitpid()
instead of a signal handler. Spawning
child processes should be completely safe.
Here is a summary of the three signal levels.
sig_handled()
, however, then the program will
continue to live.
The terminal system signals are: HUP, INT, KILL, QUIT and TERM. There are two terminal fictitious signals, IDLE and DIE. IDLE is used to notify leftover sessions when a program has run out of things to do. DIE is used to notify sessions that an exception has occurred.
POE's automatic exception handling can be turned off by setting the
CATCH_EXCEPTIONS
constant subroutine in POE::Kernel
to 0 like so:
sub POE::Kernel::CATCH_EXCEPTIONS () { 0 }
ZOMBIE is fired if the terminal signal IDLE did not wake anything up. It is used to stop the remaining ``zombie'' sessions so that an inactive program will exit cleanly.
UIDESTROY is fired when a main or top-level user interface widget has been destroyed. It is used to shut down programs when their interfaces have been closed.
Some system signals are handled specially. These are SIGCHLD/SIGCLD, SIGPIPE, and SIGWINCH.
The SIGCHLD/SIGCLD signal event is delivered to handlers registered by
both the sig()
method and sig_child().
The SIGCHLD/SIGCHLD signal event comes with three custom parameters.
ARG0
contains 'CHLD', even if SIGCLD was caught.
ARG1
contains the ID of the exiting child process.
ARG2
contains the return value from $?
.
SIGPIPE is mostly moot since POE will usually return an EPIPE error instead.
The Event module also claims to handle signals safely. Its signal handlers are written in C++, and they can do more interesting things than plain Perl handlers.
Finally, here are POE::Kernel's signal methods themselves.
sig()
registers or unregisters a EVENT_NAME event for a particular
SIGNAL_NAME. Signal names are the same as %SIG uses, with one
exception: CLD is always delivered as CHLD, so handling CHLD will
always do the right thing.
$kernel->sig( INT => 'event_sigint' );
To unregister a signal handler, just leave off the event it should generate, or pass it in undefined.
$kernel->sig( 'INT' ); $kernel->sig( INT => undef );
It's possible to register events for signals that the operating system
will never generate. These ``fictitious'' signals can however be
generated through POE's signal()
method instead of kill(2).
The sig()
method does not return a meaningful value.
sig_chld()
is a convenient way to deliver an event (EVENT_NAME) with
some OPTIONAL_ARGS only when a child process specified by PID has been
reaped. Omit EVENT_NAME and OPTIONAL_ARGS to stop waiting for a given
PID.
sig_child()
differs from using sig()
to handle CHLD:
sig_child()
notifies a session when a particular process ID has been
reaped. sig(CHLD, EVENT) notifies a session for every SIGCHLD
delivered regardless of the PID.
sig_child()
keeps a session alive until the given PID has been reaped.
The watcher is automatically removed when the event for the given
process ID has been delivered. sig()
does not keep a session alive.
sig_handled()
informs POE that a signal was handled. It is only
meaningful within event handlers that are triggered by signals.
signal()
posts a signal event to a particular session (and its
children) through POE::Kernel rather than actually signaling the
process through the operating system. Because it injects signal
events directly into POE's Kernel, its SIGNAL_NAME doesn't have to be
one the operating system understands.
For example, this posts a fictitious signal to some session:
$kernel->signal( $session, 'DIEDIEDIE' );
POE::Kernel's signal()
method doesn't return a meaningful value.
# Fire a UIDESTROY signal when this top-level window is deleted. $heap->{gtk_toplevel_window} = Gtk::Window->new('toplevel'); $kernel->signal_ui_destroy( $heap->{gtk_toplevel_window} );
the POE::Session manpage also discusses signal events.
These methods manage sessions.
detach_child()
returns 1
on success. If it fails, it returns false and sets $! to one of the
following values:
ESRCH indicates that SESSION is not a valid session.
EPERM indicates that SESSION is not a child of the current session.
This call may generate corresponding _parent and/or _child events. See PREDEFINED EVENT NAMES in POE::Session's manpage for more information about _parent and _child events.
detach_child()
returns 1 on success. If it fails, it
returns 0 and sets $! to EPERM to indicate that the current session
already is a child of POE::Kernel and cannot be detached from it.
This call may generate corresponding _parent and/or _child events. See PREDEFINED EVENT NAMES in POE::Session's manpage for more information about _parent and _child events.
State management methods let sessions hot swap their event handlers. It would be rude to change another session's handlers, so these methods only affect the current one.
state()
can add, remove, or update an
event handler in the current session.
The simplest form of state()
call deletes a handler for an event.
This example removes the current session's ``do_this'' handler.
$kernel->state( 'do_this' );
The next form assigns a coderef to an event. If the event is already being handled, its old handler will be discarded. Any events already in POE's queue will be dispatched to the new handler.
Plain coderef handlers are also called ``inline'' handlers because they originally were defined with inline anonymous subs.
$kernel->state( 'do_this', \&this_does_it );
The third and fourth forms register or replace a handler with an object method. These handlers are called ``object states'' or object handlers. The third form maps an event to a method with the same name.
$kernel->state( 'do_this', $with_this_object );
The fourth form maps an event to a method with a different name.
$kernel->state( 'do_this', $with_this_object, $calling_this_method );
The fifth and sixth forms register or replace a handler with a package method. These handlers are called ``package states'' or package handlers. The fifth form maps an event to a function with the same name.
$kernel->state( 'do_this', $with_this_package );
The sixth form maps an event to a function with a different name.
$kernel->state( 'do_this', $with_this_package, $calling_this_function );
POE::Kernel's state()
method returns 0 on success or a nonzero code
explaining why it failed:
ESRCH: The Kernel doesn't recognize the currently active session.
This happens when state()
is called when no session is active.
The Kernel internally maintains reference counts on sessions that have active resource watchers. The reference counts are used to ensure that a session doesn't self-destruct while it's doing something important.
POE::Kernel's external reference counting methods let resource watcher developers manage their own reference counts. This lets the watchers keep their sessions alive when necessary.
refcount_increment()
increments a session's external reference count,
returning the reference count after the increment.
refcount_decrement()
decrements a session's external reference count,
returning the reference count after the decrement.
$new_count = $kernel->refcount_increment( $session_id, 'thingy' ); $new_count = $kernel->refcount_decrement( $session_id, 'thingy' );
Both methods return undef on failure and set $! to explain the failure.
ESRCH: There is no session SESSION_ID currently active.
The Kernel keeps some information which can be useful to other libraries. These functions provide a consistent, safe interface to the Kernel's internal data.
get_active_session()
returns a reference to the session which is
currently running. It returns a reference to the Kernel itself if no
other session is running. This is one of the times where the Kernel
pretends it's just another session.
my $active_session = $poe_kernel->get_active_session();
This is a convenient way for procedurally called libraries to get a
reference to the current session. Otherwise a programmer would
tediously need to include SESSION
with every call.
get_active_event()
returns the currently active event name or an
empty string if called outside any event.
POE::Kernel supports any number of event loops. Four are included in the base distribution, and others are available on the CPAN. POE's public interfaces remain the same regardless of the event loop being used.
There are three ways to load an alternate event loop. The simplest is to load the event loop before loading POE::Kernel. Remember that POE loads POE::Kernel internally.
use Gtk; use POE;
POE::Kernel detects that Gtk has been loaded, and it loads the appropriate internal code to use it.
You can also specify which loop to load directly. Event loop bridges are named ``POE::Loop::$loop_module'', where $loop_module is the name of the module, with ``::'' translated to underscores. For example:
use POE qw( Loop::Event_Lib );
would load POE::Loop::Event_Lib (which may or may not be on CPAN).
If you'd rather use POE::Kernel directly, it has a different import syntax:
use POE::Kernel { loop => "Tk" };
The four event loops included in POE's distribution:
POE's default select()
loop. It is included so at least something
will work on any given platform.
Event.pm. This provides compatibility with other modules requiring Event's loop. It may also introduce safe signals in versions of Perl prior to 5.8, should you need them.
Gtk and Tk event loops. These are included to support graphical
toolkits. Others are on the CPAN, including Gtk2 and hopefully WxPerl
soon. When using Tk with POE, POE supplies an already-created
$poe_main_window variable to use for your main window. Calling Tk's
MainWindow->new()
often has an undesired outcome.
IO::Poll. This is potentially more efficient than POE's default
select()
code in large scale clients and servers.
Many external event loops expect plain coderefs as callbacks.
POE::Session has postback()
and callback()
methods that create
callbacks suitable for external event loops. In turn, they post()
or
call()
POE event handlers.
POE::Kernel contains a number of assertion and tracing flags. They were originally created to debug POE::Kernel itself, but they are also useful for tracking down other problems.
Assertions are the quiet ones. They only create output when something catastrophic has happened. That output is almost always fatal. They are mainly used to check the sanity of POE's internal data structures.
Traces are assertions' annoying cousins. They noisily report on the status of a running POE::Kernel instance, but they are never fatal.
Assertions and traces incur performance penalties when enabled. It's probably a bad idea to enable them in live systems. They are all disabled by default.
Assertion and tracing flags can be defined before POE::Kernel is first used.
# Turn on everything. sub POE::Kernel::ASSERT_DEFAULT () { 1 } sub POE::Kernel::TRACE_DEFAULT () { 1 } use POE; # Includes POE::Kernel
It is also possible to enable them using shell environment variables. The environment variables follow the same names as the constants in this section, but ``POE_'' is prepended to them.
POE_ASSERT_DEFAULT=1 POE_TRACE_DEFAULT=1 ./my_poe_program
Assertions will be discussed first.
Then there are the trace options.
TRACE_STATISTICS enables runtime gathering and reporting of various
performance metrics within a POE program. Some statistics include how
much time is spent processing event callbacks, time spent in POE's
dispatcher, and the time spent waiting for an event. A report is
displayed just before run()
returns, and the data can be retrieved at
any time using stat_getdata().
stat_getdata()
returns a hash of various statistics and their values
The statistics are calculated using a sliding window and vary over
time as a program runs.
run()
returns, or at
any time via stat_show_profile().
POE::Kernel exports two symbols for your coding enjoyment:
$poe_kernel
and $poe_main_window
. POE::Kernel is implicitly
used by POE itself, so using POE gets you POE::Kernel (and its
exports) for free.
For example, programs can't call the Kernel's run()
method without a
reference, and they normally don't get references to the Kernel
without being in a running event handler. This gets them going:
$poe_kernel->run();
It's also handy from within libraries, but event handlers themselves
receive KERNEL
parameters and don't need to use $poe_kernel
directly.
$poe_main_window
. For all other toolkits, this
exported variable is undefined.
Programs are free to use $poe_main_window
for whatever needs. They
may even assign a widget to it when using toolkits that don't require
an initial widget (Gtk for now).
$poe_main_window is undefined if a graphical toolkit isn't used.
See: signal_ui_destroy
The SEE ALSO section in POE contains a table of contents covering the entire POE distribution.
There is no mechanism in place to prevent external reference count names from clashing.
Probably lots more.
Please see POE for more information about authors and contributors.
POE::Kernel - an event driven threaded application kernel in Perl |