ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent/lib/AnyEvent.pm
(Generate patch)

Comparing AnyEvent/lib/AnyEvent.pm (file contents):
Revision 1.1 by root, Wed Apr 27 01:26:44 2005 UTC vs.
Revision 1.6 by root, Mon Dec 19 17:03:29 2005 UTC

1=head1 NAME 1=head1 NAME
2 2
3AnyEvent - ??? 3AnyEvent - provide framework for multiple event loops
4
5Event, Coro, Glib, Tk - various supported event loops
4 6
5=head1 SYNOPSIS 7=head1 SYNOPSIS
6 8
9use AnyEvent;
10
11 my $w = AnyEvent->io (fh => ..., poll => "[rw]+", cb => sub {
12 my ($poll_got) = @_;
13 ...
14 });
15
16- only one io watcher per $fh and $poll type is allowed
17(i.e. on a socket you can have one r + one w or one rw
18watcher, not any more.
19
20- AnyEvent will keep filehandles alive, so as long as the watcher exists,
21the filehandle exists.
22
23 my $w = AnyEvent->timer (after => $seconds, cb => sub {
24 ...
25 });
26
27- io and time watchers get canceled whenever $w is destroyed, so keep a copy
28
29- timers can only be used once and must be recreated for repeated operation
30
31 my $w = AnyEvent->condvar; # kind of main loop replacement
32 $w->wait; # enters main loop till $condvar gets ->broadcast
33 $w->broadcast; # wake up current and all future wait's
34
35- condvars are used to give blocking behaviour when neccessary. Create
36a condvar for any "request" or "event" your module might create, C<<
37->broadcast >> it when the event happens and provide a function that calls
38C<< ->wait >> for it. See the examples below.
39
7=head1 DESCRIPTION 40=head1 DESCRIPTION
8 41
42L<AnyEvent> provides an identical interface to multiple event loops. This
43allows module authors to utilizy an event loop without forcing module
44users to use the same event loop (as only a single event loop can coexist
45peacefully at any one time).
46
47The interface itself is vaguely similar but not identical to the Event
48module.
49
50On the first call of any method, the module tries to detect the currently
51loaded event loop by probing wether any of the following modules is
52loaded: L<Coro::Event>, L<Event>, L<Glib>, L<Tk>. The first one found is
53used. If none is found, the module tries to load these modules in the
54order given. The first one that could be successfully loaded will be
55used. If still none could be found, it will issue an error.
56
9=over 4 57=over 4
10 58
11=cut 59=cut
12 60
13package AnyEvent; 61package AnyEvent;
14 62
63no warnings;
64use strict 'vars';
15use Carp; 65use Carp;
16 66
17$VERSION = 0.1; 67our $VERSION = 0.3;
68our $MODEL;
18 69
19no warnings; 70our $AUTOLOAD;
71our @ISA;
20 72
21my @models = ( 73my @models = (
22 [Coro => Coro::Event::], 74 [Coro => Coro::Event::],
23 [Event => Event::], 75 [Event => Event::],
24 [Glib => Glib::], 76 [Glib => Glib::],
25 [Tk => Tk::], 77 [Tk => Tk::],
26); 78);
27 79
80our %method = map +($_ => 1), qw(io timer condvar broadcast wait cancel DESTROY);
81
28sub AUTOLOAD { 82sub AUTOLOAD {
29 $AUTOLOAD =~ s/.*://; 83 $AUTOLOAD =~ s/.*://;
30 84
85 $method{$AUTOLOAD}
86 or croak "$AUTOLOAD: not a valid method for AnyEvent objects";
87
88 unless ($MODEL) {
89 # check for already loaded models
31 for (@models) { 90 for (@models) {
32 my ($model, $package) = @$_; 91 my ($model, $package) = @$_;
33 if (defined ${"$package\::VERSION"}) { 92 if (scalar keys %{ *{"$package\::"} }) {
34 $EVENT = "AnyEvent::Impl::$model"; 93 eval "require AnyEvent::Impl::$model";
35 eval "require $EVENT"; die if $@; 94 last if $MODEL;
36 goto &{"$EVENT\::$AUTOLOAD"}; 95 }
96 }
97
98 unless ($MODEL) {
99 # try to load a model
100
101 for (@models) {
102 my ($model, $package) = @$_;
103 eval "require AnyEvent::Impl::$model";
104 last if $MODEL;
105 }
106
107 $MODEL
108 or die "No event module selected for AnyEvent and autodetect failed. Install any one of these modules: Coro, Event, Glib or Tk.";
37 } 109 }
38 } 110 }
39 111
40 for (@models) { 112 @ISA = $MODEL;
41 my ($model, $package) = @$_; 113
42 $EVENT = "AnyEvent::Impl::$model"; 114 my $class = shift;
43 if (eval "require $EVENT") { 115 $class->$AUTOLOAD (@_);
44 goto &{"$EVENT\::$AUTOLOAD"}; 116}
117
118=back
119
120=head1 EXAMPLE
121
122The following program uses an io watcher to read data from stdin, a timer
123to display a message once per second, and a condvar to exit the program
124when the user enters quit:
125
126 use AnyEvent;
127
128 my $cv = AnyEvent->condvar;
129
130 my $io_watcher = AnyEvent->io (fh => \*STDIN, poll => 'r', cb => sub {
131 warn "io event <$_[0]>\n"; # will always output <r>
132 chomp (my $input = <STDIN>); # read a line
133 warn "read: $input\n"; # output what has been read
134 $cv->broadcast if $input =~ /^q/i; # quit program if /^q/i
135 });
136
137 my $time_watcher; # can only be used once
138
139 sub new_timer {
140 $timer = AnyEvent->timer (after => 1, cb => sub {
141 warn "timeout\n"; # print 'timeout' about every second
142 &new_timer; # and restart the time
45 } 143 });
46 } 144 }
47 145
48 die "No event module selected for AnyEvent and autodetect failed. Install any of these: Coro, Event, Glib or Tk."; 146 new_timer; # create first timer
49}
50 147
511; 148 $cv->wait; # wait until user enters /^q/i
52 149
150=head1 REAL-WORLD EXAMPLE
151
152Consider the L<Net::FCP> module. It features (among others) the following
153API calls, which are to freenet what HTTP GET requests are to http:
154
155 my $data = $fcp->client_get ($url); # blocks
156
157 my $transaction = $fcp->txn_client_get ($url); # does not block
158 $transaction->cb ( sub { ... } ); # set optional result callback
159 my $data = $transaction->result; # possibly blocks
160
161The C<client_get> method works like C<LWP::Simple::get>: it requests the
162given URL and waits till the data has arrived. It is defined to be:
163
164 sub client_get { $_[0]->txn_client_get ($_[1])->result }
165
166And in fact is automatically generated. This is the blocking API of
167L<Net::FCP>, and it works as simple as in any other, similar, module.
168
169More complicated is C<txn_client_get>: It only creates a transaction
170(completion, result, ...) object and initiates the transaction.
171
172 my $txn = bless { }, Net::FCP::Txn::;
173
174It also creates a condition variable that is used to signal the completion
175of the request:
176
177 $txn->{finished} = AnyAvent->condvar;
178
179It then creates a socket in non-blocking mode.
180
181 socket $txn->{fh}, ...;
182 fcntl $txn->{fh}, F_SETFL, O_NONBLOCK;
183 connect $txn->{fh}, ...
184 and !$!{EWOULDBLOCK}
185 and !$!{EINPROGRESS}
186 and Carp::croak "unable to connect: $!\n";
187
188Then it creates a write-watcher which gets called whenever an error occurs
189or the connection succeeds:
190
191 $txn->{w} = AnyEvent->io (fh => $txn->{fh}, poll => 'w', cb => sub { $txn->fh_ready_w });
192
193And returns this transaction object. The C<fh_ready_w> callback gets
194called as soon as the event loop detects that the socket is ready for
195writing.
196
197The C<fh_ready_w> method makes the socket blocking again, writes the
198request data and replaces the watcher by a read watcher (waiting for reply
199data). The actual code is more complicated, but that doesn't matter for
200this example:
201
202 fcntl $txn->{fh}, F_SETFL, 0;
203 syswrite $txn->{fh}, $txn->{request}
204 or die "connection or write error";
205 $txn->{w} = AnyEvent->io (fh => $txn->{fh}, poll => 'r', cb => sub { $txn->fh_ready_r });
206
207Again, C<fh_ready_r> waits till all data has arrived, and then stores the
208result and signals any possible waiters that the request ahs finished:
209
210 sysread $txn->{fh}, $txn->{buf}, length $txn->{$buf};
211
212 if (end-of-file or data complete) {
213 $txn->{result} = $txn->{buf};
214 $txn->{finished}->broadcast;
215 $txb->{cb}->($txn) of $txn->{cb}; # also call callback
216 }
217
218The C<result> method, finally, just waits for the finished signal (if the
219request was already finished, it doesn't wait, of course, and returns the
220data:
221
222 $txn->{finished}->wait;
223 return $txn->{result};
224
225The actual code goes further and collects all errors (C<die>s, exceptions)
226that occured during request processing. The C<result> method detects
227wether an exception as thrown (it is stored inside the $txn object)
228and just throws the exception, which means connection errors and other
229problems get reported tot he code that tries to use the result, not in a
230random callback.
231
232All of this enables the following usage styles:
233
2341. Blocking:
235
236 my $data = $fcp->client_get ($url);
237
2382. Blocking, but parallelizing:
239
240 my @datas = map $_->result,
241 map $fcp->txn_client_get ($_),
242 @urls;
243
244Both blocking examples work without the module user having to know
245anything about events.
246
2473a. Event-based in a main program, using any support Event module:
248
249 use Event;
250
251 $fcp->txn_client_get ($url)->cb (sub {
252 my $txn = shift;
253 my $data = $txn->result;
254 ...
255 });
256
257 Event::loop;
258
2593b. The module user could use AnyEvent, too:
260
261 use AnyEvent;
262
263 my $quit = AnyEvent->condvar;
264
265 $fcp->txn_client_get ($url)->cb (sub {
266 ...
267 $quit->broadcast;
268 });
269
270 $quit->wait;
271
272=head1 SEE ALSO
273
274Event modules: L<Coro::Event>, L<Coro>, L<Event>, L<Glib::Event>, L<Glib>.
275
276Implementations: L<AnyEvent::Impl::Coro>, L<AnyEvent::Impl::Event>, L<AnyEvent::Impl::Glib>, L<AnyEvent::Impl::Tk>.
277
278Nontrivial usage example: L<Net::FCP>.
279
280=head1
281
282=cut
283
2841
285

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines