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

NAME

Event - Event loop processing

SYNOPSIS

 use Event qw(loop unloop);
 
 # initialize application
 Event->type(attribute => value, ...);
    
 my $ret = loop();
    
 # and some callback will call
 unloop('ok');

DESCRIPTION

The Event module provide a central facility to watch for various types of events and invoke a callback when these events occur. The central idea is to delay the handling of events in order that they can be dispatched by priority and also when it is known to be safe for callbacks to execute.

API

Events (the occurance of such) are noticed and queued by event watchers. The creation and configuration of event watchers is the primary topic of the rest of this document.

The following functions control and interrogate the event loop as a whole:

$result = loop([$timeout])

Will enter a loop that calls one_event() until unloop() is called. The argument passed to unloop() is the return value of loop(). Loops can be nested.

unloop($result)

Make the inner-most loop() return with $result.

unloop_all()

Cause all pending loop()s to return immediately. This is not implemented with die. It is implemented to work as if unloop(undef) was called for all pending loops.

sweep([$max_prio])

Queue all pending events and process the ones with priority higher than $max_prio. The default is to process all events except idle events. (Idle events are ignored by sweep.)

one_event([$timeout])

If any events are outstanding then invoke the corresponding callback of the highest priority event. If there are no events available, block until forever or until $timeout. Use of this API is not recommended because it doesn't trap exceptions and is not very efficient.

all_watchers()

Returns a list of all watchers (including stopped events).

all_running()

Returns a list of all watchers with active callbacks. Watchers are returned in order of most recent to least recent.

all_idle()

Return all watchers on the idle queue.

Event Watcher Constructors

All watchers are constructed in one of the following ways:

  $w = Event->type( [e_attr1 => $value,]... );
 

or

  use Event::type;
  $w = Event::type( [e_attr1 => $value,]...);

Where type is substituted with the kind of watcher. Built-in types include idle, inactivity, io, signal, timer, and var.

The new watcher object either has reasonable defaults or can be customized by passing attributes to the constructor. When created, watcher objects are "started" and already waiting for events (see $event->start below).

Shared Watcher Attributes

Watchers are configured with attributes (also called properties). This is a fancy way of saying that a watcher object works like hash reference. For example:

   $watcher->{e_cb} = \&some_code;   #callback

   print "$watcher->{e_hits} events happened; Wow!\n";

The Event modules reserves all keys beginning with 'e_'. You are free to use other keys for any purpose.

The following attributes are supported by all types of watchers. Most watchers also offer additional attributes to customize their particular specialty.

e_id => $int

An integer that uniquely identifies a watcher. This attribute is read-only. You should use this to test for equality (until the equality test for tied objects is fixed).

e_cb => \&code
e_cb => [$class_or_object, $method]

The function or method to call when an event happens. The callback is invoked with the $event as its only argument. An $event works like a watcher except that it has a few extra hash keys which are event specific.

Perhaps you are wondering what happens if something goes wrong and an untrapped die occurs within your callback? $Event::DIED is just for this purpose. See the full description of DIED below.

e_clump => $bool

If an event occurs many times before any events can be processed then a watcher must record this somehow. Currently there are two choice. If clump is false then a new event will be generated for each occurance of an event. On the other hand, if clump is true then each event occurance will increment e_hits. Clumping is slightly more efficient than not clumping.

e_hits => $int

A watcher increments e_hits every time it registers an event. This is usually only relevant if e_clump is enabled. This attribute is read-only.

e_prio => $int

Priority is used to order events queued for processing. Meaningful priorities range from -1 to 6 inclusive. Lower numbers mean higher priority (-1 is the highest priority and 6 is the lowest). When multiple events happen, the events with the highest priority are serviced firstly.

A negative priority indicates that the callback should be invoked immediately upon event occurance. Use this with caution. While it may seem advantageous to use negative priorities it defeats the purpose of even having an event queue in the first place.

Also of note: you cannot set the priority with event constructors. Instead use e_nice to specify an offset from the default priority. (Each event type has a default priority.)

e_desc => $string

Some identifying name. If not passed explicitly to the constructor, it will be initialized with some string that attempts to identify the location in the source code where the watcher was constructed.

e_flags => $bits

The e_flag attribute encodes some information about the state of an event. [XXX Fill in exact bits]

e_repeat => $bool

The repeat flag controls whether callback should be one-shot or if the watcher should continue waiting for new events of this kind occur. The default depends on the type of watcher. io, signal, and var default to true.

e_debug => $bool

Debugging can be activated globally or per watcher. When debugging is enabled for a particular watcher, $Event::DebugLevel is treated as two levels higher. Levels of 1, 2, 3, or 4 give progressively more diagnostics on STDERR.

e_reentrant => $bool

By default, callbacks are allowed to invoke sweep or loop which in turn may invoke the same callback again recursively. This can be useful, but can also be confusing. Disable this feature per watcher by setting reentrant to false. This will cause the watcher to be suspended during recursive calls to sweep or loop.

Shared Watcher Methods

The following methods can be invoked on an event:

$watcher->start

Activate the watcher. Many constructors will automatically invoke $watcher->start.

$watcher->again

Same as the start method except in the case of watchers with special repeat behavior. For example, repeating timers recalcuate their alarm time using the e_interval parameter.

$watcher->stop

Don't look for events any more. Note that a stopped watcher can be reactivated by calling the start or again methods.

$watcher->cancel

Stop and unconditionally destroy $watcher. If an attempt to made to use $watcher after calling cancel then an exception will be thrown.

$watcher->suspend

A suspended watcher will stop queuing events until it is resumed.

$watcher->resume

Revives a watcher that has been suspended.

$watcher->now

Make the watcher callback trigger now. The callback may or may not run immediately depending upon the watcher's priority.

Watcher Types

idle

The callback is invoked only if no other event is pending.

var

Extra attribute: e_var => \$var, e_poll => 'rw'

Triggered when the value of $var is read or modified.

timer

Extra attributes: e_at => $time, e_interval => $sec, e_hard => $bool

The $time and $sec are in seconds. Fractional seconds may be used if Time::HiRes is available.

If e_interval set then the watcher will automatically reshedule repeatedly. Be aware that due to lags in the event loop the e_interval timeout may already be in the past. If the e_hard flag is set, the event will be queued for execution relative to the last time the callback was invoke. However, if e_hard is false the new timeout will be calculated relative to the current time (this is the default).

The constructor also accepts an e_after attribute for quick initialization.

io

Extra attributes: e_fd => $fd, e_poll => "rwe", e_got => "rwet", [e_timeout => $seconds]

The callback is invoked when the file descriptor, e_fd, has data to be read, written, or pending exceptions. e_fd can be a glob, an IO::Handle object, or a file number (file descriptor). The e_poll attribute specifies which events to watch for. It consist of a string of letters representing flags. "r" indicates readable. "w" indicates writable. "e" indicates pending exceptions.

When the callback is invoked, e_got is set to tell you which conditions of e_poll were triggered. The e_got attribute is read-only. If you think testing for letters is too slow you can also use e_got as a bit mask. The bit constants are exportable from Event::Watcher.

Note that it is your choice whether to have multiple watchers per file descriptor or a single watcher to handle all conditions.

signal

Extra attribute: e_signal => $str

The callback will be invoked when the specified signal is received. The $str string should be something like 'INT' or 'QUIT'. See the documentation on %SIG for a list.

semaphore

Not implemented.

msg

Not implemented.

CUSTOMIZATION

While the bulk of Event's implementation is in C (for maximum performance), a broad range of customization hooks are available.

  • $Event::DebugLevel

    Enables progressively more debugging output. Meaningful levels range from 1 (least output) to 5 (most output). Also see e_debug.

  • $Event::Eval

    Strictly for debugging. Do not enable this unless you know what you are doing.

  • $Event::DIED

    When loop or sweep is called, an exception context is established that lasts throughout event processing. If an exception is detected then $Event::DIED is invoked:

      $Event::DIED->($watcher, $@);
     

    The default hook uses warn to print the exception. After the DIED handler returns, event processing continues as if nothing happened. If you'd like to see more detailed output you can use the verbose handler (below) or write your own.

      $Event::DIED = \&Event::verbose_exception_handler;
  • Event->add_hooks(key => sub { ... }, ...);

    The add_hooks method allows customization at key junctures in the optimized event processes core. The currently support hooks are listed below:

      hook          purpose
      ------------- ----------------------------------------------
      prepare       returns minimum time to block (timeable)
      check         assess state after normal return from select/poll
      asynccheck    check for signals, etc
      callback      invoked before each event callback

C API

Event also has a direct C API for high-performance event dispatching. See Event::MakeMaker.

WHAT ABOUT THREADS?

Event loops and threads are two different solutions to the same problem: asynchronous processing.

Event loops have been around since the beginning of computing. They are well understood and proven to be a good solution for many applications. While they make use of basic operating system services, the bulk of their implementation is usually outside the kernel. Therefore, while an event loop may appear to do many things in parallel, it does not. Actions are always executed sequentially. This implies that long running callbacks must be avoided because they halt event processing.

Event loops work well when actions are short and to the point. Long-running tasks must be broken into short steps and scheduled for execution. Some sort of a state machine is usually required. For example, consider a JPEG file download and render. When some new bytes are available they must be sorted to the right place on the screen. Quite a lot of state must be kept to keep track of how much has been rendered and how to process subsequent incoming bytes. While a web browser can easily get by without threads, a big complex web application server might be a great deal simpler to implement in a multithreaded fashion.

Threads can either substitute for an event loop or complement it. Threads are similar to processes in that the operating system manages task switching for you. However, the difference is that all threads share the same address space. This is good and bad. Much higher performance can be acheived, but since data is shared between threads extreme care must be taken when accessing or modifying global data. The operating system can switch threads at any moment or can execute multiple threads simultaineously. I hope this sounds dangerous! It is. Threads can introduce maddeningly complicated and hard to debug syncronization problems. Threads are like rocket fuel. They are essential when you really need them but most applications would be better off with a simple event loop. Even if threads are genuinely needed, consider confining them to the parts of an application where truly scalable performance is really worth the difficulty of a thread safe implementation. For example, most GUIs applications do not need threads and most scientific compute intensive problems can be isolated from event dispatching. On the other hand, high performance transaction servers generally do need a truly multithreaded implementation.

Another consideration is that threads are not quite as widely available as event loops. While a few forward-thinking operating systems have offered threads since the beginning, their addition to many popular operating systems is much more recent and some still offer no threads support. If portability is a requirement, one must check that threads support is available and also carefully test to be sure that a particular threads implementation supports the features you need. It is likely that all platforms will have a solid implementation soon, but at this point in history it is best to double check.

BUGS

bless does not work with watchers. If you attempt to bless a watcher into a different class, the blessing will not stick. The class will revert back to the original class. Unfortunately, this cannot really be fixed properly until perl has better support for custom data types.

The meaning of $io->{e_timeout}=0 might change. Use undef to unset the timeout.

ALSO SEE

Time::HiRes and NetServer::ProcessTop.

SUPPORT

Please direct your insights and complaints to the perl-loop@perl.org mailing list!

AUTHORS

Joshua N. Pritikin <bitset@mindspring.com>

Initial 0.01 implementation by Graham Barr <gbarr@pobox.com>. Also, contributions from:

 Gisle Aas E<lt>F<gisle@aas.no>E<gt>
 E<lt>F<jan.dubois@ibm.net>E<gt> (Win32)
 E<lt>F<Matija.Grabnar@arnes.si>E<gt> (File::Tail)
 Nick Ing-Simmons E<lt>F<nick@ni-s.u-net.com>E<gt> (Tk)
 Mark Mielke E<lt>F<Mark.Mielke.markm@nt.com>E<gt>
 Sarathy E<lt>F<gsar@engin.umich.edu>E<gt>

COPYRIGHT

Copyright © 1997-1999 Joshua Nathaniel Pritikin & Graham Barr. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

1 POD Error

The following errors were encountered while parsing the POD:

Around line 463:

Non-ASCII character seen before =encoding in '©'. Assuming CP1252