File Coverage

blib/lib/POE/Loop/Mojo_IOLoop.pm
Criterion Covered Total %
statement 98 110 89.0
branch 25 34 73.5
condition 7 11 63.6
subroutine 21 25 84.0
pod 0 13 0.0
total 151 193 78.2


line stmt bran cond sub pod time code
1 33     33   966254 use strict;
  33         74  
  33         1707  
2              
3             package POE::Loop::Mojo_IOLoop;
4              
5 33     33   15982 use POE::Loop::PerlSignals;
  33         22280  
  33         1442  
6              
7             our $VERSION = '0.002';
8              
9             =for poe_tests
10             BEGIN { $ENV{POE_EVENT_LOOP} = 'POE::Loop::Mojo_IOLoop' }
11             BEGIN { $ENV{MOJO_REACTOR} ||= 'Mojo::Reactor::Poll' }
12             sub skip_tests {
13             return "Mojo::IOLoop tests require the Mojo::IOLoop module" if (
14             do { eval "use Mojo::IOLoop"; $@ }
15             );
16             if (shift eq '00_info') {
17             my $reactor = Mojo::IOLoop->singleton->reactor;
18             diag("Using reactor $reactor");
19             }
20             }
21              
22             =cut
23              
24             package
25             POE::Kernel;
26              
27 33     33   626 use Mojo::IOLoop;
  33         107514  
  33         467  
28 33     33   689 use Time::HiRes;
  33         52  
  33         261  
29              
30 33   50 33   3990 use constant MOJO_DEBUG => $ENV{POE_LOOP_MOJO_DEBUG} || 0;
  33         52  
  33         38093  
31              
32             my $_timer_id;
33             my $_idle_id;
34             my @fileno_watcher;
35             my $_async_check;
36             my $DIE_MESSAGE;
37              
38             # Loop construction and destruction.
39              
40             sub loop_initialize {
41 49     49 0 762357 my $self = shift;
42            
43 49         428 my $reactor = Mojo::IOLoop->singleton->reactor;
44 49 50       2585 if ($reactor->isa('Mojo::Reactor::EV')) {
45             # Workaround to ensure perl signal handlers are called
46 0     0   0 $_async_check = EV::check(sub { });
  0         0  
47             # EV will ignore exceptions unless this is set
48 0         0 $EV::DIED = \&_die_handler;
49             }
50            
51 49         78 warn "-- Initialized loop with reactor $reactor\n" if MOJO_DEBUG;
52            
53 49 50       263 unless (defined $_idle_id) {
54 49         287 $_idle_id = Mojo::IOLoop->next_tick(\&_loop_resume_timer);
55             }
56             }
57              
58             sub loop_finalize {
59 45     45 0 5685 my $self = shift;
60            
61 45         75 warn "-- Finalized loop\n" if MOJO_DEBUG;
62            
63 45         200 foreach my $fd (0..$#fileno_watcher) {
64 474 50       990 POE::Kernel::_warn(
65             "Filehandle watcher for fileno $fd is defined during loop finalize"
66             ) if defined $fileno_watcher[$fd];
67             }
68            
69 45         218 $self->loop_ignore_all_signals();
70 45         321 undef $_async_check;
71             }
72              
73             sub _die_handler {
74 0     0   0 warn "-- Died $@\n" if MOJO_DEBUG;
75            
76             # EV doesn't let you rethrow an error here, so we have
77             # to stop the loop and get the error later
78 0         0 $DIE_MESSAGE = $@;
79            
80             # This will cause the EV::run call in loop_run to return,
81             # and cause the process to die.
82 0         0 EV::break();
83             }
84              
85             # Signal handler maintenance functions.
86              
87 0     0 0 0 sub loop_attach_uidestroy {
88             # does nothing
89             }
90              
91             # Maintain time watchers.
92              
93             sub loop_resume_time_watcher {
94 1210     1210 0 775697 my ($self, $next_time) = @_;
95            
96 1210         3037 $next_time -= Time::HiRes::time;
97 1210 100       2999 $next_time = 0 if $next_time < 0;
98            
99 1210         997 warn "-- Resume time watcher in ${next_time}s\n" if MOJO_DEBUG;
100            
101 1210 100       3210 Mojo::IOLoop->remove($_timer_id) if defined $_timer_id;
102 1210         22433 $_timer_id = Mojo::IOLoop->timer($next_time => \&_loop_event_callback);
103             }
104              
105             sub loop_reset_time_watcher {
106 415     415 0 1547179 my ($self, $next_time) = @_;
107            
108 415         558 warn "-- Reset time watcher to $next_time\n" if MOJO_DEBUG;
109            
110 415 100       2110 Mojo::IOLoop->remove($_timer_id) if defined $_timer_id;
111 415         17682 undef $_timer_id;
112 415         957 $self->loop_resume_time_watcher($next_time);
113             }
114              
115             sub _loop_resume_timer {
116 443 50   443   49496 Mojo::IOLoop->remove($_idle_id) if defined $_idle_id;
117 443         569 undef $_idle_id;
118 443         1293 $poe_kernel->loop_resume_time_watcher($poe_kernel->get_next_event_time());
119             }
120              
121 204     204 0 479129 sub loop_pause_time_watcher {
122             # does nothing
123             }
124              
125             # Maintain filehandle watchers.
126              
127             sub loop_watch_filehandle {
128 264     264 0 553987 my ($self, $handle, $mode) = @_;
129 264         645 my $fileno = fileno $handle;
130            
131 264 50       1245 confess "POE::Loop::Mojo_IOLoop does not support MODE_EX" if $mode == MODE_EX;
132 264 50 66     1198 confess "Unknown mode $mode" unless $mode == MODE_RD or $mode == MODE_WR;
133            
134 264         235 warn "-- Watch filehandle $fileno, mode $mode\n" if MOJO_DEBUG;
135            
136             # Set up callback if needed
137 264 100       609 unless (defined $fileno_watcher[$fileno]) {
138             Mojo::IOLoop->singleton->reactor->io($handle => sub {
139 485     485   8262581 my ($reactor, $writable) = @_;
140 485         988 _loop_select_callback($fileno, $writable);
141 195         1348 });
142             }
143            
144 264         19291 $fileno_watcher[$fileno][$mode] = 1;
145            
146 264         604 _update_select_watcher($handle);
147             }
148              
149             sub loop_ignore_filehandle {
150 260     260 0 213304 my ($self, $handle, $mode) = @_;
151 260         535 my $fileno = fileno $handle;
152            
153 260         283 warn "-- Ignore filehandle $fileno, mode $mode\n" if MOJO_DEBUG;
154            
155 260         588 undef $fileno_watcher[$fileno][$mode];
156            
157 260         628 _update_select_watcher($handle);
158             }
159              
160             sub loop_pause_filehandle {
161 229     229 0 44404 my ($self, $handle, $mode) = @_;
162 229         349 my $fileno = fileno $handle;
163            
164 229         198 warn "-- Pause filehandle $fileno, mode $mode\n" if MOJO_DEBUG;
165            
166 229         343 $fileno_watcher[$fileno][$mode] = 0;
167            
168 229         385 _update_select_watcher($handle);
169             }
170              
171             sub loop_resume_filehandle {
172 198     198 0 126063 my ($self, $handle, $mode) = @_;
173 198         324 my $fileno = fileno $handle;
174            
175 198         189 warn "-- Resume filehandle $fileno, mode $mode\n" if MOJO_DEBUG;
176            
177 198         333 $fileno_watcher[$fileno][$mode] = 1;
178            
179 198         338 _update_select_watcher($handle);
180             }
181              
182             sub _update_select_watcher {
183 951     951   1147 my ($handle) = @_;
184 951         1043 my $fileno = fileno $handle;
185            
186 951         991 my ($read, $write) = @{$fileno_watcher[$fileno]}[MODE_RD(),MODE_WR()];
  951         1605  
187            
188             # Don't remove watcher unless both read and write have been ignored
189 951 100 100     3727 if (defined $read or defined $write) {
190 760         2329 Mojo::IOLoop->singleton->reactor->watch($handle, $read, $write);
191             } else {
192 191         1163 Mojo::IOLoop->singleton->reactor->remove($handle);
193 191         13497 undef $fileno_watcher[$fileno];
194             }
195             }
196              
197             # Timer callback to dispatch events.
198              
199             sub _loop_event_callback {
200 563     563   18680251 my $self = $poe_kernel;
201            
202 563         633 warn "-- Timer callback\n" if MOJO_DEBUG;
203            
204 563         1890 $self->_data_ev_dispatch_due();
205 563         30117 $self->_test_if_kernel_is_idle();
206            
207 563         94262 undef $_timer_id;
208            
209 563 100       1786 if ($self->get_event_count()) {
210 405         3658 $_idle_id = Mojo::IOLoop->next_tick(\&_loop_resume_timer);
211             }
212            
213             # Transferring control back to Mojo::IOLoop; this is idle time.
214             }
215              
216             # Mojo::IOLoop filehandle callback to dispatch selects.
217              
218             sub _loop_select_callback {
219 485     485   540 my $self = $poe_kernel;
220 485         572 my ($fileno, $writable) = @_;
221            
222 485 100       974 my $mode = $writable ? MODE_WR : MODE_RD;
223            
224             # Make sure this callback is actually registered
225 485 50       1187 return unless defined $fileno_watcher[$fileno];
226            
227             # Workaround for write-only mode receiving read callback
228 485 100       1214 unless ($fileno_watcher[$fileno][$mode]) {
229 1 50 33     6 if ($mode == MODE_RD and $fileno_watcher[$fileno][MODE_WR()]) {
230             # Use write callback
231 1         1 $mode = MODE_WR;
232             } else {
233 0         0 return;
234             }
235             }
236            
237 485         391 warn "-- Select callback for filehandle $fileno, mode $mode\n"
238             if MOJO_DEBUG;
239            
240 485         1273 $self->_data_handle_enqueue_ready($mode, $fileno);
241 485         392016 $self->_test_if_kernel_is_idle();
242             }
243              
244             # The event loop itself.
245              
246 0     0 0 0 sub loop_do_timeslice {
247             }
248              
249             sub loop_run {
250 45     45 0 4695478 warn "-- Loop run\n" if MOJO_DEBUG;
251 45         362 Mojo::IOLoop->start;
252            
253 45 50       2715 if (defined $DIE_MESSAGE) {
254 0         0 my $message = $DIE_MESSAGE;
255 0         0 undef $DIE_MESSAGE;
256 0         0 die $message;
257             }
258             }
259              
260             sub loop_halt {
261 45     45 0 281050 warn "-- Loop halt\n" if MOJO_DEBUG;
262 45         293 Mojo::IOLoop->stop;
263             }
264              
265             =head1 NAME
266              
267             POE::Loop::Mojo_IOLoop - a bridge that allows POE to be driven by Mojo::IOLoop
268              
269             =head1 SYNOPSIS
270              
271             See L.
272              
273             use POE qw(Loop::Mojo_IOLoop);
274            
275             use POE::Kernel { loop => 'Mojo::IOLoop' };
276            
277             BEGIN { $ENV{POE_EVENT_LOOP} = 'POE::Loop::Mojo_IOLoop' }
278             use POE;
279              
280             =head1 DESCRIPTION
281              
282             L implements the interface documented in L.
283             Therefore it has no documentation of its own. Please see L for more
284             details.
285              
286             When using L with L, the loop must be set explicitly or
287             L will detect multiple event loops and fail. You can set the event loop
288             by setting the environment variable C to
289             C before L is loaded, or by including it in the
290             C directive when initially loading L. See
291             L for more information.
292              
293             =head1 BUGS
294              
295             Report any issues on the public bugtracker.
296              
297             =head1 AUTHOR
298              
299             Dan Book, C
300              
301             =head1 COPYRIGHT AND LICENSE
302              
303             Copyright 2015, Dan Book.
304              
305             This library is free software; you may redistribute it and/or modify it under
306             the terms of the Artistic License version 2.0.
307              
308             =head1 SEE ALSO
309              
310             L, L, L, L
311              
312             =cut
313              
314             1;