The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

POE - Perl Object Environment

DESCRIPTION

POE is a high-level, object oriented framework for writing event driven programs. Being designed to take care of most of the fiddly mucking about with select and sockets, it especially lends itself to multi-session servers and clients.

POE comes with seventeen complete, commented sample/test programs in the distribution's tests subdirectory. Please see the [unknown tag L] Tests and Example Programs section near the end of this file for a brief explanation of each. tests/tutorial-chat.perl, in particular, is a quick introduction to using POE.

POE's original purpose was to provide a runtime "agent space" in which objects ('bots) and users can roam and interact. However, because POE's events framework is useful by itself, it has been released without objects

1 Design Goals

The design goals are mostly fluff. You won't learn how to use POE by reading them.

1 Simplicity

POE is based on very simple ideas. Events, sessions to receive them, functions to manipulate resources. Each feature is designed for ease of use, mainly because the author intends to use them a lot.

Most of the subsequent design goals overlap with POE's simplicity.

2 Layers

POE is separated into distinct layers. Each layer adds features over previous layers without depending on subsequent ones. This allows developers to use subsets of POE without including unnecessary code.

3 Abstraction

POE hides most of the tedious, redundant details of event-driven programming behind high-level, functional interfaces. Some of the interfaces are abstracted even further in other POE layers. This lets developers pick the level of abstraction they're comfortable with.

4 Flexibility

POE avoids assumptions and artificial limitations wherever possible. Previous versions didn't, and it caused the author a lot of grief.

5 Invisibility

POE provides its services cleanly and quietly. POE objects are designed to plug themselves into the events layer when they are created. They quietly perform their jobs while they exist, and they cleanly unplug themselves when they are destroyed. POE tracks its own references and collects its own garbage.

6 Portability

Please see the README for the latest portability information.

Quick Start / Tutorial

This section's not written yet. The tests/tutorial-chat.perl program is a very simple, working example. It contains lots of narrative and comments. The other example programs show how to use POE for other things.

Events Layer

POE's events layer is implemented in two classes: POE::Kernel and POE::Session. Kernel contains the event queue and resource manager. Session instances are bundles of event handlers, similar to operating system processes or threads.

Sessions may also be thought of as state machines. When considering POE from this point of view, event handlers become states in the machine, and events signal transitions from one state to another. The event-driven nature of POE's state machines allows them to cooperatively multi-thread within themselves and multitask with each-other.

Consider this simple Perl code, for example:

  my $i = 0;
  while ($i < 100) {
    print $i++, "\n";
  }
  exit;

It can be represented as a finite automata (state machine) consisting of four states:

  1. Set $i to 0, and go to state 2.
  2. Test $i < 100.  If true, go to state 3; otherwise go to state 4.
  3. Display $i, increment it, and go to state 2.
  4. Exit.

These simplified event handlers represent the previous state machine:

  _start  => sub { post(1); },
  1       => sub { $i = 1; post(2); },
  2       => sub { if ($i < 100) { post(3); } else { post(4); } },
  3       => sub { print $i++, "\n"; post(2); },
  4       => sub { }, # do nothing, and the session stops

To be sure, this is a lot slower than the original procedural code, but it has the benefit of cooperating with itself and other sessions within the same program.

1 Sessions

Session constructors have changed in version 0.06. Processes no longer support multiple kernels. This obsoleted the $kernel parameter for session constructors, and it was removed.

Sessions are POE's basic, self-contained units of execution. They are equivalent to processes or threads in real operating systems. Sessions register themselves with POE's kernel when they are created. The kernel manages their resources until they stop.

1 Session Methods

These are POE::Session's public methods.

1 POE::Session::debug(...)

POE::Session::option() toggles the session's options flags. This replaces $_[HEAP]->{'_debug'} in version 0.06. Currently, options are mostly for debugging:

  • trace - Boolean. Trace events as they arrive at the session.

  • default - Boolean. Note events that can't be handled.

  $_[SESSION]->option( trace => 1, default => 0 );

Boolean values may be either 1, 0, 'on', 'off', 'yes' or 'no'.

POE::Session::option() only changes the options that are present as parameters. All other options are left alone.

2 Session Types

There currently are four kinds of sessions: Inline, Object, Package and Hybrid. Each type provides a way to build sessions from different kinds of event handlers, and each has a different constructor syntax.

1 Inline Sessions

Inline sessions consist of event names, each followed by a reference to the code that handles the event.

  new POE::Session(
        name1 => \&name1_handler, # handles the "name1" event
        name2 => sub { ... },     # handles the "name2" event
        \@start_args,             # ARG0..ARGn for the _start event
  );

Events delivered to inline sessions have undef in their OBJECT parameters.

2 Object Sessions

Object sessions consist of blessed object references, each followed by a reference to an array of events that the object will handle. Each object must have methods named after the events it handles.

Remember that => stringifies its left value. Using it for object sessions will cause object references to lose their blessing.

  my $object1 = new SomeObject(...);
  my $object2 = new SomeOtherObject(...);
  new POE::Session(
        $object1, [ 'name1', 'name2' ],
        $object2, [ 'name3', 'name4' ],
        \@start_args,
  );

Events delivered to object sessions have a reference to the object in their OBJECT parameters. sessions.

3 Package Sessions

Package sessions are similar to object sessions, but they use package names instead of object references. The => operator works for this one. Event handlers are called as package

  new POE::Session(
        $package, [ 'name1', # $package->'name1' handles "name1"
                    'name2'  # $package->'name2' handles "name2"
                  ],
        \@start_args,
  );

Events delivered to package sessions have the package name in their OBJECT parameters.

4 Hybrid Sessions

Hybrid objects contain a mix of available event handlers.

  my $object1 = new SomeObject(...);
  my $object2 = new SomeOtherObject(...);
  new POE::Session(
        \@start_args,
        $object1, [ 'name11', 'name12' ],
        'name01' => sub { ... },
        'name02' => sub { ... },
        $object2, [ 'name21', 'name22' ],
        'name03' => sub { ... },
        'name04' => sub { ... },
        $package3, [ 'name31', 'name32' ],
  );

Events delivered to hybrid sessions have various values for OBJECT. The particular value depends on how the event handler was registered.

2 About Event Handlers

Event handlers are evaluated in a scalar context. Handlers may use array references if they need to return multiple values. Return values are used by signal handlers, to tell the kernel whether or not the signal was handled. They also are returned to the caller if an event handle is called directly. See _signal or POE::Kernel::call for more on that.

If an event handler returns a reference to a POE object, it will be stringified. This is done to prevent "blessing bleed" (see the Changes file) from interfering with POE's garbage collection. The code that checks for POE objects does not look inside data passed by reference-- it's just there to catch accidents, like this example:

  sub stop_handler {
    delete $_[HEAP]->{'readwrite wheel'};
    # reference to the readwrite wheel is implicitly returned
  }

That accidentally returns a reference to a POE::Wheel::ReadWrite object. If the reference was not stringified, it would delay the wheel's destruction until after the session stopped. The wheel would try to remove its states from the nonexistent session, and a runtime error would occur.

3 Kernel

The POE::Kernel class contains POE's event loop and functions to manage events and other resources.

1 Kernel Management

Kernel management has changed in version 0.06. Support for multiple kernels has been removed, enabling better signal support in 0.06 and simplifying threads support in the future. As a result, explicitly creating kernels has been deemed silly and is now handled by POE::Kernel the first time it's used. The new() method still exists, and nothing will break if it's called, but it's just not necessary now.

The program's single kernel is automatically initialized the first time POE::Kernel is used. POE::Kernel exports $poe_kernel, a reference to the global kernel, each time it's used.

1 POE::Kernel::run

This starts the kernel's event loop. It will not return until all the sessions it manages end. There are two corollaries: If there are no sessions, it will end immediately; and if sessions never exit, neither will run().

  # includes POE::Kernel and POE::Session by default
  use POE;

  # set up initial sessions here

  $poe_kernel->run();
  exit;
2 Events

Events inform sessions when it is time to do something. In turn, sessions invoke their corresponding handlers. For example, when a session receives a _start event, it invokes its event handler named '_start'.

There are two ways to send events to sessions. Events can be posted, in which case the kernel queues them and dispatches them in FIFO order. Event handlers can also be called immediately, bypassing the queue. Immediate calls can be useful for critical code or events that should not be delayed. POE's wheels use call to minimize event latency.

1 Event Management Functions

These functions manage events. No, really!

1 Kernel::post

Kernel::post places an event in the kernel's queue. The kernel dispatches queued events in FIFO order. Event handlers are evaluated in a scalar context, and their return values are discarded.

  $kernel->post($destination_session, $event_name, @args);

Whatever the $event_name handler returns is lost. If a return value is important, there are two ways to get it. First, have the $destination_session post a return event to $_[FROM]; second, use Kernel::call.

2 Kernel::yield

Kernel::yield is an alias for posting an event to the current session. It does not operate like yield in real thread libraries (swapping stacks in plain Perl is a hard thing to do).

Kernel::yield does not need a $destination_session parameter because the kernel already knows which session is running. Event handlers are evaluated in a scalar context, and their return values are discarded.

  $kernel->yield($event_name, @args);
3 Kernel::call

Kernel::call immediately dispatches an event to its session. Event handlers are evaluated in a scalar context, and call returns their return values.

  my $handler_return_value =
         $kernel->call( $destination_session,
                        $event_name, @args
                      );

Kernel::call can exercise bugs in Perl and/or the C library (we're not sure which just yet). This only seems to occur while destroying an event handler from another event handler that is directly called by the first one. Until this is fixed, if your POE program dumps core with a SIGSEGV, change your Kernel::call invocations to Kernel::post and they should go away.

2 Event Handler Parameters

Event handler parameters have changed in version 0.06. Prior to version 0.06, inline handlers received different parameters than object and package handlers. The call signatures have been unified in version 0.06. This breaks programs written with POE 0.05 or earlier.

To prevent future breakage, POE::Session now exports constants for parameters' offsets into @_. Programs that use them guaranteed not to break if existing parameters are rearranged or new ones are added. If parameters are removed in the future, programs will break at compile time instead of silently failing during runtime.

Parameters may be used discretely as $_[KERNEL]. If several parameters are needed multiple times, it may be faster to assign them to lexicals all at once with an array slice:

  my ($kernel, $operation, $errnum, $errstr) =
     @_[KERNEL, ARG0, ARG1, ARG2];

The parameter constants are:

1 OBJECT

$_[OBJECT]'s value depends on the type of event handler. For inline handlers, it is undef. For object handlers, it contains a reference to the object that owns the handler. For package handlers, it contains the name of the package.

2 KERNEL

$_[KERNEL] is a reference to the kernel that is managing this session. It is provided in case the event handler was defined in a scope where $poe_kernel is unavailable.

3 SESSION

$_[SESSION] is a reference to the current session object. Direct manipulation of its contents and methods is not supported. It is included for use as a parameter to Kernel methods.

4 HEAP

$_[HEAP] is a reference to a hash set aside for sessions to store global data. Information stored in the heap will be available to all the event handlers in the session, and it will persist until the session stops.

POE will delete the heap from its internal structures, but developers are expected to remove anything from it that would leak memory.

Support for using the HEAP (formerly known as $me or $namespace) as an alias for SESSION in Kernel method calls is depreciated in version 0.06, and it will be removed in version 0.07.

5 FROM

$_[FROM] is a reference to the session that sent the event. It is suitable as a destination for responses. If using call in both directions, be aware that POE does not prevent deep recursion.

6 ARG0..ARG9

@_[ARG0 .. ARG9] are the first ten elements of @args as passed to post, call, yield or alarm. If more than ten items are needed, they may be referenced as $_[ARG9+1..], but it would be more efficient to pass them all as an array reference in ARG0.

3 Predefined Events & Parameters

POE reserves some event names for internal and standard use. All its predefined events begin with an underscore, and future ones will too. It may be wise to avoid leading underscores in your own event names.

Every predefined event is accompanied by OBJECT, KERNEL, SESSION, HEAP and FROM.

1 _start

Sessions register themselves with the kernel when they are created. Kernels dispatch _start events to sessions when the registration is complete. Sessions may then begin interacting with the kernel in a sane way.

POE requires every session to have a _start handler, otherwise how would they know when it's okay to start?

FROM contains a reference to the session that started this session.

ARG0..ARG9 contain arguments as they were given to the session constructor.

2 _stop

Kernels keep track of the resources that sessions use. Some resources guarantee that the session will receive events. These include enqueued events, selects (filehandle monitors), child sessions, and aliases. Sessions that run out of these resources become starved for events, and kernels removes them. Before it removes them, it issues a _stop event. This gives sessions an opportunity to clean up.

FROM is the session that posted the _stop event. In the case of resource starvation, this is the KERNEL. If _stop was posted, it contains a reference to the session that posted it.

ARG0..ARG9 are empty in the case of resource starvation. If the _stop event was posted, they may contain other values.

3 _signal

Signal handling has changed slightly in version 0.06.

POE sets handlers for most of the signals in %SIG. The only exceptions are things which might exist in %SIG but probably shouldn't. POE will not register a signal handler for RTMIN, for example, because doing so breaks Perl for HP-UX.

Signals are propagated to children of the destination session first. Since every session ultimately is a descendent of the kernel, posting signals to the kernel guarantees that every session receives them.

POE does not magically solve Perl's problems with signals. Yet.

Currently there are three types of signals. The kernel processes each in a different way:

SIGPIPE causes a _signal event to be posted directly to the session that is running when the signal was received. ARG0 contains the signal name as it appears in %SIG.

SIGCHLD and/or SIGCLD call wait to acquire the dying child's process ID. A _signal event will be posted to all sessions if the child PID is valid. ARG0 contains CHLD regardless of the actual signal name, ARG1 contains the child PID, and ARG2 contains the contents of $? just after the wait call.

All other signals cause a _signal event to be posted to all sessions. ARG0 contains the signal name as it appears in %SIG.

4 _garbage_collect

The _garbage_collect event tells the kernel to check a session's resources and stop it if none are left. It never is dispatched to a session. This was added to delay garbage collection for new sessions, allowing parent sessions to interact with them before they stop.

5 _parent

The _parent event lets child sessions know that they are about to be orphaned, and it tells them their new parents. It is dispatched to child sessions before parents receive their _stop events.

FROM should always equal KERNEL. If it does not, then the event was sent by a session other than the kernel. ARG0 is this session's old parent; ARG1 is the new parent.

6 _child

The _child event is sent to parent sessions when they acquire or lose child sessions. _child is dispatched to parents after the children receive _start or before they receive _stop.

FROM should always equal KERNEL. If it does not, then the event was sent by a session other than the kernel.

ARG0 indicates what is happening to the child. It is 'gain' if the session is a grandchild being given by a dying child. It is 'lose' if the session is itself a dying child. It is 'create' if the child was created by the current session.

ARG1 is a reference to the child session. It will still be valid, even if the child is in its death throes.

ARG2 is only valid when ARG0 contains 'create'. It contains the return value of the child's _start event handler, which was evaluated in a scalar context (and stringified if it was a reference to a POE::* object).

7 _default

The _default handler is invoked whenever a session receives an event it can't handle. The event is discarded if the session doesn't have a _default handler. This prevents POE from recursing until perl's stack eats the machine.

ARG0 contains the name of the original event. ARG1 contains a reference to the original event's ARG0.. parameters.

_default can be useful for detecting misspelled event names or handling strange signals. So can POE::Session::debug().

3 Alarms

Alarms are just events that are scheduled to be dispatched at some point in the future. POE will use Time::HiRes, if it's available, to allow fractional alarm times.

1 Kernel::alarm

Kernel::alarm enqueues an event with a future dispatch time, specified in seconds since the unix epoch.

  $kernel->alarm($event_name, $dispatch_time, @args);

If $dispatch_time is in the past, it will be clipped to time.

Alarms are keyed on their event names. It is possible to remove an alarm that hasn't yet been dispatched by omitting the other parameters:

  $kernel->alarm($event_name);  # clears the $event_name alarm

Subsequent alarms set for the same name will overwrite previous ones. This is useful for setting timeout timers.

Kernel::alarm can be misused to remove events from the kernel's queue. This happens because alarms are merely events scheduled to be dispatched in the future. This behavior is not supported and may change. If someone finds it to be useful, please contact the author.

2 Kernel::delay

Kernel::delay enqueues an event for a certain amount of time in the future. It is a shortcut for calling Kernel::alarm with time + $delay. It automagically uses a high-resolution version of time, if Time::HiRes is available.

To set a delay:

  $kernel->delay($event_name, $delay, @args);

As with Kernel::alarm, omitting the other parameters will remove a delay:

  $kernel->delay($event_name);  # clears the $event_name delay

Kernel::delay can be misused to remove events from the kernel's queue. This happens because alarms are merely events scheduled to be dispatched in the future. This behavior is not supported and may change. If someone finds it to be useful, please contact the author.

4 Aliases

Aliases allow sessions to be referred to by name. They also allow sessions to remain active without having open selects or events. This provides support for "daemon" sessions that act as resources but don't do much by themselves.

Aliases must be unique. Sessions may have more than one alias.

1 Kernel::alias_set

Sets an alias for the current session.

  $kernel->alias_set($alias);

Returns 1 on success. On failure, it returns 0 and sets $! to one of:

  • EEXIST - the alias exists for another session

2 Kernel::alias_remove

Removes an alias for the current session.

  $kernel->alias_remove($alias);

Returns 1 on success. On failure, it returns 0 and sets $! to one of:

  • ESRCH - the alias does not exist

  • EPERM - the alias belongs to another session

3 Kernel::alias_resolve

Resolves an alias to a session reference. Kernels do this internally, so it usually is not necessary.

  my $session_reference = $kernel->alias_resolve($alias_name);

Returns a session reference on success. On failure, it returns undef and sets $! to one of:

  • ESRCH - the alias does not exist

5 Selects

Selects are filehandle monitors. They cause kernels to generate events when file activity occurs. Files are automatically closed when all the selects watching them are released.

There are three types of select, each corresponding to one of the bit vectors in Perl's four-argument select() function. Read selects generate events when files become ready for reading. Write selects generate events when files are available to be written to. Expedite selects generate events when out-of-band information becomes available for reading.

1 Kernel::select

Kernel::select allows sessions to add, change or remove all three selects for a filehandle at once. Undefined event names remove their corresponding selects.

  $kernel->select( $filehandle,
                   $read_event_name,    # or undef to remove
                   $write_event_name,   # or undef to remove
                   $expedite_event_name # or undef to remove
  );
2 Kernel::select_read

This function adds, changes or removes a filehandle's read select. The other selects remain unchanged.

  $kernel->select_read($filehandle, $read_event_name);
3 Kernel::select_write

This function adds, changes or removes a filehandle's write select. The other selects remain unchanged.

  $kernel->select_write($filehandle, $write_event_name);
4 Kernel::select_expedite

This function adds, changes or removes a filehandle's expedite select. The other selects remain unchanged.

  $kernel->select_expedite($filehandle, $expedite_event_name);
6 Signals

The kernel generates _signal events when it receives signals from the underlying operating system. Sessions may also send signals between themselves without involving the OS.

The kernel determines whether or not signals have been handled by looking at _signal handlers' return values. Boolean true indicates that a signal was handled; boolean false means it wasn't.

Some signals will cause a kernel to stop a session if they aren't handled. These "terminal" signals are QUIT, INT, KILL, TERM and HUP.

  sub hup_handler {
    my $heap = $_[HEAP];
    &close_files($heap);   # close log files
    &rotate_files($heap);  # rotate logs
    &open_files($heap);    # open new log files
    1;                     # and don't _stop the session!
  }

Finally, there is one fictitious signal that always stops a session: ZOMBIE. When the kernel runs out of events, alarms and selects, it sends any remaining sessions a ZOMBIE signal. This lets them know that the event queue has stalled, and they're as good as dead anyway.

1 Kernel::sig

Signals normally post _signal events to sessions. Kernel::sig allows sessions to receive different events for each signal.

To receive sigint_event instead of _signal for SIGINT:

  $kernel->sig('INT', 'sigint_event');

To receive _signal for SIGINT once again:

  $kernel->sig('INT');
2 Kernel::signal

Kernel::signal simulates a signal. It bypasses the operating system, so the signal's name is not limited to what the OS allows. Likewise, Kernel::sig may be used to catch these fictitious signals.

  $kernel->sig('BOGUS', 'sigbogus_event');
  $kernel->signal($session, 'BOGUS');
  $kernel->signal($kernel, 'HUP'); # sends to every session
7 States

States are another name for event handlers. This was discussed in the Events Layer section. The name "state" is used here instead of "event_handler" because it's easier to type.

The kernel's state management function allows sessions to add, change and remove event handlers at runtime. Wheel constructors and destructors use this to add and remove event handlers from sessions.

1 Kernel::state

Kernel::state adds, changes or removes a session's state. This may be used to alter inline, object and package event handlers:

  $kernel->state($event_name, $code_reference);      # inline
  $kernel->state($object_reference, \@method_names); # object
  $kernel->state($package_name, \@function_names);   # package

Returns 1 on success. On failure, it returns 0 and sets $! to one of:

  • ESRCH - somehow, the current session does not exist

I/O Layer

The I/O layer abstracts low- and medium-level I/O into three functional classes: Drivers, Filters and Wheels.

1 Drivers

Drivers provide a generic interface for low-level I/O. Wheels use this interface to communicate over different types of files without having to know the details for each.

In theory, drivers should be interchangeable. In practice, there seems to be an impermeable barrier between the different SOCK_* types. More on this in later versions, after Wheel::SocketFactory acquires UDP support.

1 Generic Driver Interface

Drivers are expected to have at least four methods. The methods may be empty stubs if the underlying I/O doesn't require their functions.

1 Driver::new

Driver::new creates and initializes a new driver.

  my $driver = new POE::Driver::Something();
2 Driver::get

Driver::get immediately tries to read information from a filehandle. It returns a reference to an array of received data chunks. The array may be empty if nothing could be read. The array reference it returns is suitable as a parameter to Filter::get.

  my $chunks_for_filter = $driver->get($handle);

Wheels usually call Driver::get from their read select handlers.

3 Driver::put

Driver::put places raw data into the driver's output queue. Some drivers may flush data during put. It accepts a reference to an array of writable chunks and returns the number of elements in the output queue. Wheels use the return value to know when to manage write selects and send events.

  my $enqueued = $driver->put($streamable_from_filter);

Wheels usually call Driver::put from their own put methods.

4 Driver::flush

Driver::flush attempts to flush data from the driver's output queue to the file. It returns the number of elements remaining in the output queue after the flush.

  my $enqueued = $driver->flush($handle);

Wheels usually call Driver::flush from their write select handlers.

2 Specific Drivers

These drivers implement specific types of I/O. They all follow the generic driver interface.

1 Driver::SendRecv

This driver is not currently available. It is scheduled to be part of a future release, along with UDP support in Wheel::SocketFactory.

Driver::SendRecv driver will be a generic interface to send and recv.

2 Driver::SysRW

Driver::SysRW is a generic interface to sysread and syswrite.

2 Filters

Filters provide a generic interface for low- and medium-level protocols. Wheels use this interface to communicate in different ways without having to know the details for each.

In theory, filters should be interchangeable. In practice, stream and block protocols tend to be incompatible. More on this in later versions, after Wheel::SocketFactory acquires UDP support and things can be tried.

1 Generic Filter Interface

Filters are expected to have at least three methods. The methods implement fairly basic functions, and they all are expected to do something.

1 Filter::new

Filter::new creates and initializes a new filter.

  my $filter = new POE::Filter::Something();
2 Filter::get

Filter::get translates raw stream data into logical units. It accepts a reference to an array of raw stream chunks (returned from Driver::get) and returns a reference to an array of complete logical units. Some filters will hold onto partial logical units until they are completed in a subsequent Filter::get call.

  my $logical_blocks = $filter->get($chunks_from_driver);

Filter::get returns a reference to an empty array if the stream doesn't include enough information for a complete logical unit.

3 Filter::put

Filter::put accepts a reference to an array of logical data units. It translates the data units into streamable representations (suitable for Driver::put), and it returns them in a different array reference.

  my $streamable_for_driver = $filter->put($logical_blocks);
2 Specific Filters

These filters implement specific low- and medium-level protocols. They all follow the generic filter interface.

1 Filter::Line

Filter::Line translates streams to and from delimited lines.

To do: This filter is broken as designed. A future version will allow the end-of-line marker to be specified as a parameter to Filter::Line::new. It may also have a method that allows the marker to be changed after the filter is created.

Regardless of the changes, it will maintain compatibility by default.

1 Line::get

This function splits streams on newlines, using the regexp /(\x0D\x0A?|\x0A\x0D?)/. It returns as many complete lines as it finds. Incomplete lines are kept until they are completed.

2 Line::put

This function appends network newlines ("\x0D\x0A") to its parameters in preparation for them to be written by a driver.

2 Filter::Reference

Filter::Reference translates streams to and from Perl references. It requires either Storable or FreezeThaw.

1 Reference::get

Reference::get reconstitutes streamed, frozen data into references. References will be blessed, if necessary. If the reference points to an object, be sure to use its module before calling its methods.

  my $references = $ref_filter->get($frozen_data);
2 Reference::put

Reference::put accepts one or more references. It freezes the references and returns them as streamable values.

  my $frozen_data = $ref_filter->put($reference);
3 Stream Filter

Filter::Stream passes data through unchanged.

1 Stream::get

Stream::get returns an exact copy of its parameters.

2 Stream::put

Stream::put returns an exact copy of its parameters.

3 Wheels

Wheels provide standard, reusable logic for filters and drivers. They are designed to manage the resources and objects they are given, to use Drivers and Filters more or less interchangeably, and to clean up the resources they use.

1 Generic Wheel Interface

The generic wheel interface is very simple. It consists of a constructor, a destructor and optional methods.

1 Wheel::new

Wheel::new creates and initializes a new wheel. Part of a wheel's initialization involves adding event handlers to its parent session and registering them with the kernel.

  $heap->{wheel} = new POE::Wheel::Something( ... );

Because wheels have wildly different functions, they tend also to have very different constructors.

2 Wheel::DESTROY

Wheel::DESTROY removes the handlers from the parent session and releases the resources it manages. This all happens automatically when the parent session deletes its reference to the wheel.

  delete $heap->{wheel};
3 Wheel::put

Wheels hide the resources they use. For this reason, wheels that manage writable files must provide their own Wheel::put methods. Wheel::put combines Filter::put and Driver::put in predictable ways.

2 Specific Wheels

POE comes with a small assortment of wheels. This will grow as people need to do other things.

1 ListenAccept

Wheel::ListenAccept waits for activity on a listening socket and accepts remote connections as they arrive. It generates events for successful and failed connections. EAGAIN is not considered to be a failure. This wheel neither needs nor includes a put method.

Wheel::ListenAccept was intended to be used with other sources of sockets. It predates Wheel::SocketFactory and is compatible with IO::Socket classes.

1 ListenAccept Methods

These are ListenAccept's methods.

1 ListenAccept::new

ListenAccept::new parameters include a listening socket handle and the names of events to be generated on successful and failed connections.

  my $wheel = new POE::Wheel::ListenAccept(
        Handle      => $socket_handle,     # listening socket
        AcceptState => $accept_event_name, # success event
        ErrorState  => $error_event_name   # failure event
  );
2 ListenAccept Events and Parameters

These are the events that Wheel::ListenAccept emits, and the parameters each event includes.

1 AcceptState

AcceptState contains the name of the event that will be generated upon a successful connection.

ARG0 contains the accepted socket handle.

A sample AcceptState handler:

  sub accept_handler {
    my $handle = $_[ARG0];
    # optional security things with getpeername
    &create_server_session($handle);
  }
2 ErrorState

ErrorState contains the name of the event that will be generated upon a failed connection.

ARG0 contains the name of the function that failed. This usually is 'accept'. ARG1 and ARG2 contain the numeric and string versions of $! at the time of the failure, respectively.

A sample ErrorState handler:

  sub error_handler {
    my ($operation, $errnum, $errstr) = @_[ARG0, ARG1, ARG2];
    warn "$operation error $errnum: $errstr";
  }
2 ReadWrite

This wheel performs buffered I/O on a filehandle. It generates events for common file conditions, such as read availability. This wheel includes a put method.

1 ReadWrite Methods

These are ReadWrite's methods.

1 ReadWrite::new

ReadWrite::new parameters include a file or socket handle, a driver and a filter, and the names of events to generate for different conditions.

  my $wheel = new POE::Wheel::ReadWrite(
        Handle       => $file_or_socket_handle,       # handle to R/W
        Driver       => new POE::Driver::Something(), # driver to use
        Filter       => new POE::Filter::Something(), # filter to use
        InputState   => $input_event_name,  # event to emit on input
        FlushedState => $flush_event_name,  # event to emit on flush
        ErrorState   => $error_event_name,  # event to emit on error
  );

This wheel currently does not support OOB data. Please contact the author if OOB support is needed.

2 ReadWrite::put

ReadWrite::put enqueues output for the filehandle and enables the wheel's write select. It accepts one or more units of data, in its filter's format.

2 ReadWrite Events and Parameters

These are the events that Wheel::ReadWrite emits, and the parameters each event includes.

1 InputState

InputState contains the name of the event that will be generated for each logical unit of input received. If the InputState parameter is omitted, the wheel be write-only. This supports log file writing.

ARG0 contains a logical unit of input.

A sample InputState handler:

  sub input_handler {
    my ($heap, $input) = @_[HEAP, ARG0];
    print "Got input: $input\n";
    $heap->{wheel}->put($input);   # echo it back
  }
2 FlushedState

FlushedState contains the name of the event that will be generated whenever the wheel's output queue becomes empty. This signals that all pending data has been written. It does not include parameters.

A sample FlushedState handler:

  sub flush_handler {
    delete $_[HEAP]->{wheel};  # disconnects after flush
  }
3 ErrorState

ErrorState contains the name of the event that will be generated whenever the wheel encounters a file error.

ARG0 contains the name of the function that failed. This depends on the wheel's associated driver. ARG1 and ARG2 contain the numeric and string versions of $! at the time of the failure, respectively.

A sample ErrorState handler:

  sub error_handler {
    my ($operation, $errnum, $errstr) = @_[ARG0, ARG1, ARG2];
    warn "$operation error $errnum: $errstr";
  }
3 FollowTail

This wheel generates events when data appears at the end of a file. It is a read-only wheel and does not include a put method. It behaves a lot like a read-only version of Wheel::ReadWrite.

1 FollowTail Methods

These are FollowTail's methods.

1 FollowTail::new

FollowTail::new parameters include a seekable filehandle to watch, a driver that can read from the file, a filter that can format the file's records, the name of an event handler that will process records, and the name of an event handler that will deal with errors. It now accepts an optional PollInterval parameter. This determines how long to wait between checks for file activity.

  my $wheel = new POE::Wheel::FollowTail(
        Handle       => $file_handle,
        Driver       => new POE::Driver::Something(),
        Filter       => new POE::Filter::Something(),
        InputState   => $input_event_name,
        ErrorState   => $error_event_name,
        PollInterval => 1,
  );
2 FollowTail Events

These are the events that Wheel::FollowTail emits, and the parameters each event includes.

1 InputState

This event behaves exactly like InputState for Wheel::ReadWrite.

2 ErrorState

This event behaves exactly like ErrorState for Wheel::ReadWrite.

4 SocketFactory

This wheel creates sockets, generating events when something happens to them. Success events come with connected sockets, ready to be used. Failure events are accompanied by error codes.

SocketFactory currently supports the AF_UNIX domain, and TCP sockets within the AF_INET domain. AF_INET/UDP sockets are forthcoming.

1 SocketFactory Methods

Socket factories only have one method, new().

1 SocketFactory::new

SocketFactory::new does all the work. Its parameters are an amalgam of the parameters for socket(), setsockopt(), bind(), listen(), connect(), and accept():

1 SocketDomain

This is the DOMAIN parameter for socket(). Currently supported values are AF_UNIX and AF_INET. It is always required.

2 SocketType

This is the TYPE parameter for socket(). Currently supported values are SOCK_STREAM and SOCK_DGRAM (although datagram sockets are not tested at this time). It is always required.

3 SocketProtocol

This is the PROTOCOL parameter for socket(). Protocols may be specified by name or number (see /etc/protocol). The only supported protocol at this time is 'tcp'. SocketProtocol is ignored for the AF_UNIX domain, and it is required for AF_INET sockets.

4 BindAddress

This is the address of the local interface that the socket will be bound to. It is required for all AF_UNIX sockets and recommended for listening AF_INET.

It defaults to INADDR_ANY if it's not specified for AF_INET sockets.

BindAddress is expected to be a textual representation of the address. It will be packed, with or without an accompanying BindPort as necessary for the socket domain.

5 BindPort

This is the port of the local interface that the socket will be bound to. It is ignored for all AF_UNIX sockets and recommended for listening AF_INET sockets. It defaults to 0 if it's not specified for AF_INET sockets.

BindPort is expected to be a textual representation of the port. It may be specified by name or number.

6 ListenQueue

This parameter specifies the length of the socket's listen() queue. For sockets that support connections, ListenQueue helps determine whether to be a listening or connecting socket.

ListenQueue is clipped to never exceed SOMAXCONN.

7 RemoteAddress

This is the remote address to which the socket should connect. It is required for connecting sockets and ignored in all other cases.

RemoteAddress is expected to be a textual representation of the address. It will be packed, with or without an accompanying RemotePort as necessary for the socket domain.

8 RemotePort

This is the remote port to which the socket should connect. It is required for connecting AF_INET sockets and ignored in all other cases.

RemotePort is expected to be a textual representation of the port. It may be specified by name or number.

9 SuccessState

This is the name of the event that will be generated when the socket is successfully created. For sockets that support connections, this also indicates a connection was made.

SocketFactory only generates one SuccessState event when a connection has been established. For client sockets, this happens when the connection has gone through. For server sockets, this indicates that a client has successfully been accepted.

ARG0 always contains the connected or accepted socket.

If ARG0 is an accepted AF_INET socket, then ARG1 and ARG2 will contain the accepted socket's address and port, as returned by unpack_sockaddr_in.

ARG1 and ARG2 are undef for AF_UNIX sockets.

10 FailureState

This is the name of the event that will be generated when something goes wrong. EWOULDBLOCK is not one of the conditions for generating this event.

As with other "error" events, ARG0 contains the syscall that failed, ARG1 contains the numeric version of $! at the time of failure, and ARG2 contains the string version of $!.

2 SocketFactory Examples

Please see tests/socketfactory.perl. It includes SocketFactory samples for every supported socket type.

Object Layer

This layer puts the O in POE. It's still in development, and this documentation is mostly a place holder.

1 Curator

This class manages objects.

2 Object

Instances of this class are managed by the Curator.

Test and Example Programs

The test/example programs have been updated for version 0.06. They even include comments now.

These example programs may be found in the tests subdirectory. They all should work on any reasonable Perl platform.

1 followtail.perl

tests/followtail.perl tests Wheel::FollowTail's ability to follow files' tails without blocking. It uses write-only ReadWrite wheels to write to logs.

It creates ten sessions that periodically append timestamps to hypothetical log files. It creates ten more sessions to follow those files' tails and display the new timestamps. To ensure that nothing is blocking, it creates a final thread that displays a short message twice every second. Upon SIGINT, they will all shut down, and the temporary log files will be unlinked.

That's 21 cooperative sessions in all.

2 forkbomb.perl

tests/forkbomb.perl verifies parent/child relationships and signal propagation.

It creates 200 sessions whose jobs are to create more of themselves. After the 100th session, sessions will start to randomly exit. After the 200th session, they will stop creating new sessions and all exit. These limits ensure that the program does not take over the machine.

SIGINT should cause the program to exit immediately.

3 httpd.perl

tests/httpd.perl is a simple Filter::HTTPD test.

It creates an HTTP server on port 80 of all interfaces. The port may be overridden on the command line:

  ./httpd.perl 8888

The server should answer and respond to HTTP requests.

4 names.perl

tests/names.perl tests session aliases (formerly known as "names") and provides a simple example of an asynchronous callback protocol for inter-session communication. That's just a fancy way of saying the sessions pass messages back and forth to do blocking things in a nonblocking way.

It creates a "lock daemon" session, and five clients. The clients use the daemon to synchronize their activities. Everything shuts down and exits gracefully on SIGINT.

5 objsessions.perl

tests/objsessions.perl is a version of tests/sessions.perl that uses object sessions instead of inline ones. It's a little simpler than the inline version.

6 packagesessions.perl

tests/packagesessions.perl is a version of tests/sessions.perl that uses package sessions instead of inline ones. It's a little simpler than the inline version.

7 preforkedserver.perl

tests/preforkedserver.perl is a proof of concept for pre-forking servers. It maintains a pool of five servers: one parent (that also handles connections) and four pre- and re-forked children.

8 proxy.perl

tests/proxy.perl is an advanced wheel test that implements a fully-functional port redirector (proxy). It was implemented to make sure that POE was capable of doing it cleanly.

The default redirection table:

  127.0.0.1:7000-127.0.0.1:7001   # cascading proxies on 7000
  127.0.0.1:7001-127.0.0.1:7002
  127.0.0.1:7002-127.0.0.1:7003
  127.0.0.1:7003-127.0.0.1:7004
  127.0.0.1:7004-127.0.0.1:7005
  127.0.0.1:7005-127.0.0.1:7006
  127.0.0.1:7006-127.0.0.1:7007
  127.0.0.1:7007-127.0.0.1:7008
  127.0.0.1:7008-127.0.0.1:7009
  127.0.0.1:7009-perl.org:daytime # plain proxy on 7009
  127.0.0.1:7010-127.0.0.1:7010   # infinite loop-- fun!
  127.0.0.1:7777-127.0.0.1:12345  # test "connection refused"
9 refsender.perl and refserver.perl

tests/refserver.perl is a small reference server. It accepts data from clients and displays some information about it.

tests/refsender.perl is a small reference client. It sends data to a waiting reference server. By default, it sends a few different types of references. When given a numeric parameter, it will send that many copies of \@ARGV. This was added to test POE's ability to handle large, fast streams of data.

Please note that refserver and refsender implement a uni-directional protocol. The client does not wait for a response, by design.

These tests are based on Artur Bergman's contributed code, with ideas from Dave Paris.

10 selects.perl

tests/selects.perl predates wheels. It was written to test POE's basic select logic.

This test creates a chargen server and client in the same process. The client tests its ability to connect and receive information from the server, then shuts down. The server continues to wait for other connections until stopped by SIGINT.

11 sessions.perl

tests/sessions.perl is an early events test. It was modified later to test Kernel::call, making it a little more complicated than its object and package session counterparts.

All the session tests create five sessions, which share the event queue for a small number of iterations before exiting. People who are new to POE might want to look at this test first.

12 signals.perl

tests/signals.perl is an early signals test that was later enhanced to verify sub-second events.

It creates two sessions that wait for signals and display their information. Each session sends fictitious signals to itself, the other session, or the kernel.

SIGINT will gracefully stop the program.

13 socketfactory.perl

tests/socketfactory.perl tests the different types of sockets that Wheel::SocketFactory. It is basically multiple versions of thrash.perl, each using a different socket type, in one program.

14 thrash.perl

tests/thrash.perl stress-tests events, the socket factory, and memory. Its main purpose is to check the Events and I/O layers for memory leaks and flaws. It also acts as a sort of benchmark.

This program creates a simulated daytime server and a pool of clients (5) within the same process. The client pool constantly hits the server with new connections. This program should quickly indicate if POE is leaking resources, and it also seems to be a good profiling target.

The program averages connections per second over ten-second periods. It is not a good example of POE's performance because it is both a server and its own clients. Its benchmarks mainly are used to compare POE's performance from one version to the next.

15 tutorial-chat.perl

tests/tutorial-chat.perl is a very simple chat server. It includes a running narration in blocks of pod. Hopefully it's sufficiently friendly enough to be a useful introduction to POE.

16 wheels.perl

tests/wheels.perl is a version of tests/selects.perl that uses wheels instead of hand-coded event handlers.

Things To Do

1 Near Future
  • fix alarm semantics (need to find a way not to break things)

2 Medium Future
  • Chained filters

  • Chained wheels

  • Wrap event handlers in "eval {}", for exception handlers?

  • Translate die and warn into ... ?

  • Filter::Block - like Filter::Stream but for datagrams?

  • Allow Filter::Line to specify the newline character.

  • Add a Kernel function to list active sessions.

  • Add a Kernel function to acquire details about a session.

  • Add a Kernel function to acquire the kernel's and OS's load averages.

3 Ideas to Consider
  • POP? is this POE3 or bholzman's persistent objects?

  • poe_distributor session, for distributed POE?

  • $kernel->stop() and $kernel->run() to pause and resume the kernel?

  • Filter::HTTPD needs to send responses directly... POE::Module::*?

4 Someday
  • Use threads, if available, requested and stable.

  • Use fork, if available and requested.

  • Distribute event dispatching across several systems.

  • Load-balancing among distributed POE kernels.

  • Filter::HTTP (user agent).

  • Rewrite Serv's curses widgets for POE.

AUTHORS

1 Contributors

These are the people who help make POE possible.

1 Artur Bergman

Filter::Reference and Filter::HTTPD are Copyright 1998 Artur Bergman <artur@vogon-solutions.com>. All rights reserved. Artur's contributions are free software; you may redistribute them and/or modify them under the same terms as Perl itself.

2 Dave Paris

Dave Paris's ideas, testing and benchmarking discovered some subtle (and not so subtle) timing problems in POE 0.05. The pre-forking server test was also his idea. Version 0.06 should handle high-load situations much smoother now.

3 Robert Seifer

Robert Seifer contributed probably entirely too much time, both his own and his computer's, to the detection and eradication of a memory corruption bug that POE tickled in Perl. In the end, his work produced a patch that circumvents problems found relating to anonymous subs, scope and @{} processing.

2 Author

POE is Copyright 1998 Rocco Caputo <troc@netrus.net>. All rights reserved. POE is free software; you may redistribute it and/or modify it under the same terms as Perl itself.