--- AnyEvent/README 2005/12/01 21:19:58 1.2 +++ AnyEvent/README 2006/01/08 04:41:08 1.5 @@ -4,26 +4,43 @@ Event, Coro, Glib, Tk - various supported event loops SYNOPSIS - use AnyEvent; + use AnyEvent; - my $w = AnyEvent->timer (fh => ..., poll => "[rw]+", cb => sub { + my $w = AnyEvent->io (fh => ..., poll => "[rw]+", cb => sub { my ($poll_got) = @_; ... }); - my $w = AnyEvent->io (after => $seconds, cb => sub { + + * only one io watcher per $fh and $poll type is allowed (i.e. on a + socket you can have one r + one w or one rw watcher, not any more + (limitation by Tk). + + * the $poll_got passed to the handler needs to be checked by looking for + single characters (e.g. with a regex), as it can contain more event + types than were requested (e.g. a 'w' watcher might generate 'rw' + events, limitation by Glib). + + * AnyEvent will keep filehandles alive, so as long as the watcher + exists, the filehandle exists. + + my $w = AnyEvent->timer (after => $seconds, cb => sub { ... }); - # watchers get canceled whenever $w is destroyed - # only one watcher per $fh and $poll type is allowed - # (i.e. on a socket you cna have one r + one w or one rw - # watcher, not any more. - # timers can only be used once + * io and time watchers get canceled whenever $w is destroyed, so keep a + copy + + * timers can only be used once and must be recreated for repeated + operation (limitation by Glib and Tk). my $w = AnyEvent->condvar; # kind of main loop replacement - # can only be used once - $w->wait; # enters main loop till $condvar gets ->send - $w->broadcast; # wake up waiting and future wait's + $w->wait; # enters main loop till $condvar gets ->broadcast + $w->broadcast; # wake up current and all future wait's + + * condvars are used to give blocking behaviour when neccessary. Create a + condvar for any "request" or "event" your module might create, + "->broadcast" it when the event happens and provide a function that + calls "->wait" for it. See the examples below. DESCRIPTION AnyEvent provides an identical interface to multiple event loops. This @@ -41,6 +58,35 @@ order given. The first one that could be successfully loaded will be used. If still none could be found, it will issue an error. +SUPPLYING YOUR OWN EVENT MODEL INTERFACE + If you need to support another event library which isn't directly + supported by AnyEvent, you can supply your own interface to it by + pushing, before the first watch gets created, the package name of the + event module and the package name of the interface to use onto + @AnyEvent::REGISTRY. You can do that before and even without loading + AnyEvent. + + Example: + + push @AnyEvent::REGISTRY, [urxvt => urxvt::anyevent::]; + + This tells AnyEvent to (literally) use the "urxvt::anyevent::" module + when it finds the "urxvt" module is loaded. When AnyEvent is loaded and + requested to find a suitable event model, it will first check for the + urxvt module. + + The above isn't fictitious, the *rxvt-unicode* (a.k.a. urxvt) uses the + above line exactly. An interface isn't included in AnyEvent because it + doesn't make sense outside the embedded interpreter inside + *rxvt-unicode*, and it is updated and maintained as part of the + *rxvt-unicode* distribution. + +ENVIRONMENT VARIABLES + The following environment variables are used by this module: + + "PERL_ANYEVENT_VERBOSE" when set to 2 or higher, reports which event + model gets used. + EXAMPLE The following program uses an io watcher to read data from stdin, a timer to display a message once per second, and a condvar to exit the @@ -70,8 +116,133 @@ $cv->wait; # wait until user enters /^q/i +REAL-WORLD EXAMPLE + Consider the Net::FCP module. It features (among others) the following + API calls, which are to freenet what HTTP GET requests are to http: + + my $data = $fcp->client_get ($url); # blocks + + my $transaction = $fcp->txn_client_get ($url); # does not block + $transaction->cb ( sub { ... } ); # set optional result callback + my $data = $transaction->result; # possibly blocks + + The "client_get" method works like "LWP::Simple::get": it requests the + given URL and waits till the data has arrived. It is defined to be: + + sub client_get { $_[0]->txn_client_get ($_[1])->result } + + And in fact is automatically generated. This is the blocking API of + Net::FCP, and it works as simple as in any other, similar, module. + + More complicated is "txn_client_get": It only creates a transaction + (completion, result, ...) object and initiates the transaction. + + my $txn = bless { }, Net::FCP::Txn::; + + It also creates a condition variable that is used to signal the + completion of the request: + + $txn->{finished} = AnyAvent->condvar; + + It then creates a socket in non-blocking mode. + + socket $txn->{fh}, ...; + fcntl $txn->{fh}, F_SETFL, O_NONBLOCK; + connect $txn->{fh}, ... + and !$!{EWOULDBLOCK} + and !$!{EINPROGRESS} + and Carp::croak "unable to connect: $!\n"; + + Then it creates a write-watcher which gets called whenever an error + occurs or the connection succeeds: + + $txn->{w} = AnyEvent->io (fh => $txn->{fh}, poll => 'w', cb => sub { $txn->fh_ready_w }); + + And returns this transaction object. The "fh_ready_w" callback gets + called as soon as the event loop detects that the socket is ready for + writing. + + The "fh_ready_w" method makes the socket blocking again, writes the + request data and replaces the watcher by a read watcher (waiting for + reply data). The actual code is more complicated, but that doesn't + matter for this example: + + fcntl $txn->{fh}, F_SETFL, 0; + syswrite $txn->{fh}, $txn->{request} + or die "connection or write error"; + $txn->{w} = AnyEvent->io (fh => $txn->{fh}, poll => 'r', cb => sub { $txn->fh_ready_r }); + + Again, "fh_ready_r" waits till all data has arrived, and then stores the + result and signals any possible waiters that the request ahs finished: + + sysread $txn->{fh}, $txn->{buf}, length $txn->{$buf}; + + if (end-of-file or data complete) { + $txn->{result} = $txn->{buf}; + $txn->{finished}->broadcast; + $txb->{cb}->($txn) of $txn->{cb}; # also call callback + } + + The "result" method, finally, just waits for the finished signal (if the + request was already finished, it doesn't wait, of course, and returns + the data: + + $txn->{finished}->wait; + return $txn->{result}; + + The actual code goes further and collects all errors ("die"s, + exceptions) that occured during request processing. The "result" method + detects wether an exception as thrown (it is stored inside the $txn + object) and just throws the exception, which means connection errors and + other problems get reported tot he code that tries to use the result, + not in a random callback. + + All of this enables the following usage styles: + + 1. Blocking: + + my $data = $fcp->client_get ($url); + + 2. Blocking, but parallelizing: + + my @datas = map $_->result, + map $fcp->txn_client_get ($_), + @urls; + + Both blocking examples work without the module user having to know + anything about events. + + 3a. Event-based in a main program, using any support Event module: + + use Event; + + $fcp->txn_client_get ($url)->cb (sub { + my $txn = shift; + my $data = $txn->result; + ... + }); + + Event::loop; + + 3b. The module user could use AnyEvent, too: + + use AnyEvent; + + my $quit = AnyEvent->condvar; + + $fcp->txn_client_get ($url)->cb (sub { + ... + $quit->broadcast; + }); + + $quit->wait; + SEE ALSO - Coro::Event, Coro, Event, Glib::Event, Glib, AnyEvent::Impl::Coro, - AnyEvent::Impl::Event, AnyEvent::Impl::Glib, AnyEvent::Impl::Tk. + Event modules: Coro::Event, Coro, Event, Glib::Event, Glib. + + Implementations: AnyEvent::Impl::Coro, AnyEvent::Impl::Event, + AnyEvent::Impl::Glib, AnyEvent::Impl::Tk. + + Nontrivial usage example: Net::FCP.