ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent/lib/AnyEvent/Impl/POE.pm
Revision: 1.45
Committed: Thu Apr 5 04:12:22 2012 UTC (12 years, 2 months ago) by root
Branch: MAIN
Changes since 1.44: +1 -1 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 =head1 NAME
2    
3     AnyEvent::Impl::POE - AnyEvent adaptor for POE
4    
5 root 1.13 =encoding utf-8
6    
7 root 1.1 =head1 SYNOPSIS
8    
9 root 1.18 use AnyEvent;
10     use POE;
11    
12     # this module gets loaded automatically as required
13 root 1.1
14     =head1 DESCRIPTION
15    
16     This module provides transparent support for AnyEvent. You don't have to
17     do anything to make POE work with AnyEvent except by loading POE before
18 root 1.22 creating the first AnyEvent watcher. There are some cases where POE will
19 root 1.33 issue spurious (and non-suppressible) warnings. These can be avoided by
20 root 1.22 loading AnyEvent::Impl::POE before loading any other modules using POE and
21     AnyEvent, i.e. in your main program.
22    
23     AnyEvent::Impl::POE will output some spurious message how to work around
24     POE's spurious messages when it detects these cases.
25 root 1.1
26 root 1.3 Unfortunately, POE isn't generic enough to implement a fully working
27     AnyEvent backend: POE is too badly designed, too badly documented and too
28     badly implemented.
29 root 1.2
30 root 1.3 Here are the details, and what it means to you if you want to be
31     interoperable with POE:
32 root 1.2
33     =over 4
34    
35     =item Weird messages
36    
37 root 1.34 If you only use C<run_one_timeslice> (as AnyEvent has to for its
38 root 1.33 condition variables), POE will print an ugly, unsuppressible, message at
39 root 1.4 program exit:
40 root 1.2
41     Sessions were started, but POE::Kernel's run() method was never...
42    
43     The message is correct, the question is why POE prints it in the first
44     place in a correct program (this is not a singular case though).
45    
46 root 1.39 AnyEvent consequently patches the POE kernel so it thinks it already
47     ran. Other workarounds, even the one cited in the POE documentation
48     itself, have serious side effects, such as throwing away events.
49 root 1.2
50 root 1.16 The author of POE verified that this is indeed true, and has no plans to
51     change this.
52    
53 root 1.19 POE has other weird messages, and sometimes weird behaviour, for example,
54     it doesn't support overloaded code references as callbacks for no apparent
55     reason.
56    
57 root 1.7 =item One POE session per Event
58 root 1.2
59     AnyEvent has to create one POE::Session per event watcher, which is
60 root 1.3 immensely slow and makes watchers very large. The reason for this is
61     lacking lifetime management (mostly undocumented, too). Without one
62     session/watcher it is not possible to easily keep the kernel from running
63 root 1.16 endlessly.
64    
65     This is not just a problem with the way AnyEvent has to interact with
66     POE, but is a principal issue with POEs lifetime management (namely
67     that stopping the kernel stops sessions, but AnyEvent has no control
68     over who and when the kernel starts or stops w.r.t. AnyEvent watcher
69     creation/destruction).
70    
71     From benchmark data it is not clear that session creation is that costly,
72     though - the real inefficiencies with POE seem to come from other sources,
73     such as event handling.
74 root 1.2
75     =item One watcher per fd/event combo
76    
77     POE, of course, suffers from the same bug as Tk and some other badly
78     designed event models in that it doesn't support multiple watchers per
79 root 1.3 fd/poll combo. The workaround is the same as with Tk: AnyEvent::Impl::POE
80     creates a separate file descriptor to hand to POE, which isn't fast and
81     certainly not nice to your resources.
82 root 1.2
83 root 1.7 Of course, without the workaround, POE also prints ugly messages again
84     that say the program *might* be buggy.
85    
86 root 1.16 While this is not good to performance, at least regarding speed, with a
87     modern Linux kernel, the overhead is actually quite small.
88    
89 root 1.43 =item Timing deficiencies
90 root 1.3
91     POE manages to not have a function that returns the current time. This is
92     extremely problematic, as POE can use different time functions, which can
93 root 1.11 differ by more than a second - and user code is left guessing which one is
94     used.
95    
96 root 1.32 In addition, most timer functions in POE want an absolute timestamp, which
97 root 1.11 is hard to create if all you have is a relative time and no function to
98 root 1.16 return the "current time".
99    
100     And of course POE doesn't handle time jumps at all (not even when using
101     an event loop that happens to do that, such as L<EV>, as it does its own
102     unoptimised timer management).
103 root 1.12
104     AnyEvent works around the unavailability of the current time using
105     relative timers exclusively, in the hope that POE gets it right at least
106     internally.
107 root 1.3
108 root 1.43 =item Lack of defined event ordering
109 root 1.3
110 root 1.33 POE cannot guarantee the order of callback invocation for timers, and
111 root 1.3 usually gets it wrong. That is, if you have two timers, one timing out
112 root 1.25 after another (all else being equal), the callbacks might be called in
113 root 1.16 reverse order.
114 root 1.3
115     How one manages to even implement stuff that way escapes me.
116    
117 root 1.43 =item Child watchers
118 root 1.3
119 root 1.7 POE offers child watchers - which is a laudable thing, as few event loops
120 root 1.3 do. Unfortunately, they cannot even implement AnyEvent's simple child
121 root 1.25 watchers: they are not generic enough (the POE implementation isn't even
122     generic enough to let properly designed back-end use their native child
123     watcher instead - it insist on doing it itself the broken way).
124    
125 root 1.44 Unfortunately, POE's child handling is inherently racy: if the child exits
126     before the handler is created (because e.g. it crashes or simply is quick
127     about it), then current versions of POE (1.352) will I<never> invoke the
128     child watcher, and there is nothing that can be done about it. Older
129     versions of POE only delayed in this case. The reason is that POE first
130     checks if the child has already exited, and I<then> installs the signal
131     handler - aa classical race.
132    
133     Your only hope is for the fork'ed process to not exit too quickly, in
134     which case everything happens to work.
135 root 1.25
136     Of course, whenever POE reaps an unrelated child it will also output a
137     message for it that you cannot suppress (which shouldn't be too surprising
138     at this point). Very professional.
139 root 1.6
140 root 1.7 As a workaround, AnyEvent::Impl::POE will take advantage of undocumented
141 root 1.25 behaviour in POE::Kernel to catch the status of all child processes, but
142     it cannot guarantee delivery.
143 root 1.7
144     How one manages to have such a glaring bug in an event loop after ten
145     years of development escapes me.
146 root 1.3
147 root 1.29 (There are more annoying bugs, for example, POE runs C<waitpid>
148 root 1.44 unconditionally at finaliser time, so your program will hang until all
149     child processes have exited.)
150 root 1.29
151 root 1.43 =item Documentation quality
152 root 1.3
153     At the time of this writing, POE was in its tenth year. Still, its
154     documentation is extremely lacking, making it impossible to implement
155 root 1.10 stuff as trivial as AnyEvent watchers without having to resort to
156 root 1.3 undocumented behaviour or features.
157    
158 root 1.33 For example, the POE::Kernel manpage has nine occurrences of the word TODO
159     with an explanation of whats missing. In general, the POE man pages are
160 root 1.10 littered with comments like "section not yet written".
161    
162     Some other gems:
163 root 1.3
164     This allows many object methods to also be package methods.
165    
166     This is nice, but since it doesn't document I<which> methods these are,
167     this is utterly useless information.
168    
169     Terminal signals will kill sessions if they are not handled by a
170 root 1.10 "sig_handled"() call. The OS signals that usually kill or dump a
171     process are considered terminal in POE, but they never trigger a
172 root 1.3 coredump. These are: HUP, INT, QUIT and TERM.
173    
174 root 1.10 Although AnyEvent calls C<sig_handled>, removing it has no apparent
175     effects on POE handling SIGINT.
176 root 1.3
177 root 1.11 refcount_increment SESSION_ID, COUNTER_NAME
178    
179     Nowhere is explained which COUNTER_NAMEs are valid and which aren't - not
180     all scalars (or even strings) are valid counter names. Take your guess,
181 root 1.16 failure is of course completely silent. I found this out the hard way, as
182     the first name I came up with was silently ignored.
183 root 1.11
184     get_next_event_time() returns the time the next event is due, in a form
185     compatible with the UNIX time() function.
186    
187 root 1.33 And surely, one would hope that POE supports sub-second accuracy as
188 root 1.11 documented elsewhere, unlike the explanation above implies. Yet:
189    
190     POE::Kernel timers support subsecond accuracy, but don’t expect too
191     much here. Perl is not the right language for realtime programming.
192    
193 root 1.33 ... of course, Perl is not the right language to expect sub-second
194     accuracy - the manpage author must hate Perl to spread so much FUD in
195     so little space. The Deliantra game server logs with 100µs-accuracy
196     because Perl is fast enough to require this, and is still able to deliver
197     map updates with little jitter at exactly the right time. It does not,
198     however, use POE.
199 root 1.11
200 root 1.3 Furthermore, since the Kernel keeps track of everything sessions do, it
201     knows when a session has run out of tasks to perform.
202    
203 root 1.11 This is impossible - how does the kernel know that a session is no longer
204 root 1.3 watching for some (external) event (e.g. by some other session)? It
205 root 1.10 cannot, and therefore this is wrong - but you would be hard pressed to
206     find out how to work around this and tell the kernel manually about such
207     events.
208 root 1.3
209     It gets worse, though - the notion of "task" or "resource", although used
210     throughout the documentation, is not defined in a usable way. For example,
211     waiting for a timeout is considered to be a task, waiting for a signal is
212 root 1.10 not (a session that only waits for a signal is considered finished and
213     gets removed). The user is left guessing when waiting for an event counts
214 root 1.15 as task and when not (in fact, the issue with signals is mentioned in
215     passing in a section about child watchers and directly contradicts earlier
216     parts in that document).
217 root 1.3
218 root 1.10 One could go on endlessly - ten years, no usable documentation.
219 root 1.3
220 root 1.8 It is likely that differences between documentation, or the one or two
221 root 1.10 things I had to guess, cause unanticipated problems with this adaptor.
222 root 1.3
223 root 1.16 =item Fragile and inconsistent API
224 root 1.3
225     The POE API is extremely inconsistent - sometimes you have to pass a
226     session argument, sometimes it gets ignored, sometimes a session-specific
227     method must not use a session argument.
228 root 1.2
229 root 1.10 Error handling is sub-standard as well: even for programming mistakes,
230     POE does not C<croak> but, in most cases, just sets C<$!> or simply does
231     nothing at all, leading to fragile programs.
232    
233     Sometimes registering a handler uses the "eventname, parameter" ordering
234     (timeouts), sometimes it is "parameter, eventname" (signals). There is
235     little consistency overall.
236 root 1.1
237 root 1.17 =item Lack of knowledge
238    
239 root 1.18 The IO::Poll event loop provides an alternative that theoretically
240     scales better than select().
241 root 1.17
242     The IO::Poll "event loop" (who in his right mind would call that an event
243     loop) of course scales about identically (sometimes it is a bit faster,
244     sometimes a bit slower) to select in theory, and also in practise, of
245     course, as both are O(n) in the number of file descriptors, which is
246     rather bad.
247    
248     This is just one place where it gets obvious how little the author of the
249     POE manpage understands.
250    
251 root 1.23 =item No idle events
252    
253     The POE-recommended workaround to this is apparently to use
254 root 1.33 C<fork>. Consequently, idle watchers will have to be emulated by AnyEvent.
255 root 1.23
256 root 1.43 =item Questionable maintainer behaviour
257 root 1.41
258 root 1.43 The author of POE is known to fabricate statements and post these to
259     public mailinglists - apparently, spreading FUD about competing (in his
260     eyes) projects or their maintainers is acceptable to him.
261    
262     This has (I believe) zero effects on the quality or usefulness of his
263     code, but it does completely undermine his trustworthyness - so don't
264     blindly believe anything he says, he might have just made it up to suit
265     his needs (benchmark results, the names of my ten wifes, the length of my
266     penis, etc. etc.). When in doubt, double-check - not just him, anybody
267     actually.
268    
269     Example: L<http://www.nntp.perl.org/group/perl.perl5.porters/2012/01/msg182141.html>.
270     I challenged him in that thread to provide evidence for his statement by giving at
271     least two examples, but of course since he just made it up, he couldn't provide any evidence.
272 root 1.41
273 root 1.3 =back
274 root 1.1
275 root 1.9 On the good side, AnyEvent allows you to write your modules in a 100%
276     POE-compatible way (bug-for-bug compatible even), without forcing your
277 root 1.3 module to use POE - it is still open to better event models, of which
278     there are plenty.
279 root 1.1
280 root 1.28 Oh, and one other positive thing:
281    
282     RUNNING_IN_HELL
283    
284     POE knows about the nature of the beast!
285    
286 root 1.1 =cut
287    
288     package AnyEvent::Impl::POE;
289    
290 root 1.30 use AnyEvent (); BEGIN { AnyEvent::common_sense }
291 root 1.1 use POE;
292    
293 root 1.39 # suppress an idiotic warning inside POE
294     ${ POE::Kernel->new->[POE::Kernel::KR_RUN] } |= POE::Kernel::KR_RUN_CALLED;
295 root 1.1
296     sub io {
297     my ($class, %arg) = @_;
298 root 1.2
299 root 1.26 # POE itself might do the right thing, but some POE backends don't,
300     # so do the safe thing, it's not as if this will slow us down
301     # any further *g*
302 root 1.21 my ($fh, $pee) = AnyEvent::_dupfh $arg{poll}, $arg{fh}, "select_read", "select_write";
303 root 1.2
304 root 1.27 my $cb = delete $arg{cb}; my $cb = sub { &$cb }; # POE doesn't like callable objects
305 root 1.19
306 root 1.1 my $session = POE::Session->create (
307     inline_states => {
308 root 1.26 _start => sub { $_[KERNEL]->$pee ($fh => "ready") },
309     ready => sub { $cb->() },
310     stop => sub { $_[KERNEL]->$pee ($fh) },
311 root 1.1 },
312     );
313 root 1.23 bless \\$session, "AnyEvent::Impl::POE"
314 root 1.1 }
315    
316     sub timer {
317     my ($class, %arg) = @_;
318 root 1.19
319 root 1.27 my $after = delete $arg{after};
320     my $ival = delete $arg{interval};
321     my $cb = delete $arg{cb}; my $cb = sub { &$cb }; # POE doesn't like callable objects
322 root 1.19
323 root 1.1 my $session = POE::Session->create (
324     inline_states => {
325     _start => sub {
326     $_[KERNEL]->delay_set (timeout => $after);
327     },
328 root 1.20 timeout => $ival ? sub { $_[KERNEL]->delay_set (timeout => $ival); $cb->() } : $cb,
329 root 1.1 stop => sub {
330     $_[KERNEL]->alarm_remove_all;
331     },
332     },
333     );
334 root 1.23 bless \\$session, "AnyEvent::Impl::POE"
335 root 1.1 }
336    
337     sub signal {
338     my ($class, %arg) = @_;
339 root 1.31 my $signal = AnyEvent::Base::sig2name delete $arg{signal};
340 root 1.27 my $cb = delete $arg{cb}; my $cb = sub { &$cb }; # POE doesn't like callable objects
341 root 1.1 my $session = POE::Session->create (
342     inline_states => {
343     _start => sub {
344 root 1.40 # I suck - POE
345     },
346     start => sub {
347 root 1.1 $_[KERNEL]->sig ($signal => "catch");
348     $_[KERNEL]->refcount_increment ($_[SESSION]->ID => "poe");
349     },
350     catch => sub {
351     $cb->();
352     $_[KERNEL]->sig_handled;
353     },
354     stop => sub {
355     $_[KERNEL]->refcount_decrement ($_[SESSION]->ID => "poe");
356     $_[KERNEL]->sig ($signal);
357     },
358     },
359     );
360 root 1.40 POE::Kernel->call ($session, "start");
361 root 1.23 bless \\$session, "AnyEvent::Impl::POE"
362 root 1.1 }
363    
364 root 1.7 sub child {
365     my ($class, %arg) = @_;
366     my $pid = delete $arg{pid};
367 root 1.27 my $cb = delete $arg{cb}; my $cb = sub { &$cb }; # POE doesn't like callable objects
368 root 1.7 my $session = POE::Session->create (
369     inline_states => {
370     _start => sub {
371 root 1.40 # I suck - POE
372     },
373     start => sub {
374 root 1.7 $_[KERNEL]->sig (CHLD => "child");
375     $_[KERNEL]->refcount_increment ($_[SESSION]->ID => "poe");
376     },
377     child => sub {
378     my ($rpid, $status) = @_[ARG1, ARG2];
379    
380     $cb->($rpid, $status) if $rpid == $pid || $pid == 0;
381     },
382     stop => sub {
383     $_[KERNEL]->refcount_decrement ($_[SESSION]->ID => "poe");
384     $_[KERNEL]->sig ("CHLD");
385     },
386     },
387     );
388 root 1.40 # newer POE versions lose signals unless we call ->sig early.
389     POE::Kernel->call ($session, "start");
390 root 1.23 bless \\$session, "AnyEvent::Impl::POE"
391 root 1.7 }
392    
393 root 1.1 sub DESTROY {
394 root 1.35 POE::Kernel->call (${${$_[0]}}, "stop");
395 root 1.1 }
396    
397 root 1.36 #sub loop {
398     # POE::Kernel->run;
399     #}
400 root 1.24
401 root 1.37 sub _poll {
402     POE::Kernel->loop_do_timeslice;
403     }
404    
405     sub AnyEvent::CondVar::Base::_wait {
406 root 1.38 POE::Kernel->loop_do_timeslice until exists $_[0]{_ae_sent};
407 root 1.37 }
408    
409 root 1.1 =head1 SEE ALSO
410    
411     L<AnyEvent>, L<POE>.
412    
413     =head1 AUTHOR
414    
415     Marc Lehmann <schmorp@schmorp.de>
416 root 1.45 http://software.schmorp.de/pkg/AnyEvent.html
417 root 1.1
418     =cut
419    
420 root 1.42 1
421