home *** CD-ROM | disk | FTP | other *** search
- # $Id: Loop.pm,v 1.4 2004/04/17 17:20:36 sungo Exp $
-
- package POE::Loop;
-
- use strict;
-
- use vars qw($VERSION);
- $VERSION = do {my@r=(q$Revision: 1.4 $=~/\d+/g);sprintf"%d."."%04d"x$#r,@r};
-
- use Carp qw(croak);
-
- sub new {
- my $type = shift;
- croak "$type is a virtual base class and not meant to be used directly";
- }
-
- 1;
-
- __END__
-
- =head1 NAME
-
- POE::Loop - documentation for POE's event loop bridge interface
-
- =head1 SYNOPSIS
-
- $kernel->loop_initialize();
- $kernel->loop_finalize();
- $kernel->loop_do_timeslice();
- $kernel->loop_run();
- $kernel->loop_halt();
-
- $kernel->loop_watch_signal($signal_name);
- $kernel->loop_ignore_signal($signal_name);
- $kernel->loop_attach_uidestroy($gui_window);
-
- $kernel->loop_resume_time_watcher($next_time);
- $kernel->loop_reset_time_watcher($next_time);
- $kernel->loop_pause_time_watcher();
-
- $kernel->loop_watch_filehandle($handle, $mode);
- $kernel->loop_ignore_filehandle($handle, $mode);
- $kernel->loop_pause_filehandle($handle, $mode);
- $kernel->loop_resume_filehandle($handle, $mode);
-
- =head1 DESCRIPTION
-
- POE's runtime kernel abstraction uses the "bridge" pattern to
- encapsulate services provided by different event loops. This
- abstraction allows POE to cooperate with several event loops and
- support new ones with a minimum amount of work.
-
- POE relies on a relatively small number of event loop services: signal
- callbacks, time or alarm callbacks, and filehandle activity callbacks.
-
- The rest of the bridge interface is administrative trivia such as
- initializing, executing, and finalizing event loop.
-
- =head1 GENERAL NOTES
-
- An event loop bridge is not a proper object in itself. Rather, it is
- a suite of functions that are defined within the POE::Kernel
- namespace. A bridge is a plugged-in part of POE::Kernel itself. Its
- functions are proper POE::Kernel methods.
-
- Each bridge first defines its own namespace and version within it.
- This way CPAN and other things can track its version.
-
- # $Id: Loop.pm,v 1.4 2004/04/17 17:20:36 sungo Exp $
-
- use strict;
-
- # YourToolkit bridge for POE::Kernel;
-
- package POE::Loop::YourToolkit;
-
- use vars qw($VERSION);
- $VERSION = do {my@r=(q$Revision: 1.4 $=~/\d+/g);sprintf"%d."."%04d"x$#r,@r};
-
- package POE::Kernel;
-
- ... private lexical data and functions defined here ...
-
- 1;
-
- __END__
-
- =head1 NAME
-
- ... documentation goes here ...
-
- =cut
-
- The public interface for loop bridges is broken into four parts:
- administrative functions, signal functions, time functions, and
- filehandle functions. They will be described in detail shortly.
-
- Bridges use lexical variables to keep track of things. The types and
- number of variables depends on the needs of each event loop. For
- example, POE::Loop::Select keeps bit vectors for its select() call.
- POE::Loop::Gtk tracks a single time watcher and multiple file watchers
- for each file descriptor.
-
- Bridges often employ private functions as callbacks from their event
- loops. The Event, Gtk, and Tk bridges do this.
-
- Developers should look at existing bridges to get a feel for things.
- The C<-m> flag for perldoc will show a module in its entirety.
-
- perldoc -m POE::Loop::Select
- perldoc -m POE::Loop::Gtk
- ...
-
- =head1 ADMINISTRATIVE FUNCTIONS
-
- These functions initialize and finalize an event loop, run the loop to
- process events, and halt it.
-
- =over 2
-
- =item loop_initialize
-
- Initialize the event loop. Graphical toolkits especially need some
- sort of init() call or sequence to set up. For example,
- POE::Loop::Gtk implements loop_initialize() like this.
-
- sub loop_initialize {
- Gtk->init;
- }
-
- POE::Loop::Select does a little more work.
-
- sub loop_initialize {
- @loop_vectors = ( '', '', '' );
- vec($loop_vectors[MODE_RD], 0, 1) = 0;
- vec($loop_vectors[MODE_WR], 0, 1) = 0;
- vec($loop_vectors[MODE_EX], 0, 1) = 0;
- }
-
- =item loop_finalize
-
- Finalize the event loop. Most event loops do not require anything
- here since they have already stopped by the time loop_finalize() is
- called. However, this is a good place to check that a bridge has not
- leaked memory or data. This example comes from POE::Loop::Event.
-
- sub loop_finalize {
- foreach my $fd (0..$#fileno_watcher) {
- next unless defined $fileno_watcher[$fd];
- foreach my $mode (MODE_RD, MODE_WR, MODE_EX) {
- warn "Fileno $fd / mode $mode has a watcher at loop_finalize"
- if defined $fileno_watcher[$fd]->[$mode];
- }
- }
- }
-
- =item loop_do_timeslice
-
- Wait for time to pass or new events to occur, and dispatch events
- which are due. If the underlying event loop does these things, then
- loop_do_timeslice() either provide- minimal glue for them or does
- nothing.
-
- For example, the loop_do_timeslice() function for the Select bridge
- sets up and calls select(). If any files or other resources become
- active, it enqueues events for them. Finally, it triggers dispatch
- for any events are due.
-
- On the other hand, the Gtk event loop handles all this, so
- loop_do_timeslice() is empty for the Gtk bridge.
-
- A sample loop_do_timeslice() is not presented here because it would
- either be quite large or empty. See the bridges for Poll and Select
- for large ones. The Event, Gtk, and Tk bridges are good examples of
- empty ones.
-
- =item loop_run
-
- Run an event loop until POE has no more sessions to handle events.
- This function tends to be quite small. For example, the Poll bridge
- uses:
-
- sub loop_run {
- my $self = shift;
- while ($self->_data_ses_count()) {
- $self->loop_do_timeslice();
- }
- }
-
- This function is even more trivial when an event loop handles it.
- This is from the Gtk bridge:
-
- sub loop_run {
- Gtk->main;
- }
-
- =item loop_halt
-
- Halt an event loop, especially one which does not know about POE.
- This tends to be an empty function for loops written in the bridges
- themselves (Poll, Select) and a trivial function for ones that have
- their own main loops.
-
- For example, the loop_run() function in the Poll bridge exits when
- sessions have run out, so its loop_halt() function is empty:
-
- sub loop_halt {
- # does nothing
- }
-
- Gtk, however, needs to be stopped because it does not know when POE is
- done.
-
- sub loop_halt {
- Gtk->main_quit();
- }
-
- =back
-
- =head1 SIGNAL FUNCTIONS
-
- These functions enable and disable signal watchers.
-
- =over 2
-
- =item loop_watch_signal SIGNAL_NAME
-
- Watch for a given SIGNAL_NAME, most likely by registering a signal
- handler. Signal names are the ones included in %SIG. That is, they
- are the UNIX signal names with the leading "SIG" removed.
-
- Most event loops do not have native signal watchers, so it is up to
- their bridges to register %SIG handlers. Some bridges, such as
- POE::Loop::Event, register callbacks for various signals.
-
- There are three types of signal handlers:
-
- CHLD/CLD handlers, when managed by the bridges themselves, poll for
- exited children. POE::Kernel does most of this, but
- loop_watch_signal() still needs to start the process.
-
- PIPE handlers. The PIPE signal event must be sent to the session that
- is active when the signal occurred.
-
- Everything else. Signal events for everything else are sent to
- POE::Kernel, where they are distributed to every session.
-
- The loop_watch_signal() function tends to be very long, so an example
- is not presented here. The Event and Select bridges have good
- examples, though.
-
- =item loop_ignore_signal SIGNAL_NAME
-
- Stop watching SIGNAL_NAME. This usually resets the %SIG entry for
- SIGNAL_NAME to DEFAULT. In the Event bridge, however, it stops and
- removes a watcher for the signal.
-
- The Select bridge:
-
- sub loop_ignore_signal {
- my ($self, $signal) = @_;
- $SIG{$signal} = "DEFAULT";
- }
-
- The Event bridge:
-
- sub loop_ignore_signal {
- my ($self, $signal) = @_;
- if (defined $signal_watcher{$signal}) {
- $signal_watcher{$signal}->stop();
- delete $signal_watcher{$signal};
- }
- }
-
- =item loop_attach_uidestroy WINDOW
-
- Send a UIDESTROY signal when WINDOW is closed. The UIDESTROY signal
- is used to shut down a POE program when its user interface is
- destroyed.
-
- This function is only meaningful in bridges that interface with
- graphical toolkits. All other bridges leave loop_attach_uidestroy()
- empty. See POE::Loop::Gtk and POE::Loop::Tk for examples.
-
- =back
-
- =head1 ALARM OR TIME FUNCTIONS
-
- These functions enable and disable a time watcher or alarm in the
- substrate. POE only requires one, which is reused or re-created as
- necessary.
-
- Most event loops trigger callbacks when time has passed. Bridges for
- this kind of loop will need to register and unregister a callback as
- necessary. The callback, in turn, will dispatch due events and do
- some other maintenance.
-
- The bridge time functions accept NEXT_EVENT_TIME in the form of a UNIX
- epoch time. Event times may contain fractional seconds. Time
- functions may be required to translate times from the UNIX epoch into
- whatever representation an underlying event loop requires.
-
- =over 2
-
- =item loop_resume_time_watcher NEXT_EVENT_TIME
-
- Resume an already active time watcher. Used with
- loop_pause_time_watcher() to provide lightweight timer toggling.
- NEXT_EVENT_TIME is the UNIX epoch time of the next event in the queue.
- This function is used by bridges that set time watchers in other event
- loop libraries. For example, Gtk uses this:
-
- sub loop_resume_time_watcher {
- my ($self, $next_time) = @_;
- $next_time -= time();
- $next_time *= 1000;
- $next_time = 0 if $next_time < 0;
- $_watcher_timer = Gtk->timeout_add( $next_time,
- \&_loop_event_callback
- );
- }
-
- It is often empty in bridges that implement their own event loops.
-
- =item loop_reset_time_watcher NEXT_EVENT_TIME
-
- Reset a time watcher, often by stoping or destroying an existing one
- and creating a new one in its place. This function has the same
- semantics as (and is often implemented in terms of)
- loop_resume_time_watcher(). It is usually more expensive than that
- function, however. Again, from Gtk:
-
- sub loop_reset_time_watcher {
- my ($self, $next_time) = @_;
- Gtk->timeout_remove($_watcher_timer);
- undef $_watcher_timer;
- $self->loop_resume_time_watcher($next_time);
- }
-
- =item loop_pause_time_watcher
-
- Pause a time watcher. This should be done without destroying the
- timer, if the underlying event loop supports that.
-
- POE::Loop::Event supports pausing a timer:
-
- sub loop_pause_time_watcher {
- $_watcher_timer->stop();
- }
-
- =back
-
- =head1 FILE ACTIVITY FUNCTIONS
-
- These functions enable and disable file activity watchers. The pause
- and resume functions are lightweight versions of ignore and watch.
- They are used to quickly toggle the state of a file activity watcher
- without incurring the overhead of destroying and creating them
- entirely.
-
- All the functions take the same two parameters: a file HANDLE and a
- file access MODE.
-
- Modes may be MODE_RD, MODE_WR, or MODE_EX. These constants are
- defined by POE::Kernel and correspond to read, write, or exceptions.
-
- POE calls MODE_EX "expedited" because it often signals that a file is
- ready for out-of-band information. Not all event loops handle
- MODE_EX. For example, Tk:
-
- sub loop_watch_filehandle {
- my ($self, $handle, $mode) = @_;
- my $fileno = fileno($handle);
-
- # The Tk documentation implies by omission that expedited
- # filehandles aren't, uh, handled. This is part 1 of 2.
- confess "Tk does not support expedited filehandles"
- if $mode == MODE_EX;
- ...
- }
-
- =over 2
-
- =item loop_watch_filehandle HANDLE, MODE
-
- Watch a file HANDLE for activity in a given MODE. Registers the
- HANDLE (or, more often its file descriptor via fileno()) in the given
- MODE with the underlying event loop.
-
- POE::Loop::Select sets a vec() bit so the next select() call will know
- about the handle. It also tracks which file descriptors it has
- active.
-
- sub loop_watch_filehandle {
- my ($self, $handle, $mode) = @_;
- my $fileno = fileno($handle);
- vec($loop_vectors[$mode], $fileno, 1) = 1;
- $loop_filenos{$fileno} |= (1<<$mode);
- }
-
- =item loop_ignore_filehandle HANDLE, MODE
-
- Stop watching a file HANDLE in a given MODE. Stops (and possibly
- destroys) an event watcher corresponding to the HANDLE and MODE.
-
- POE::Loop::Poll manages the descriptor/mode bits out of its
- loop_ignore_filehandle() function. It also performs some cleanup if a
- descriptors has been totally ignored.
-
- sub loop_ignore_filehandle {
- my ($self, $handle, $mode) = @_;
- my $fileno = fileno($handle);
-
- my $type = mode_to_poll($mode);
- my $current = $poll_fd_masks{$fileno} || 0;
- my $new = $current & ~$type;
-
- if ($new) {
- $poll_fd_masks{$fileno} = $new;
- }
- else {
- delete $poll_fd_masks{$fileno};
- }
- }
-
- =item loop_pause_filehandle HANDLE, MODE
-
- This is a lightweight form of loop_ignore_filehandle(). It is used
- along with loop_resume_filehandle() to temporarily toggle a watcher's
- state for a file HANDLE in a particular mode.
-
- Some event loops, such as Event.pm, support their file watchers being
- disabled and re-enabled without the need to destroy and re-create
- entire objects.
-
- sub loop_pause_filehandle {
- my ($self, $handle, $mode) = @_;
- my $fileno = fileno($handle);
- $fileno_watcher[$fileno]->[$mode]->stop();
- }
-
- By comparison, the loop_ignore_filehandle() function for Event.pm
- involves canceling and destroying a watcher object. This can be quite
- expensive.
-
- sub loop_ignore_filehandle {
- my ($self, $handle, $mode) = @_;
- my $fileno = fileno($handle);
-
- # Don't bother removing a select if none was registered.
- if (defined $fileno_watcher[$fileno]->[$mode]) {
- $fileno_watcher[$fileno]->[$mode]->cancel();
- undef $fileno_watcher[$fileno]->[$mode];
- }
- }
-
- =item loop_resume_filehandle HANDLE, MODE
-
- This is a lightweight form of loop_watch_filehandle(). It is used
- along with loop_pause_filehandle() to temporarily toggle a a watcher's
- state for a file HANDLE in a particular mode.
-
- =back
-
- =head1 SEE ALSO
-
- L<POE>, L<POE::Loop::Event>, L<POE::Loop::Gtk>, L<POE::Loop::Poll>,
- L<POE::Loop::Select>, L<POE::Loop::Tk>.
-
- =head1 BUGS
-
- Signal handlers are often repeated between bridges:
- http://rt.cpan.org/NoAuth/Bug.html?id=1632
-
- =head1 AUTHORS & LICENSING
-
- Please see L<POE> for more information about authors, contributors,
- and POE's licensing.
-
- =cut
-