File Coverage

blib/lib/POE/Loop/Prima.pm
Criterion Covered Total %
statement 22 24 91.6
branch n/a
condition n/a
subroutine 8 8 100.0
pod n/a
total 30 32 93.7


line stmt bran cond sub pod time code
1             # $Id: Prima.pm,v 1.7 2010/03/24 21:59:53 dk Exp $
2              
3             # Prima event loop bridge for POE::Kernel.
4              
5             package POE::Loop::Prima;
6              
7 1     1   88107 use strict;
  1         2  
  1         33  
8 1     1   5 use warnings;
  1         2  
  1         38  
9             our $VERSION = '1.03';
10              
11             # Include common signal handling.
12 1     1   13 use POE;
  1         2  
  1         5  
13 1     1   259 use POE::Loop::PerlSignals;
  1         1  
  1         18  
14              
15             package POE::Kernel;
16              
17 1     1   3 use strict;
  1         1  
  1         20  
18 1     1   3 use warnings;
  1         1  
  1         23  
19 1     1   3 no warnings 'redefine';
  1         0  
  1         37  
20 1     1   204 use Prima;
  0            
  0            
21              
22             my $_watcher_timer;
23             my @fileno_watcher;
24              
25             #------------------------------------------------------------------------------
26             # Loop construction and destruction.
27              
28             sub loop_initialize
29             {
30             $::application = Prima::Application-> create()
31             unless $::application;
32             }
33              
34             sub loop_finalize
35             {
36             my $self = shift;
37              
38             undef $_watcher_timer;
39            
40             foreach my $fd (0..$#fileno_watcher) {
41             next unless defined $fileno_watcher[$fd];
42             foreach my $mode (MODE_RD, MODE_WR, MODE_EX) {
43             POE::Kernel::_warn(
44             "Mode $mode watcher for fileno $fd is defined during loop finalize"
45             ) if defined $fileno_watcher[$fd]->[$mode];
46             }
47             }
48              
49             if ( $::application) {
50             $::application-> destroy;
51             undef $::application;
52             }
53              
54             $self-> loop_ignore_all_signals();
55             }
56              
57             #------------------------------------------------------------------------------
58             # Signal handler maintenance functions.
59              
60             # This function sets us up a signal when whichever window is passed to
61             # it closes.
62             sub loop_attach_uidestroy
63             {
64             my ( $self, $window) = @_;
65            
66             $window-> onDestroy( sub {
67             return unless $self-> _data_ses_count();
68             $self-> _dispatch_event(
69             $self, $self,
70             EN_SIGNAL, ET_SIGNAL, [ 'UIDESTROY' ],
71             __FILE__, __LINE__, time(), -__LINE__
72             );
73             return 0;
74             } );
75             }
76              
77             #------------------------------------------------------------------------------
78             # Maintain time watchers.
79              
80             my $last_time = time();
81              
82             sub _loop_event_callback
83             {
84             my $self = $poe_kernel;
85              
86             if ( TRACE_STATISTICS) {
87             $self-> _data_stat_add('idle_seconds', time() - $last_time);
88             $last_time = time();
89             }
90            
91             $self->_data_ev_dispatch_due();
92             $self->_test_if_kernel_is_idle();
93            
94             $_watcher_timer-> stop;
95            
96             # Return false to stop.
97             return 0;
98             }
99              
100             sub loop_pause_time_watcher
101             {
102             $_watcher_timer-> stop if $_watcher_timer;
103             }
104              
105             sub loop_resume_time_watcher
106             {
107             my ($self, $next_time) = @_;
108              
109             $next_time -= time();
110             $next_time *= 1000;
111             $next_time = 0 if $next_time < 0;
112              
113             $_watcher_timer = Prima::Timer-> new(
114             owner => $::application,
115             onTick => \&_loop_event_callback,
116             ) unless $_watcher_timer;
117              
118             $_watcher_timer-> stop;
119             $_watcher_timer-> timeout( $next_time);
120             $_watcher_timer-> start;
121             }
122              
123             *loop_reset_time_watcher = \&loop_resume_time_watcher;
124              
125             #------------------------------------------------------------------------------
126             # Maintain filehandle watchers.
127              
128             my %mask = (
129             MODE_RD , [ fe::Read, 'onRead' ],
130             MODE_WR , [ fe::Write, 'onWrite' ],
131             MODE_EX , [ fe::Exception, 'onException' ],
132             );
133              
134             sub _loop_select_callback
135             {
136             my ( $self, $obj) = ( $poe_kernel, @_ );
137              
138             if (TRACE_FILES) {
139             POE::Kernel::_warn " got $mask{$obj->{mode}}->[1] callback for " . $obj-> file;
140             }
141              
142             $self-> _data_handle_enqueue_ready( $obj->{mode}, $obj-> {fileno} );
143             $self-> _test_if_kernel_is_idle();
144              
145             # Return false to stop
146             return 0;
147             }
148              
149             sub loop_watch_filehandle
150             {
151             my ($self, $handle, $mode) = @_;
152              
153             my $fileno = fileno($handle);
154             my $mask = $mask{ $mode };
155             die "Bad mode $mode" unless defined $mask;
156            
157             # Overwriting a pre-existing watcher?
158             if (defined $fileno_watcher[$fileno]->[$mode]) {
159             $fileno_watcher[$fileno]->[$mode]-> destroy;
160             undef $fileno_watcher[$fileno]->[$mode];
161             }
162            
163             if (TRACE_FILES) {
164             POE::Kernel::_warn " new file $handle in mode $mode";
165             }
166            
167             # Register the new watcher.
168             my $obj = Prima::File-> new(
169             owner => $::application,
170             file => $handle,
171             mask => $mask-> [0],
172             $mask-> [1] => \&_loop_select_callback,
173             );
174              
175             $obj-> {mode} = $mode;
176             $obj-> {fileno} = $fileno;
177              
178             $fileno_watcher[$fileno]->[$mode] = $obj;
179             }
180              
181             *loop_resume_filehandle = \&loop_watch_filehandle;
182              
183             sub loop_ignore_filehandle
184             {
185             my ($self, $handle, $mode) = @_;
186             my $fileno = fileno($handle);
187            
188             if (TRACE_FILES) {
189             POE::Kernel::_warn " destroy file $handle in mode $mode";
190             }
191            
192             if (defined $fileno_watcher[$fileno]->[$mode]) {
193             $fileno_watcher[$fileno]->[$mode]-> destroy;
194             undef $fileno_watcher[$fileno]->[$mode];
195             }
196             }
197              
198             *loop_pause_filehandle = \&loop_ignore_filehandle;
199              
200             #------------------------------------------------------------------------------
201             # The event loop itself.
202              
203             sub loop_do_timeslice
204             {
205             my $self = shift;
206            
207             # Check for a hung kernel.
208             $self-> _test_if_kernel_is_idle();
209              
210             my $now = time if TRACE_STATISTICS;
211              
212             $::application-> yield() if $::application;
213            
214             $self-> _data_stat_add('idle_seconds', time - $now) if TRACE_STATISTICS;
215            
216             # Dispatch whatever events are due. Update the next dispatch time.
217             $self-> _data_ev_dispatch_due();
218             }
219              
220             sub loop_run
221             {
222             my $self = shift;
223              
224             # Run for as long as there are sessions to service.
225             while ($self->_data_ses_count()) {
226             $self->loop_do_timeslice();
227             }
228             }
229              
230             sub loop_halt {}
231              
232             sub skip_tests
233             {
234             return "Prima tests require the Prima module"
235             if do { eval "use Prima"; $@ };
236             }
237              
238             1;
239              
240             __END__