… | |
… | |
113 | |
113 | |
114 | =item Event Non-Ordering |
114 | =item Event Non-Ordering |
115 | |
115 | |
116 | POE cannot guarentee the order of callback invocation for timers, and |
116 | POE cannot guarentee the order of callback invocation for timers, and |
117 | usually gets it wrong. That is, if you have two timers, one timing out |
117 | usually gets it wrong. That is, if you have two timers, one timing out |
118 | after another (all els ebeing equal), the callbacks might be called in |
118 | after another (all else being equal), the callbacks might be called in |
119 | reverse order. |
119 | reverse order. |
120 | |
120 | |
121 | How one manages to even implement stuff that way escapes me. |
121 | How one manages to even implement stuff that way escapes me. |
122 | |
122 | |
123 | =item Child Watchers |
123 | =item Child Watchers |
124 | |
124 | |
125 | POE offers child watchers - which is a laudable thing, as few event loops |
125 | POE offers child watchers - which is a laudable thing, as few event loops |
126 | do. Unfortunately, they cannot even implement AnyEvent's simple child |
126 | do. Unfortunately, they cannot even implement AnyEvent's simple child |
127 | watchers: they are not generic enough (even the POE implementation itself |
127 | watchers: they are not generic enough (the POE implementation isn't even |
128 | isn't generic enough to let properly designed event loops such as EV use |
128 | generic enough to let properly designed back-end use their native child |
129 | their child watcher instead - it insist on doing it itself the slow way). |
129 | watcher instead - it insist on doing it itself the broken way). |
130 | |
130 | |
|
|
131 | Unfortunately, POE's child handling is inherently racy: if the child |
|
|
132 | exits before the handler is created (which is impossible to avoid in |
|
|
133 | general, imagine the forked program to exit immediately because of a |
|
|
134 | bug, or imagine the POE kernel being busy for a second), one has to |
|
|
135 | wait for another event to occur, which can take an indefinite amount of |
|
|
136 | time. Apparently POE implements a busy-waiting loop every second, but this |
|
|
137 | is not guaranteed or documented, so in practise child status events can be |
|
|
138 | delayed for up to a second "only". |
|
|
139 | |
131 | Of course, if POE reaps an unrelated child it will also output a message |
140 | Of course, whenever POE reaps an unrelated child it will also output a |
132 | for it that you cannot suppress (which shouldn't be too surprising at this |
141 | message for it that you cannot suppress (which shouldn't be too surprising |
133 | point). Very professional. |
142 | at this point). Very professional. |
134 | |
143 | |
135 | As a workaround, AnyEvent::Impl::POE will take advantage of undocumented |
144 | As a workaround, AnyEvent::Impl::POE will take advantage of undocumented |
136 | behaviour in POE::Kernel to catch the status of all child processes. |
145 | behaviour in POE::Kernel to catch the status of all child processes, but |
137 | |
146 | it cannot guarantee delivery. |
138 | Unfortunately, POE's child handling is racy: if the child exits before the |
|
|
139 | handler is created (which is impossible to avoid in general), one has to |
|
|
140 | wait for another event to occur, which can take an indefinite amount of |
|
|
141 | time (apparently POE does a busy-waiting loop every second, but this is |
|
|
142 | not guarenteed or documented, so in practise child status events can be |
|
|
143 | delayed for up to a second "only" at least in the current version). |
|
|
144 | |
147 | |
145 | How one manages to have such a glaring bug in an event loop after ten |
148 | How one manages to have such a glaring bug in an event loop after ten |
146 | years of development escapes me. |
149 | years of development escapes me. |
147 | |
150 | |
148 | =item Documentation Quality |
151 | =item Documentation Quality |
… | |
… | |
241 | course, as both are O(n) in the number of file descriptors, which is |
244 | course, as both are O(n) in the number of file descriptors, which is |
242 | rather bad. |
245 | rather bad. |
243 | |
246 | |
244 | This is just one place where it gets obvious how little the author of the |
247 | This is just one place where it gets obvious how little the author of the |
245 | POE manpage understands. |
248 | POE manpage understands. |
|
|
249 | |
|
|
250 | =item No idle events |
|
|
251 | |
|
|
252 | The POE-recommended workaround to this is apparently to use |
|
|
253 | C<fork>. Consequently, idle watchera will have to be emulated by AnyEvent. |
246 | |
254 | |
247 | =back |
255 | =back |
248 | |
256 | |
249 | On the good side, AnyEvent allows you to write your modules in a 100% |
257 | On the good side, AnyEvent allows you to write your modules in a 100% |
250 | POE-compatible way (bug-for-bug compatible even), without forcing your |
258 | POE-compatible way (bug-for-bug compatible even), without forcing your |
… | |
… | |
295 | stop => sub { |
303 | stop => sub { |
296 | $_[KERNEL]->$pee ($fh); |
304 | $_[KERNEL]->$pee ($fh); |
297 | }, |
305 | }, |
298 | }, |
306 | }, |
299 | ); |
307 | ); |
300 | bless \\$session, AnyEvent::Impl::POE:: |
308 | bless \\$session, "AnyEvent::Impl::POE" |
301 | } |
309 | } |
302 | |
310 | |
303 | sub timer { |
311 | sub timer { |
304 | my ($class, %arg) = @_; |
312 | my ($class, %arg) = @_; |
305 | |
313 | |
… | |
… | |
316 | stop => sub { |
324 | stop => sub { |
317 | $_[KERNEL]->alarm_remove_all; |
325 | $_[KERNEL]->alarm_remove_all; |
318 | }, |
326 | }, |
319 | }, |
327 | }, |
320 | ); |
328 | ); |
321 | bless \\$session, AnyEvent::Impl::POE:: |
329 | bless \\$session, "AnyEvent::Impl::POE" |
322 | } |
330 | } |
323 | |
331 | |
324 | sub signal { |
332 | sub signal { |
325 | my ($class, %arg) = @_; |
333 | my ($class, %arg) = @_; |
326 | my $signal = delete $arg{signal}; |
334 | my $signal = delete $arg{signal}; |
… | |
… | |
339 | $_[KERNEL]->refcount_decrement ($_[SESSION]->ID => "poe"); |
347 | $_[KERNEL]->refcount_decrement ($_[SESSION]->ID => "poe"); |
340 | $_[KERNEL]->sig ($signal); |
348 | $_[KERNEL]->sig ($signal); |
341 | }, |
349 | }, |
342 | }, |
350 | }, |
343 | ); |
351 | ); |
344 | bless \\$session, AnyEvent::Impl::POE:: |
352 | bless \\$session, "AnyEvent::Impl::POE" |
345 | } |
353 | } |
346 | |
354 | |
347 | sub child { |
355 | sub child { |
348 | my ($class, %arg) = @_; |
356 | my ($class, %arg) = @_; |
349 | my $pid = delete $arg{pid}; |
357 | my $pid = delete $arg{pid}; |
… | |
… | |
363 | $_[KERNEL]->refcount_decrement ($_[SESSION]->ID => "poe"); |
371 | $_[KERNEL]->refcount_decrement ($_[SESSION]->ID => "poe"); |
364 | $_[KERNEL]->sig ("CHLD"); |
372 | $_[KERNEL]->sig ("CHLD"); |
365 | }, |
373 | }, |
366 | }, |
374 | }, |
367 | ); |
375 | ); |
368 | bless \\$session, AnyEvent::Impl::POE:: |
376 | bless \\$session, "AnyEvent::Impl::POE" |
369 | } |
377 | } |
370 | |
378 | |
371 | sub DESTROY { |
379 | sub DESTROY { |
372 | POE::Kernel->post (${${$_[0]}}, "stop"); |
380 | POE::Kernel->post (${${$_[0]}}, "stop"); |
373 | } |
381 | } |
374 | |
382 | |
375 | sub one_event { |
383 | sub one_event { |
376 | POE::Kernel->loop_do_timeslice; |
384 | POE::Kernel->loop_do_timeslice; |
377 | } |
385 | } |
378 | |
386 | |
|
|
387 | sub loop { |
|
|
388 | POE::Kernel->run; |
|
|
389 | } |
|
|
390 | |
379 | 1; |
391 | 1; |
380 | |
392 | |
381 | =head1 SEE ALSO |
393 | =head1 SEE ALSO |
382 | |
394 | |
383 | L<AnyEvent>, L<POE>. |
395 | L<AnyEvent>, L<POE>. |