NAME¶
Event - Event loop processing
SYNOPSIS¶
use Event qw(loop unloop);
# initialize application
Event->flavor(attribute => value, ...);
my $ret = loop();
# and some callback will call
unloop('ok');
DESCRIPTION¶
ALERT: Marc Lehmann may have taken over the future of event loops in Perl. Check
out his libev library and EV Perl module. 25 Aug 2009
The Event module provide a central facility to watch for various types of events
and invoke a callback when these events occur. The idea is to delay the
handling of events so that they may be dispatched in priority order when it is
safe for callbacks to execute.
Events (in the ordinary sense of the word) are detected by
watchers,
which reify them as
events (in the special Event module sense). For
clarity, the former type of events may be called "source events",
and the latter "target events". Source events, such as signals
arriving, happen whether or not they are being watched. If a source event
occurs which a watcher is actively watching then the watcher generates a
corresponding target event. Target events are only created by watchers. If
several watchers are interested in the same source event then each will
generate their own target event. Hence, any particular source event may result
in zero, one, two, or any number of target events: the same as the number of
watchers which were actively watching for it.
Target events are queued to be processed in priority order (priority being
determined by the creating watcher) and in FIFO order among events of the same
priority. Queued ("pending") events can, in some cases, be cancelled
before being processed. A queued event is processed by being passed to the
callback function (or method on a particular object or class) which was
specified to the watcher.
A watcher, once created, operates autonomously without the Event user having to
retain any reference to it. However, keeping a reference makes it possible to
modify most of the watcher's characteristics. A watcher can be switched
between active and inactive states. When inactive, it does not generate target
events.
Some types of source event are not reified as target events immediately. Signals
received, for example, are counted initially. The counted signals are reified
at certain execution points. Hence, signal events may be processed out of
order, and if handled carelessly, on the wrong side of a state change in event
handling. A useful way to view this is that occurrence of the source event is
not actually the arrival of the signal but is triggered by the counting of the
signal.
Reification can be forced when necessary. The schedule on which some other
events are created is non-obvious. This is especially the case with watchers
that watch for a condition rather than an event. In some cases, target events
are generated on a schedule that depends on the operation of the event loop.
PERL API¶
Events (the occurrence 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 or 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($result)
- Cause all pending loop()s to return immediately. This is not
implemented with "die". It is works as if
"unloop($result)" were called for all nested loops.
- sweep([$max_prio])
- Queue all pending events and dispatch any with priority strictly less than
$max_prio (the highest priority is 0). The default is to process all
events except idle events. (While idle events are ignored by sweep,
idle watchers are not ignored. If you want to avoid triggering an
idle watcher then set "max" to "undef" or
"stop()" it.)
- 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
forever or until $timeout. Use of this API is not recommended because it
is not efficient and does not trap exceptions. However, you might wish to
understand how it works:
- 1.
- Queue asyncronous events (signals, etc). That is, previously recorded
events are reified.
- 2.
- If there are any events with priority 5 or less (see StarvePrio) then
service the next one and return.
- 3.
- Calculate the maximum wait time (minimum time till the next timer
expiration) and pass control to the poll/select system call. Upon return,
queue all pending events.
- 4.
- Queue asyncronous events again.
- 5.
- If there are any events then service the next one and return.
- 6.
- Service the next idle watcher.
StarvePrio is the priority level for which events are dispatched during step 2.
It cannot be changed without a recompile. In the rare case that an event is
always pending at step 2 then I/O watchers will starve. However, this is
highly unlikely since async watchers should never queue events so
rapidly.
- all_watchers()
- Returns a list of all watchers (including stopped watchers).
- all_running()
- Returns a list of all watchers with actively running callbacks. Watchers
are returned in order of most recent to least recent.
- all_idle()
- Returns a list of all the idle watchers. If the event queue is very busy,
all the idle watchers will sit on the idle queue waiting to run. However,
be aware that if an idle watcher has the "max" attribute set
then it will queue a normal event when its "max" wait time is
exceeded.
- queue_pending()
- Examines asynchronous source events (timers & signals) and reifies
them as target events. "queue_pending()" is only called
implicitly by "sweep()" and "one_event()". Otherwise,
"queue_pending()" is not called implicitly.
NOTE: Signal watchers generate target events according to which watchers are
active at the time that "queue_pending()" is called rather than
according to the time the signal is received. This is best explained by
example. See the file "demo/queue_pending.t".
Event Watcher Constructors¶
All watchers are constructed in one of the following ways:
$w = Event->flavor( [attr1 => $value,]... );
$w = Event::flavor($Class, [attr1 => $value,]...);
$w = Event::flavor->new([attr1 => $value,]...);
Where
flavor is substituted with the kind of watcher. Built-in types
include idle, io, signal, timer, and var.
New watchers (hopefully) have reasonable defaults and can also be customized by
passing extra attributes to the constructor. When created, watcher objects are
"started" and are waiting for events (see
"$event->start" below).
NetServer::Portal can display watchers in real-time, formatted similarly to the
popular "top" program. You may find this a useful aide for
debugging.
Shared Watcher Attributes¶
Watchers are configured with attributes (also known as properties). For example:
$watcher->cb(\&some_code); # set callback
warn $event->w->desc.": ".$event->hits." events happened; Wow!";
All watchers support the following attributes: cb, cbtime, debug, desc, prio,
max_cb_tm, reentrant, and repeat. Watcher constructors accept the preceding
and additionally: async and nice. Moreover, watchers also offer extra
attributes according to their specialty.
Shared Watcher Methods¶
The following methods are available for all watchers:
- $watcher->start
- Activate the watcher. Watchers refuse to "start()" without
sufficient configuration information to generate events. Constructors
always invoke "start()" unless the "parked=>1"
option is requested. You will need to set the parked option if you
preallocate unconfigured watchers.
Note: If there are any unreified asynchronous events that are of interest to
the watcher, it will see these events even though they happened before it
was started. This affects signal watchers, but there will only be existing
unreified signal events if Event was already handling the signal, which it
would only do if there were another active watcher for the same signal. If
this situation might occur, and it would be a problem for the new watcher
to see older events, call "queue_pending()" immediately before
starting the new watcher in order to reify any outstanding events. This
explaination may be more clear if read along with
"demo/queue_pending.t".
- $watcher->again
- This is the same as the "start" except if a watcher has special
repeat behavior. For example, repeating timers recalculate their alarm
time using the "interval" parameter.
- $watcher->now
- Cause the watcher to generate an event, even if it is stopped. The
callback may or may not run immediately depending upon the event's
priority. If you must unconditionally invoke the callback, consider
something like
$w->cb->($w);
- $watcher->stop
- Don't look for events any more. Running events are allowed to complete but
pending events are cancelled. Note that a stopped watcher can be
reactivated by calling the "start" or "again" methods.
Watchers are stopped implicitly if their new configuration deprives them of
the ability to generate events. For instance:
my $io_watcher = Event->io(timeout => 1); # started
$io_watcher->timeout(undef); # stopped implicitly
$io_watcher->timeout(1); # still stopped
$io_watcher->start; # restarted
- $watcher->cancel
- Stop and destroy $watcher. Running events are allowed to complete but
pending events are cancelled. Cancelled watchers are no longer valid
except for read-only operations. For example, prio() can return the
watcher's priority, but start() will fail.
- $watcher->is_cancelled
- Reports whether the $watcher has been cancelled.
- $watcher->is_active
- Reports whether the $watcher has been started. The return value is not
affected by suspend.
- $watcher->is_running
- Zero if the callback is not running. Otherwise, the number of levels that
the callback has been entered. This can be greater than one if a
"reentrant" callback invokes "loop" (or
"sweep", with lesser probability).
- $watcher->is_suspended
- Reports whether the $watcher is suspended. Suspension is a debugging
feature; see the discussion of the "suspend" attribute
below.
- $watcher->pending
- In scalar context, returns a boolean indicating whether this watcher has
any events pending in the event queue. In array context, returns a list of
all the watcher's pending events.
Note that this does not check for unreified asynchronous events. Call
"queue_pending()" first if you want to see signals received
since the last operation of the event loop.
Watcher Types¶
- idle
- Extra attributes: min => $seconds, max => $seconds
Watches for the Event system to be idle, i.e., to have no events pending. If
the system is never idle, an event will be generated at least every
"max" seconds. While Event is idle, events will be generated not
more often than "min" seconds.
If neither "min" nor "max" is specified, the watcher
defaults to one-shot behaviour ("repeat" false), otherwise it
defaults to repeating. In either case, the default can be overidden by
specifying a "repeat" attribute. "min" defaults to
0.01, and "max" defaults to infinity.
- var
- Extra attributes: var => \$var, poll => 'rw'
Var watchers generate events when the given variable is read from or written
to, as specified by "poll". "poll" defaults to
"w".
As perl is a concise language, it is often difficult to predict when a
variable will be read. For this reason, variable watchers should poll only
for writes unless you know what you are doing.
- timer
- Extra attributes: at => $time, after => $sec, interval => $sec,
hard => $bool
Generate events at particular times. The $time and $sec are in seconds.
Fractional seconds may be used if Time::HiRes is available. "at"
and "after" are mutually exclusive.
"at" or "after" specify the initial time that the event
will trigger. Subsequent timer events occur at intervals specified by
"interval" or "after" (in that order of preference) if
either was supplied. The timer defaults to one-shot behaviour if
"interval" was not specified, or repeating behaviour if
"interval" was specified; in either case this can be overridden
by providing "repeat" explicitly.
You need to know the time at the start of today if you are trying to set
timers to trigger at day relative times. You can find it with:
use Time::Local;
my $TodaySeconds = int timelocal(0,0,0,(localtime)[3,4,5]);
This calculation may seem a little heavy weight. If you want to use UTC
rather than local time then you can use this instead:
my $TodaySeconds = time - time % 86400;
Beware that, due to lags in the event loop, the "interval" timeout
may already be in the past. If the "hard" flag is set, the event
will be queued for execution relative to the last time the callback was
invoked. However, if "hard" is false the new timeout will be
calculated relative to the current time. "hard" defaults to
false.
- io
- Extra attributes: fd => $fd, poll => 'rwe' [timeout => $seconds,
hard => $bool, timeout_cb => \&code]
The callback is invoked when the file descriptor, "fd", has data
to be read, written, or pending exceptions. "fd" can be a GLOB,
an IO::Handle object, or a file number (file descriptor). "poll"
defaults to "r".
Note that it is your option whether to have multiple watchers per file
handle or to use a single watcher for all event conditions.
If "timeout" is set, events are also generated regularly if no
actual I/O event occurs. If "timeout_cb" is set then timeouts
use this alternate callback instead of the main callback.
- signal
- Extra attribute: signal => $str
Generates events based on signal arrival. The events are not actually
generated immediately when the signal arrives: signals received are
counted and reified by "queue_pending()" or implicitly by
"one_event()". Several signals of the same type may be merged
into a single event. In such cases, the number of signals represented by a
single event is stored in the "hits" attribute.
PRIORITY¶
Priority is used to sort the event queue. Meaningful priorities range from -1 to
6 inclusive. Lower numbers mean higher priority (-1 is the highest priority
and 6 is the lowest). If multiple events get queued, the ones with the highest
priority are serviced first. Events with equal priority are serviced in
first-in-first-out order.
use Event qw(PRIO_HIGH PRIO_NORMAL); # some constants
LEVELS: -1 0 1 2 3 4 5 6
----------------------+-------------+---------------
PRIO_HIGH PRIO_NORMAL
A negative priority causes the callback to be invoked immediately upon event
occurrence. Use this with caution. While it may seem advantageous to use
negative priorities, they bypass the whole point of having an event queue.
Each watcher has a
default priority, assigned by its constructor:
io PRIO_NORMAL
signal PRIO_HIGH
timer PRIO_NORMAL
var PRIO_NORMAL
Default priorities are stored in ${"Event::${type}::DefaultPriority"}.
If the default priority is not satisfactory for your purposes, the constructor
options "nice", "async", or "prio" can be used
to adjust it. "nice" specifies an offset from the default priority;
"async" forces the priority to -1; and "prio" assigns a
given priority of your choice. If more than one of these options are given
then "prio" overrides "async" overrides "nice".
WATCHER CONSTRUCTOR ATTRIBUTES¶
These options are only supported as constructor arguments.
- after => $seconds
- See the discussion of the timer watcher.
- async => $bool
- If $bool then the watcher priority is set to -1.
- nice => $offset
- Offset from the default priority.
- parked => $yes
- By default, watcher constructors automatically invoke the
"start()" method. If you don't want the watcher started then
request "parked=>1".
WATCHER ATTRIBUTES¶
- at => $time
- The expiration time in the same units as the system clock. For a timer,
"at" will usually be in the future.
- cb => \&code
- cb => [$class_or_object, $method_name]
- The function or method to call when an event is dispatched. The callback
is invoked with $event as its only argument.
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.
- cbtime => $time
- When the callback was invoked most recently.
- data => $anything
- The "data()" method associates arbitrary data with a watcher.
This method is not intended for implementers of watchers. If you are
subclassing or implementing a watcher, consider the "private()"
method.
- 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.
- desc => $string
- An identifying name. If this is not passed explicitly to the constructor,
it will be initialized with a string that attempts to identify the
location in the source code where the watcher was constructed.
- fd => $filehandle
- This attribute can accept either a perl-esque filehandle or a system call
derived file descriptor number.
- hard => $bool
- Determines how repeating timers (or timeouts) are recalculated. The timer
is restarted either before or after the callback depending on whether it
is true or false, respectively. In long-running callbacks this can make a
significant difference.
- interval => $seconds
- How long between repeating timeouts. The "at" attribute is
recalculated using "interval" upon callback return.
- max => $seconds
- The maximum number of seconds to wait before triggering the callback.
Similar to a "timeout".
- max_cb_tm => $seconds
- The maximum number of seconds to spend in a callback. If a callback uses
more time then it is aborted. Defaults to 1 sec. This feature is normally
disabled. See Event::Stats.
- min => $seconds
- Enforce a minimum number of seconds between triggering events.
- poll => $bits
- Determines which kinds of events are of interest. This attribute can be
set with either strings or bit constants. The bit constants are available
via 'use Event::Watcher qw(R W E T);'.
string constant description
------ -------- ---------------
'r' R read
'w' W write
'e' E exception
't' T timeout
Thus, both of these statements enable interest in read:
$w->poll($w->poll . 'r');
$w->poll($w->poll | R);
A given type of watcher may support all or a subset of the available
events.
- prio => $level
- Changes the watcher's priority to the given level. Events generated by a
watcher usually inherit the priority of the watcher.
- private => $anything
- Use the "private()" method to associate arbitrary data with a
watcher. This method is intended for implementers of watchers or watcher
subclasses. Each caller's package accesses its own private attribute.
- 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. Moreover, if
you keep reentering callbacks you will quickly run out of stack space.
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".
- repeat => $bool
- The repeat flag controls whether the callback should either be one-shot or
continue waiting for new events. The default setting depends on the type
of watcher. io, signal, and var default to true.
- signal => $str
- The callback is invoked after the specified signal is received. The $str
string should be something like 'INT' or 'QUIT'. Also see the
documentation for %SIG.
A given signal can be handled by %SIG or Event, but not both at the same
time. Event handles the signal as long as there is at least one active
watcher. If all watchers for the signal are cancelled or stopped then
Event sets the signal handler to SIG_DFL.
- suspend => $bool
- Stop looking for events. Running events are allowed to complete, but
queued events are cancelled.
Suspend is for debugging. If you suspend all watchers in an application then
you can examine the complete state unchanged for as long as you like
without worrying about timer expirations. If you actually wish to stop a
watcher then use the "stop()" method.
- timeout => $seconds
- The number of seconds before a watcher times out.
- timeout_cb => \&code
- timeout_cb => [$class_or_object, $method_name]
- This is an optional attribute for use when it is desired that timeouts be
serviced in a separate code path than normal events. When this attribute
is unset, timeouts are serviced by "cb".
- var => $ref
- A reference to the variable being watched.
EVENT ATTRIBUTES¶
- got => $bits
- "got" is available in the callback of watchers with
"poll". "got" is in the same format as
"poll" except that it gives what kind of event actually
happened. In contrast, "poll" is just an indication of
interest.
- hits => $int
- Signals in quick succession can be clumped into a single event. The number
of signals clumped together is indicated by this attribute. This is always
one for event types which don't clump.
- prio => $level
- Be aware that this priority can differ from the watcher's priority. For
instance, the watcher's priority may have changed since the event was
generated. Moreover, the C extension API offers the freedom to queue
events of arbitrary priority.
- w => $watcher
- This method return the event's watcher. It is read-only.
Customization and Exceptions¶
- •
- $Event::DebugLevel
Enables progressively more debugging output. Meaningful levels range from 1
(least output) to 5 (most output). Also see "debug".
- •
- $Event::DIED
When "loop" or "sweep" is called, an exception context
is established for the duration of event processing. If an exception is
detected then $Event::DIED is invoked. The default hook uses
"warn" to output the exception. After the DIED handler
completes, event processing continues as if nothing happened.
If you'd like more detailed output you can install the verbose handler:
$Event::DIED = \&Event::verbose_exception_handler;
Or you can write your own. The handler is invoked like this:
$Event::DIED->($event, $@);
If you do not want to continue looping after an error, you can do something
like this:
$Event::DIED = sub {
Event::verbose_exception_handler(@_);
Event::unloop_all();
};
- •
- Event->add_hooks(key => sub { ... }, ...);
The bulk of Event's implementation is in C for maximum performance.
The "add_hooks" method allows insertion of perl code at key
points in the optimized event processing core. While flexible, this can
hurt performance *significantly*. If you want customization *and*
performance, please see the C API.
Currently support hooks are detailed as follows:
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 API for callbacks written exclusively in C. 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 event loops make use of basic operating system services, the bulk of their
implementation is usually outside the kernel. While an event loop may appear
to do many things in parallel, it does not, even on multiprocessor hardware.
Actions are always dispatched sequentially. This implies that long running
callbacks must be avoided because otherwise event processing is halted.
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. While a big, complex application
server is usually simpler to implement in a multithreaded fashion, a web
browser can easily get by without threads. Consider a JPEG file download and
render. When some new bytes are available they are sorted to the right place
on the screen. Only a little state must be kept to keep track of how much has
been rendered and to process subsequent incoming bytes.
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. Higher performance can be achieved but since data is
shared between threads, extreme care must be taken to access or modify global
data. The operating system can switch threads at any moment or can execute
multiple threads simultaneously. I hope this sounds dangerous! It is! Threads
can introduce maddeningly complicated and hard to debug synchronization
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 multithreaded 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 mandate a truly multithreaded approach.
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 a particular threads implementation to see whether it 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.
Many suggestions by Mark Mielke <Mark.Mielke.markm@nt.com>
WHAT ABOUT NON-PREEMPTIVE THREADS?¶
The Java language is oriented to use non-preemptive threads, yet even Java uses
an event-loop for Swing (AFAIK). That is one of the reasons I don't use Java
for network-centric applications. My belief is that the benefit of
multi-threading is the gain in performance on SMP hardware. In my view,
non-preemptive threads (java green-threads) are usually poor design. I find
them harder to work with, harder to debug, and slower for a rather marginal
gain in readability. I really like working with a state machine. I find it
leads to more stable and better code. It also has the benefit of abstracting
away how concurrency is achieved.
Contributed by artur@vogon-solutions.com, 12 Jul 1999.
BUGS¶
No support for epoll, or better, libevent.
The scope of events is pretty strange compared to most other perl objects. I'm
not sure if this is a bug or a feature (OK, probably it was a mistake). We'll
probably want to re-work things for Perl6.
The meaning of $io->
timeout(0) might change. Use "undef" to
unset the timeout.
There seems to be some sort of bug in the global destruction phase:
Attempt to free unreferenced scalar during global destruction.
Use of uninitialized value during global destruction.
Explicit blessing to '' (assuming package main) during global
destruction.
THE FUTURE¶
Even if this module does not end up being the One and True Event Loop, the
author will insure that it is source compatible with its successor, or arrange
for gradual migration. Back in the early days, the Event programming API was
changing at every release. Care was taken to allow the old API to continue to
work, and the transition was eased by printing out lots of warnings about the
new usage. So you shouldn't sit on your hands in anticipation of the One and
True Event Loop. Just start coding!
ALSO SEE¶
- •
- Useful and Fun
Time::HiRes, NetServer::Portal, Time::Warp
- •
- Message Passing
COPE, IPC::LDT, Event-tcp
- •
- GUI
While Tk does not yet support Event, PerlQt does.
- •
- C API
Inline
SUPPORT¶
If you have insights or complaints then please subscribe to the mailing list!
Send email to:
perl-loop-subscribe@perl.org
AUTHOR¶
Joshua N. Pritikin <
jpritikin@pobox.com>
ACKNOWLEDGMENT¶
Initial 0.01 implementation by Graham Barr <
gbarr@pobox.com>.
Other contributors include at least those lists below and folks mentioned in
the ChangeLog.
Gisle Aas <gisle@aas.no>
Uri Guttman <uri@sysarch.com>
Nick Ing-Simmons <nick@ni-s.u-net.com> (Tk)
Sarathy <gsar@engin.umich.edu>
Jochen Stenzel <perl@jochen-stenzel.de>
COPYRIGHT¶
Copyright X 1997 Joshua Nathaniel Pritikin & Graham Barr
Copyright X 1998, 1999, 2000, 2001, 2002, 2003, 2004 Joshua Nathaniel Pritikin
All rights reserved. This program is free software; you can redistribute it
and/or modify it under the same terms as Perl itself.