package Event::Lib; use 5.006; use strict; use warnings; require Exporter; require XSLoader; our @ISA = qw(Exporter); our $VERSION = '1.03'; XSLoader::load('Event::Lib', $VERSION); eval q{ use constant _EVENT_LOG_NONE => &_EVENT_LOG_ERR + 1; }; @Event::Lib::event::ISA = @Event::Lib::signal::ISA = @Event::Lib::timer::ISA = qw/Event::Lib::base/; our %EXPORT_TAGS = ( 'all' => [ qw( event_init event_priority_init event_log_level event_register_except_handler event_fork event_mainloop event_one_loop event_one_nbloop event_new event_add signal_new timer_new EV_PERSIST EV_READ EV_SIGNAL EV_TIMEOUT EV_WRITE _EVENT_LOG_DEBUG _EVENT_LOG_MSG _EVENT_LOG_WARN _EVENT_LOG_ERR _EVENT_LOG_NONE ) ] ); our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); our @EXPORT = qw( event_init event_priority_init event_log_level event_register_except_handler event_mainloop event_one_loop event_one_nbloop event_new signal_new timer_new event_add EV_PERSIST EV_READ EV_SIGNAL EV_TIMEOUT EV_WRITE _EVENT_LOG_DEBUG _EVENT_LOG_MSG _EVENT_LOG_WARN _EVENT_LOG_ERR _EVENT_LOG_NONE ); *Event::Lib::base::add = \&event_add; *Event::Lib::base::free = \&event_free; sub AUTOLOAD { # This AUTOLOAD is used to 'autoload' constants from the constant() # XS function. my $constname; our $AUTOLOAD; ($constname = $AUTOLOAD) =~ s/.*:://; if ($constname eq 'constant') { require Carp; Carp::croak("&Event::Lib::constant not defined"); } my ($error, $val) = constant($constname); if ($error) { require Carp; Carp::croak($error); } { no strict 'refs'; *$AUTOLOAD = sub { $val }; } goto &$AUTOLOAD; } 1; __END__ =head1 NAME Event::Lib - Perl extentions for event-based programming =head1 SYNOPSIS use Event::Lib; use POSIX qw/SIGINT/; my $seconds; sub timer { my $event = shift; print "\r", ++$seconds; $event->add(1); } sub reader { my $event = shift; my $fh = $event->fh; print <$fh>; $event->add; } sub signal { my $event = shift; print "Caught SIGINT\n"; } my $timer = timer_new(\&timer); my $reader = event_new(\*STDIN, EV_READ, \&reader); my $signal = signal_new(SIGINT, \&signal); $timer->add(1); # triggered every second $reader->add; $signal->add; event_mainloop; =head1 DESCRIPTION This module is a Perl wrapper around libevent(3) as available from L. It allows to execute a function whenever a given event on a filehandle happens, a timeout occurs or a signal is received. Under the hood, one of the available mechanisms for asynchronously dealing with events is used. This could be C, C or C. The variables that you may set are the following: =over 4 =item * EVENT_NOPOLL =item * EVENT_NOSELECT =item * EVENT_NOEPOLL =item * EVENT_NODEVPOLL =item * EVENT_NOKQUEUE =back If you set all of the above variables, it is a fatal error and you'll receive the message C. There is one other variable available: =over 4 =item * EVENT_LOG_LEVEL This is the environment-variable version of set_log_level() intended to conveniently run your script more verbosely for debugging purpose. The lower this value is, the more informational output libevent produces on STDERR. C means maximum debugging output whereas C means no output at all: $ EVENT_LOG_LEVEL=0 perl your_script.pl =back =head1 EXAMPLE: A SIMPLE TCP SERVER Here's a reasonably complete example how to use this library to create a simple TCP server serving many clients at once. It makes use of all three kinds of events: use POSIX qw/SIGHUP/; use IO::Socket::INET; use Event::Lib; $| = 1; # Invoked when a new client connects to us sub handle_incoming { my $e = shift; my $h = $e->fh; my $client = $h->accept or die "Should not happen"; $client->blocking(0); # set up a new event that watches the client socket my $event = event_new($client, EV_READ|EV_PERSIST, \&handle_client); $event->add; } # Invoked when the client's socket becomes readable sub handle_client { my $e = shift; my $h = $e->fh; printf "Handling %s:%s\n", $h->peerhost, $h->peerport; while (<$h>) { print "\t$_"; if (/^quit$/) { # this client says goodbye close $h; $e->remove; last; } } } # This just prints the number of # seconds elapsed my $secs; sub show_time { my $e = shift; print "\r", $secs++; $e->add; } # Do something when receiving SIGHUP sub sighup { my $e = shift; # a common thing to do would be # re-reading a config-file or so ... } # Create a listening socket my $server = IO::Socket::INET->new( LocalAddr => 'localhost', LocalPort => 9000, Proto => 'tcp', ReuseAddr => SO_REUSEADDR, Listen => 1, Blocking => 0, ) or die $@; my $main = event_new($server, EV_READ|EV_PERSIST, \&handle_incoming); my $timer = timer_new(\&show_time); my $hup = signal_new(SIGHUP, \&sighup); $_->add for $main, $timer, $hup; event_mainloop; __END__ You can test the above server with this little program of which you can start a few several simultaneous instances: use IO::Socket::INET; my $server = IO::Socket::INET->new( Proto => 'tcp', PeerAddr => 'localhost', PeerPort => 9000, ) or die $@; print $server "HI!\n"; sleep 10; print $server "quit\n"; __END__ =head1 OTHER EVENT MODULES There are already a handful of similar modules on the CPAN. The two most prominent ones are I and the venerable I framework. =head2 Event In its functionality it's quite close to I with some additional features not present in this module (you can watch variables, for example). Interface-wise, it's quite a bit heavier while I gets away with just a handful of functions and methods. On the other hand, it has been around for years and so you may expect I to be rock-stable. The one main advantage of I appears to be in its innards. The underlying I is capable of employing not just the C and C