File Coverage

blib/lib/HOE/POE/Kernel.pm
Criterion Covered Total %
statement 339 606 55.9
branch 72 182 39.5
condition 19 45 42.2
subroutine 51 88 57.9
pod 45 52 86.5
total 526 973 54.0


line stmt bran cond sub pod time code
1             package POE::Kernel;
2              
3 110     110   9522836 use strict;
  110         225  
  110         4621  
4 110     110   559 use warnings;
  110         219  
  110         4090  
5              
6 110     110   555 use Time::HiRes;
  110         220  
  110         668  
7 110     110   113609 use WeakRef;
  110         127721  
  110         11052  
8              
9 110     110   79606 use POE::Callstack qw(CURRENT_SESSION CURRENT_EVENT);
  110         332  
  110         8059  
10 110     110   72438 use POE::Event;
  110         438  
  110         4332  
11 110     110   69330 use POE::Event::Signal;
  110         326  
  110         2937  
12 110     110   65490 use POE::Event::Alarm;
  110         220  
  110         3018  
13 110     110   62702 use POE::Session::Dead;
  110         224  
  110         3143  
14              
15 110     110   661 use Carp qw(cluck croak);
  110         118  
  110         8806  
16              
17 110     110   554 use Errno qw(EPERM ESRCH EEXIST);
  110         220  
  110         6015  
18              
19 110     110   654 use vars qw($poe_kernel);
  110         216  
  110         29469  
20              
21             # This is for silently making POE::Kernel->whatever from a package to an object call...
22             # it may not even be necessary... heck, it may not even work... should test that.
23             # Followup: It is necessary.
24             sub POE::Kernel {
25 229     229 1 407426 return $poe_kernel;
26             }
27              
28             BEGIN {
29 110 50   110   580 if($ENV{'HOE_DEBUG'}) {
30 0         0 eval "sub DEBUGGING () { 1 }";
31             }
32             else {
33 110         6339 eval "sub DEBUGGING () { 0 }";
34             }
35              
36 110 50       1438 unless (__PACKAGE__->can('ASSERT_USAGE')) {
37 110         3215 eval "sub ASSERT_USAGE () { 0 }";
38             }
39              
40 110         326 my $debug_file;
41            
42 110 50       440 if(my $debug_filename = $ENV{'HOE_DEBUG_FILE'}) {
43 0 0       0 unless (open $debug_file, '>', $debug_filename) {
44 0         0 warn "can't open debug file '$debug_filename': $!";
45 0         0 $debug_file = \*STDERR;
46             }
47 0         0 CORE::select((CORE::select($debug_file), $| = 1)[0]);
48             }
49             else {
50 110         49397 $debug_file = \*STDERR;
51             }
52              
53             sub DEBUG {
54 0     0 0 0 print $debug_file @_;
55             }
56             }
57              
58             sub RUNNING_IN_HELL () { 0 }
59              
60             sub CHECKING_INTEGRITY () { 1 }
61              
62             sub new {
63 150     150 1 283 my $class = shift;
64 150   33     1534 my $self = bless [], (ref $class || $class);
65 150         728 $self->_init();
66              
67 150         329 return $self;
68             }
69              
70             my $counter = 0;
71              
72             sub _init {
73 190     190   310 my $self = shift;
74              
75 190         329 ++$counter;
76            
77 190         2453 @$self = (
78             {}, # Aliases
79             [], # Queue
80             {}, # FH Reads
81             {}, # FH Reads (Paused)
82             {}, # FH Writes
83             {}, # FH Writes (Paused)
84             {}, # FH Expedites
85             {}, # FH Expedites (Paused spot, DANGEROUS, necessary for now)
86             {}, # Refs
87             {}, # IDS
88             {}, # Sessions
89             {}, # Signals
90             {}, # Parent Session, by child session
91             {}, # Child Sessions hashref "key"==value (weakened values), by parent session
92             "THE KERNEL $counter", # ID
93             );
94             }
95              
96             sub KR_ALIASES () { 0 }
97             sub KR_QUEUE () { 1 }
98             sub KR_FH_READS () { 2 }
99             sub KR_FH_READS_PAUSED () { 3 }
100             sub KR_FH_WRITES () { 4 }
101             sub KR_FH_WRITES_PAUSED () { 5 }
102             sub KR_FH_EXPEDITES () { 6 }
103             sub KR_FH_EXPEDITES_NASTY () { 7 } # I have to make this exist to prevent crashes until I make watcher objects.
104             sub KR_REFS () { 8 }
105             sub KR_IDS () { 9 }
106             sub KR_SESSIONS () { 10 }
107             sub KR_SIGNALS () { 11 }
108             sub KR_PARENTS () { 12 }
109             sub KR_CHILDREN () { 13 }
110             sub KR_ID () { 14 }
111              
112             sub import {
113 110     110   1132 my $package = caller();
114 110     110   783 no strict 'refs';
  110         127  
  110         48265  
115 110         325 my $export_kernel = $poe_kernel;
116 110         230 *{ "${package}::poe_kernel" } = \$export_kernel;
  110         678  
117 110         232 weaken( ${ "${package}::poe_kernel" } );
  110         2116  
118             }
119              
120             {
121             my $next_id = 1;
122             my %hijacked_namespaces;
123            
124             sub session_alloc {
125 190     190 1 126054 my $self = shift;
126 190         352 my $session = shift;
127 190         407 my @args = @_;
128 190         552 my $id = $next_id++;
129 190         1550 weaken($self->[KR_IDS]->{$id} = $session);
130 190         699 $self->[KR_SESSIONS]->{$session} = $id;
131              
132 190         890 my $parent = CURRENT_SESSION;
133              
134 190         692 $self->[KR_PARENTS]->{$session} = $parent;
135 190         1009 weaken($self->[KR_CHILDREN]->{$parent}->{$session} = $session);
136            
137             # Who is SENDER in this case?
138 190         648 my $result = $self->call( $session, '_start', @args );
139            
140             # $parent could be the Kernel, \@result may not be correct, see POE::Session docs which are vague.
141 190         673 $self->call( $parent, '_child', 'create', $session, $result );
142              
143 110     110   571 no strict 'refs';
  110         221  
  110         4773  
144 110     110   652 no warnings 'redefine';
  110         221  
  110         775417  
145 190         366 my $package = ref($session);
146 190 100       889 unless (exists $hijacked_namespaces{$package}) {
147 109         116 my $old_destroy = *{"${package}::DESTROY"}{CODE};
  109         667  
148 109         559 *{"${package}::DESTROY"} = sub {
149 90     90   132 my $inner_self = shift;
150 90 50       457 defined( $POE::Kernel::poe_kernel ) and
151             $POE::Kernel::poe_kernel->session_dealloc( $inner_self );
152 90 100       1204 return unless $old_destroy;
153 2         18 $old_destroy->($inner_self);
154 2         51 bless $inner_self, 'POE::Session::Dead';
155 109         754 };
156 109         469 $hijacked_namespaces{$package} = undef;
157             }
158             }
159             }
160              
161             sub session_dealloc {
162 90     90 0 119 my $self = shift;
163 90         101 my $session = shift;
164 90         108 DEBUG "[SESSION] Deallocating $session\n" if DEBUGGING;
165              
166 90 100       457 if (exists $self->[KR_SESSIONS]->{$session}) {
167 50         130 my @result = $self->call( $session, '_stop' );
168 50         170 my $parent = $self->[KR_PARENTS]->{$session};
169              
170             # $parent could be the Kernel, the args list is vaguely documented in POE::Session... not sure this is correct
171 50         166 $self->call( $parent, '_child', 'lose', $session, \@result );
172             }
173 90         290 $self->cleanup_session( $session );
174             }
175              
176             sub cleanup_session {
177 130     130 0 260 my $self = shift;
178 130         140 my $session = shift;
179              
180             # We could destroy the innards of the session and that may help clean things up
181              
182 130 100       474 if (my $id = $self->[KR_SESSIONS]->{$session} ) {
183 90         241 delete $self->[KR_SESSIONS]->{$session};
184 90         218 delete $self->[KR_IDS]->{$id};
185             }
186 130 100       440 if (my $parent = delete $self->[KR_PARENTS]->{$session}) {
187 90         484 delete $self->[KR_CHILDREN]->{$parent}->{$session};
188             }
189 130         324 return;
190             }
191              
192             sub ID {
193 300     300 1 629 my $self = shift;
194 300         2042 return $self->[KR_ID];
195             }
196              
197             sub ID_session_to_id {
198 0     0 1 0 my $self = shift;
199 0         0 my $session = shift;
200            
201 0         0 return $self->[KR_SESSIONS]->{$session};
202             }
203              
204             sub ID_id_to_session {
205 0     0 1 0 my $self = shift;
206 0         0 my $id = shift;
207              
208 0         0 return $self->[KR_IDS]->{$id};
209             }
210              
211             sub get_active_session {
212 0     0 1 0 return CURRENT_SESSION;
213             }
214              
215             sub get_active_event {
216 0     0 1 0 return CURRENT_EVENT;
217             }
218              
219             sub get_children {
220 143     143 0 201 my $self = shift;
221 143         38108 my $parent = shift;
222              
223 143 50       371 unless (defined( $parent )) {
224 0         0 cluck( "Undefined parent to find children of\n" );
225             }
226            
227 143 100       597 if (exists $self->[KR_CHILDREN]->{$parent}) {
228 42         56 return values %{$self->[KR_CHILDREN]->{$parent}};
  42         197  
229             }
230 101         333 return (); # return empty list or undef... empty list prevents recursion problems... undef seems more correct
231             }
232              
233             sub stop {
234             # If this gets called from within an event dispatched by a signal event,
235             # then it won't stop till the signal event is finished dispatching, dangerous
236 40     40 1 139 my $self = shift;
237 40         84 foreach my $child ($self->get_children($self)) {
238 40         102 $self->cleanup_session( $child );
239             }
240            
241             # all kernel structures need to be purged in the same way, yucky, but very necessary
242 40         61 @{$self->[KR_QUEUE]} = ();
  40         118  
243 40         102 $self->_init();
244 40         115 initialize_kernel();
245             }
246              
247             sub detach_child {
248 0     0 1 0 my $self = shift;
249 0         0 my $session = shift;
250              
251 0 0       0 if (grep { $session == $_ } $self->get_children( CURRENT_SESSION )) {
  0         0  
252 0         0 return _internal_detach( $session );
253             }
254             else {
255 0         0 $! = EPERM;
256 0         0 return 0;
257             }
258             }
259              
260             sub detach_myself {
261 0     0 1 0 my $self = shift;
262 0         0 return _internal_detach( CURRENT_SESSION );
263             }
264              
265             sub _internal_detach {
266 0     0   0 my $self = shift;
267 0         0 my $session = shift;
268              
269 0         0 my $parents = $self->[KR_PARENTS];
270 0         0 my $children = $self->[KR_CHILDREN];
271              
272 0 0       0 if (exists( $parents->{$session} )) {
273 0         0 my $old_parent = $parents->{$session};
274            
275 0 0       0 if ($old_parent == $self) {
276 0         0 $! = EPERM;
277 0         0 return 0;
278             }
279             else {
280 0         0 $self->call( $old_parent, '_child', 'lose', $session );
281 0         0 delete( $children->{$old_parent}->{$session} );
282              
283             # Prevent leaks
284 0 0       0 keys( %{$children->{$old_parent}} ) or delete $children->{$old_parent};
  0         0  
285              
286 0         0 $self->[KR_PARENTS]->{$session} = $self;
287 0         0 weaken($self->[KR_CHILDREN]->{$self}->{$session} = $session);
288              
289 0         0 $self->call( $session, '_parent', $old_parent, $self );
290             # This is always the kernel... what the heck is this event for?
291             #$self->call( $self, '_child', 'gain', $session );
292            
293 0         0 return 1;
294             }
295             }
296             else {
297 0         0 $! = ESRCH;
298 0         0 return 0;
299             }
300             }
301              
302             sub post {
303 1     1 1 1166 my $self = shift;
304 1         3 my ($to, $state, @etc) = @_;
305              
306 1 50       4 die "destination is undefined in post" unless(defined( $to ));
307 1 50       3 die "event is undefined in post" unless(defined( $state ));
308              
309             # Name resolution /could/ happen during dispatch instead, I think everything would stay alive just fine simply because kernel is embedded in the event, and the sessions are all held inside aliases within that.
310 1         9 my $from = CURRENT_SESSION;
311 1         2 my $queue = $self->[KR_QUEUE];
312 1         5 @$queue = sort { $a <=> $b } (@$queue, POE::Event->new( $self, time, $from, $to, $state, \@etc ));
  0         0  
313              
314 1         7 DEBUG "[POST] Kernel: $self From: $from To: $to State: $state Args: @etc\n" if DEBUGGING;
315             }
316              
317             sub yield {
318 227     227 1 71703 my $self = shift;
319 227         959 my ($state, @etc) = @_;
320              
321 227 50       708 die "event name is undefined in yield" unless(defined( $state ));
322              
323 227         662 my $from = CURRENT_SESSION;
324 227         525 my $queue = $self->[KR_QUEUE];
325 227         1720 @$queue = sort { $a <=> $b } (@$queue, POE::Event->new( $self, time, $from, $from, $state, \@etc ));
  0         0  
326            
327 227         1809 DEBUG "[YIELD] Kernel $self From/To: $from State: $state\n" if DEBUGGING;
328             }
329              
330             sub call {
331 483     483 1 2200 my $self = shift;
332 483         1250 my ($to, $state, @etc) = @_;
333              
334 483 50       991 croak( "destination undefined in call" ) unless(defined( $to ));
335 483 50       6765 croak( "event undefined in call" ) unless(defined( $to ));
336              
337 483         745 DEBUG "[CALL] Kernel: $self To: $to State: $state\n" if DEBUGGING;
338 483         584 my $return;
339             my @return;
340 483         662 my $wantarray = wantarray;
341              
342 483         1346 my $event = POE::Event->new( $self, undef, CURRENT_SESSION, $to, $state, \@etc );
343              
344 483 100       1217 if (defined( $wantarray )) {
345 242 100       767 if ($wantarray) {
346 51         238 @return = $event->dispatch();
347             }
348             else {
349 191         1438 $return = $event->dispatch();
350             }
351             }
352             else {
353 241         1040 $event->dispatch();
354             }
355            
356 483         684 DEBUG "[CALL] Completed\n" if DEBUGGING;
357              
358 483 100       888 if (defined( $wantarray )) {
359 242 100       1350 if ($wantarray) {
360 51         205 return @return;
361             }
362             else {
363 191         1152 return $return;
364             }
365             }
366             else {
367 241         704 return;
368             }
369             }
370              
371             sub resolve_session {
372 924     924 0 1352 my $self = shift;
373 924         1013 my $input = $_[0];
374            
375 924         1295 my $aliases = $self->[KR_ALIASES];
376 924         1379 my $ids = $self->[KR_IDS];
377              
378 924         1110 DEBUG( "[RESOLVE] Input: $input\n" ) if DEBUGGING;
379              
380 924 50       2255 unless( $input ) {
381 0         0 cluck( "Undefined state resolution attempted\n" );
382             }
383              
384 924 50 33     80979 if (ref( $input ) and $input->can('_invoke_state')) {
    0          
    0          
385 924         19764 return $input;
386             }
387             elsif (exists( $aliases->{$input} )) {
388 0         0 return $aliases->{$input};
389             }
390             elsif (exists( $ids->{$input} )) {
391 0         0 return $ids->{$input};
392             }
393             else {
394             # return $input;
395 0         0 return undef; # shouldn't this be more correct?
396             }
397             }
398              
399             sub _select_any {
400 0     0   0 my $self = shift;
401 0         0 my $class = shift;
402 0         0 my $fh = shift;
403 0         0 my $event = shift;
404              
405 0         0 my $fd = fileno($fh);
406              
407 0         0 my $current_session = CURRENT_SESSION;
408              
409 0 0       0 unless (defined( $current_session )) {
410 0         0 DEBUG "[[[BAD]]] Current session undefined, global destruction?\n";
411 0         0 return;
412             }
413            
414 0         0 my $main_class = $self->[$class];
415 0         0 my $paused_class = $self->[$class + 1];
416              
417 0 0       0 if ($event) { # Setup watcher
418 0         0 DEBUG "[WATCH] Watch Fd: $fd Fh: $fh Class: $class Event: $event\n" if DEBUGGING;
419 0 0 0     0 unless (exists $main_class->{$fd} and ref $main_class->{$fd} eq 'ARRAY') {
420 0         0 $main_class->{$fd} = [];
421             }
422              
423 0 0       0 unless (grep { $_->{session} == $current_session } @{$main_class->{$fd}}) {
  0         0  
  0         0  
424 0         0 push @{$main_class->{$fd}}, {
  0         0  
425             kernel => $self,
426             session => $current_session,
427             fd => $fd,
428             fh => $fh,
429             event => $event,
430             };
431             }
432             }
433             else { # Clear watcher
434 0         0 DEBUG "[WATCH] Stop Fd: $fd Fh: $fh Class: $class\n" if DEBUGGING;
435 0 0       0 @{$main_class->{$fd}} = grep {
  0         0  
436 0         0 defined( $_->{session} ) and $_->{session} != $current_session
437 0         0 } (@{$main_class->{$fd}});
438            
439 0 0       0 @{$paused_class->{$fd}} = grep {
  0         0  
440 0         0 defined( $_->{session} ) and $_->{session} != $current_session
441 0         0 } (@{$paused_class->{$fd}});
442              
443 0 0       0 unless (@{$main_class->{$fd}}) {
  0         0  
444 0         0 delete $main_class->{$fd};
445             }
446 0 0       0 unless (@{$paused_class->{$fd}}) {
  0         0  
447 0         0 delete $paused_class->{$fd};
448             }
449             }
450             }
451              
452             sub select_read {
453 0     0 1 0 my $self = shift;
454 0         0 DEBUG "[WATCH] Read @_\n" if DEBUGGING;
455 0         0 $self->_select_any( KR_FH_READS, @_ );
456             }
457              
458             sub select_write {
459 0     0 1 0 my $self = shift;
460 0         0 DEBUG "[WATCH] Write @_\n" if DEBUGGING;
461 0         0 $self->_select_any( KR_FH_WRITES, @_ );
462             }
463              
464             sub select_expedite {
465 0     0 1 0 my $self = shift;
466 0         0 DEBUG "[WATCH] Expedite @_\n" if DEBUGGING;
467 0         0 $self->_select_any( KR_FH_EXPEDITES, @_ );
468             }
469              
470             sub select {
471 0     0 1 0 my $self = shift;
472 0         0 my $fh = shift;
473              
474             # $self->
475             # if (@_ == 3) {
476 0         0 my ($read, $write, $expedite) = @_;
477              
478 0         0 $self->select_read( $fh, $read );
479 0         0 $self->select_write( $fh, $write );
480 0         0 $self->select_expedite( $fh, $expedite );
481             # }
482             # elsif (@_ == 0) {
483             # $self->select_read( $fh );
484             # $self->select_write( $fh );
485             # $self->select_expedite( $fh );
486             # }
487             # else {
488             # die();
489             # }
490             }
491              
492             sub _select_pause_any {
493 0     0   0 my $self = shift;
494 0         0 my $class = shift;
495 0         0 my $fh = shift;
496 0         0 my $fd = fileno( $fh );
497              
498 0         0 my $main_class = $self->[$class];
499 0         0 my $paused_class = $self->[$class + 1];
500              
501 0         0 $paused_class->{$fd} = $main_class->{$fd};
502 0         0 delete $main_class->{$fd};
503             }
504              
505             sub select_pause_read {
506 0     0 1 0 my $self = shift;
507 0         0 DEBUG "[WATCH] Read pause: @_\n" if DEBUGGING;
508 0         0 $self->_select_pause_any( KR_FH_READS, @_ );
509             }
510              
511             sub select_pause_write {
512 0     0 1 0 my $self = shift;
513 0         0 DEBUG "[WATCH] Write pause: @_\n" if DEBUGGING;
514 0         0 $self->_select_pause_any( KR_FH_WRITES, @_ );
515             }
516              
517             sub _select_resume_any {
518 0     0   0 my $self = shift;
519 0         0 my $class = shift;
520 0         0 my $fh = shift;
521 0         0 my $fd = fileno( $fh );
522              
523 0         0 my $main_class = $self->[$class];
524 0         0 my $paused_class = $self->[$class + 1];
525              
526 0         0 $main_class->{$fd} = $paused_class->{$fd};
527 0         0 delete $paused_class->{$fd};
528             }
529              
530             sub select_resume_read {
531 0     0 1 0 my $self = shift;
532 0         0 DEBUG "[WATCH] Read resume: @_\n" if DEBUGGING;
533 0         0 $self->_select_resume_any( KR_FH_READS, @_ );
534             }
535              
536             sub select_resume_write {
537 0     0 1 0 my $self = shift;
538 0         0 DEBUG "[WATCH] Write resume: @_\n" if DEBUGGING;
539 0         0 $self->_select_resume_any( KR_FH_WRITES, @_ );
540             }
541              
542             sub delay {
543 4     4 1 462 my @stuff = @_;
544              
545 4         6 DEBUG( "[ALARM] delay\n" ) if DEBUGGING;
546            
547 4 50       10 die unless $_[1];
548              
549 4         12 _internal_alarm_destroy(@stuff);
550              
551 4         5 my $result;
552              
553 4 50       11 if (defined( $_[2] )) {
554 4         14 $stuff[2] += time;
555 4         11 $result = _internal_alarm_add(@stuff);
556             }
557              
558 4 50       27 return 0 if (defined( $result ));
559             }
560              
561             sub delay_add {
562 1     1 1 8 my @stuff = @_;
563            
564 1         2 DEBUG( "[ALARM] delay_add\n" ) if DEBUGGING;
565            
566 1 50       4 die unless $_[1];
567 1 50       4 die unless $_[2];
568              
569 1         2 $stuff[2] += time;
570              
571 1 50       197 return 0 if (defined( _internal_alarm_add(@stuff) ));
572             }
573              
574             sub alarm {
575 1     1 1 7 DEBUG( "[ALARM] alarm\n" ) if DEBUGGING;
576              
577 1 50       16 die unless $_[1];
578              
579 1         4 _internal_alarm_destroy(@_);
580              
581 1         2 my $result;
582            
583 1 50       4 if (defined( $_[2] )) {
584 1         4 _internal_alarm_add(@_);
585             }
586              
587 1 50       4 return 0 if (defined( $result ));
588             }
589              
590             sub alarm_add {
591 1     1 1 5 DEBUG( "[ALARM] alarm_add\n" ) if DEBUGGING;
592              
593 1 50       4 die unless $_[1];
594 1 50       4 die unless $_[2];
595              
596 1 50       3 return 0 if (defined( _internal_alarm_add(@_) ));
597             }
598              
599             sub _internal_alarm_add {
600 10     10   27 my ($self, $name, $seconds, @args) = @_;
601              
602 10         9 DEBUG( "[ALARM] _internal_alarm_add\n" ) if DEBUGGING;
603              
604 10         18 my $queue = $self->[KR_QUEUE];
605              
606 10         29 my $current_session = CURRENT_SESSION;
607              
608 10         263 my $event = POE::Event::Alarm->new(
609             $self,
610             $seconds,
611             $current_session,
612             $current_session,
613             $name,
614             \@args,
615             time,
616             );
617              
618 10         54 @$queue = sort { $a <=> $b } (
  6         36  
619             @$queue,
620             $event
621             );
622              
623 10         37 return $event->alarm_id;
624             }
625              
626             sub _internal_alarm_destroy {
627 5     5   7 my ($self, $event) = @_;
628              
629 5         9 my $queue = $self->[KR_QUEUE];
630              
631 5         15 my $current_session = CURRENT_SESSION;
632              
633             # This algorithm is completely wrong, I don't know what I was thinking when I wrote it
634            
635 5   66     11 @$queue = grep { not ( $_->can('alarm_id') and $current_session == $_->from and $event eq $_->name() ) } @$queue;
  3         39  
636             }
637              
638             sub alarm_adjust {
639 0     0 1 0 my ($self, $alarm_id, $delta) = @_;
640              
641 0         0 DEBUG( "[ALARM] Adjusting $alarm_id by $delta\n" ) if DEBUGGING;
642            
643 0         0 my $queue = $self->[KR_QUEUE];
644              
645 0 0       0 my @alarms = grep { $_->can('alarm_id') and $_->alarm_id == $alarm_id } @$queue;
  0         0  
646              
647 0 0       0 if (@alarms == 1) {
648 0         0 return $alarms[0]->adjust_when( $delta );
649             }
650             }
651              
652             sub alarm_set {
653 1     1 1 931 DEBUG( "[ALARM] Setting Alarm @_\n" ) if DEBUGGING;
654 1         6 return _internal_alarm_add(@_);
655             }
656              
657             sub alarm_remove {
658 1     1 1 6 my ($self, $alarm_id) = @_;
659              
660 1         3 my $queue = $self->[KR_QUEUE];
661 1         2 my @events;
662              
663 1         3 my $current_session = CURRENT_SESSION;
664              
665 1         3 DEBUG( "[ALARM] Attempting removal of ID# $alarm_id from $current_session\n" ) if DEBUGGING;
666              
667 2         3 @$queue = map {
668 1         2 DEBUG( "[ALARM] Iterating: $_ from " . $_->from . "\n" ) if DEBUGGING;
669 2 100 66     54 if ($_->can('alarm_id') and $_->alarm_id == $alarm_id and $current_session == $_->from) {
      66        
670 1         3 push @events, $_;
671 1         2 ();
672             }
673             else {
674 1         5 $_;
675             }
676             } @$queue;
677              
678 1         2 DEBUG( "[ALARM] " . @events . " matching events found, and removed\n" ) if DEBUGGING;
679              
680 1 50       4 if (@events == 1) {
681 1         9 my $event = shift @events;
682 1         7 my $things = [ $event->name, $event->when, $event->args ];
683              
684 1 50       5 if (wantarray) {
685 0         0 return @$things;
686             }
687             else {
688 1         18 return $things;
689             }
690             }
691              
692 0         0 return;
693             }
694              
695             sub alarm_remove_all {
696 0     0 1 0 my ($self) = @_;
697              
698 0         0 my $queue = $self->[KR_QUEUE];
699 0         0 my @events;
700              
701 0         0 my $current_session = CURRENT_SESSION;
702              
703 0         0 DEBUG( "[ALARM] alarm_remove_all\n" ) if DEBUGGING;
704              
705             @$queue = map {
706 0 0 0     0 if ($_->can('alarm_id') and $current_session == $_->from) {
  0         0  
707 0         0 push @events, $_;
708 0         0 ();
709             }
710             else {
711 0         0 $_;
712             }
713             } @$queue;
714              
715 0         0 DEBUG( "[ALARM] alarm_remove_all: removed " . @events . " alarm events for $current_session.\n" ) if DEBUGGING;
716              
717 0         0 my $things = [ map { [ $_->name, $_->when, $_->args ] } @events ];
  0         0  
718              
719 0 0       0 if (wantarray) {
720 0         0 return @$things;
721             }
722             else {
723 0         0 return $things;
724             }
725             }
726              
727             sub delay_set {
728 2     2 1 1105 my @stuff = @_;
729              
730 2         3 DEBUG( "[ALARM] delay_set\n" ) if DEBUGGING;
731            
732 2 50       7 die unless $_[1];
733 2 50       6 die unless $_[2];
734              
735 2         10 $stuff[2] += time;
736              
737 2         6 _internal_alarm_add(@stuff);
738             }
739              
740             sub delay_adjust {
741 0     0 1 0 my ($self, $alarm_id, $when) = @_;
742              
743 0         0 DEBUG( "[ALARM] delay_adjust\n" ) if DEBUGGING;
744              
745 0         0 my $queue = $self->[KR_QUEUE];
746              
747 0 0       0 my @alarms = grep { $_->can('alarm_id') and $_->alarm_id == $alarm_id } @$queue;
  0         0  
748              
749 0 0       0 if (@alarms == 1) {
750 0         0 return $alarms[0]->set_when( $when + time );
751             }
752             }
753              
754             sub run {
755 187     187 1 414 my $self = shift;
756 187         299 DEBUG "[KERNEL] Starting Loop\n" if DEBUGGING;
757 187 100       1349 weaken( $poe_kernel ) unless isweak( $poe_kernel );
758              
759 187         451 my $queue = $self->[KR_QUEUE];
760 187         315 my $fh_reads = $self->[KR_FH_READS];
761 187         403 my $fh_preads = $self->[KR_FH_READS_PAUSED];
762 187         226 my $fh_writes = $self->[KR_FH_WRITES];
763 187         399 my $fh_pwrites = $self->[KR_FH_WRITES_PAUSED];
764 187         208 my $fh_expedites = $self->[KR_FH_EXPEDITES];
765 187         509 my $signals = $self->[KR_SIGNALS];
766              
767 187   66     1449 while (
      66        
      33        
      33        
      33        
      66        
768             @$queue or
769             keys %$fh_reads or
770             keys %$fh_preads or
771             keys %$fh_writes or
772             keys %$fh_pwrites or
773             keys %$fh_expedites or
774             keys %$signals
775             ) {
776 310         712 my $when;
777 310         54031 while (@$queue) {
778 301         1745 $when = $queue->[0]->when();
779 301         816 my $now = time;
780 301 100       1144 if ($when <= $now) {
781 296         519 my $event = shift @$queue;
782 296         1349 my $from = $event->from;
783 296         1558 my $name = $event->name;
784 296         563 DEBUG "[DISPATCH] $event @$event From: $from Event: $name Args: " . join(',', $event->args) . "\n" if DEBUGGING;
785 296         60008 $event->dispatch();
786 196         537 DEBUG "[DISPATCH] Completed\n" if DEBUGGING;
787 196 100       1029 if (@$queue) {
788 50         224 $when = $queue->[0]->when();
789             }
790             }
791             else {
792 5         125 last;
793             }
794             }
795            
796 210 100       586 if (defined( $when )) {
797 151         256 $when -= time;
798 151 100       407 if ($when < 0) {
799 1         9 $when = 0;
800             }
801             }
802            
803 210         982 $self->_select($when);
804             }
805            
806 87         422 POE::Callstack::POP;
807 87         254 POE::Callstack::CLEAN;
808 87         680 POE::Callstack::PUSH( $poe_kernel );
809              
810 87         1713 DEBUG "[RUN] Kernel exited cleanly\n" if DEBUGGING;
811             }
812              
813             sub run_one_timeslice {
814 0     0 1 0 my $self = shift;
815              
816 0         0 my $queue = $self->[KR_QUEUE];
817              
818 0         0 $self->_select( 0 );
819              
820 0         0 my $when;
821            
822 0         0 while (@$queue) {
823 0         0 $when = $queue->[0]->when();
824 0 0       0 if ($when <= time) {
825 0         0 my $event = shift @$queue;
826 0         0 my $from = $event->from;
827 0         0 my $name = $event->name;
828 0         0 $event->dispatch();
829 0 0       0 if (@$queue) {
830 0         0 $when = $queue->[0]->when();
831             }
832             }
833             else {
834 0         0 last;
835             }
836             }
837              
838 0 0       0 if (defined( $when )) {
839 0         0 $when -= time;
840 0 0       0 if ($when < 0) {
841 0         0 $when = 0;
842             }
843             }
844              
845 0         0 return $when;
846             }
847              
848             sub _select {
849 210     210   365 my $self = shift;
850 210         327 my $timeout = shift;
851              
852 210         385 my $reads = $self->[KR_FH_READS];
853 210         563 my $preads = $self->[KR_FH_READS_PAUSED];
854 210         781 my $writes = $self->[KR_FH_WRITES];
855 210         329 my $pwrites = $self->[KR_FH_WRITES_PAUSED];
856 210         19650 my $expedites = $self->[KR_FH_EXPEDITES];
857 210         290 my $signals = $self->[KR_SIGNALS];
858              
859 210         377 my $rin = my $win = my $ein = '';
860            
861 210         273 my $read_count = 0;
862 210         664 foreach my $fd (keys %$reads) {
863 0         0 $read_count++;
864 0         0 vec($rin, $fd, 1) = 1;
865             }
866              
867 210         366 my $pread_count = 0;
868 210         673 foreach my $fd (keys %$preads) {
869 0         0 $pread_count++;
870             }
871              
872 210         326 my $write_count = 0;
873 210         513 foreach my $fd (keys %$writes) {
874 0         0 $write_count++;
875 0         0 vec($win, $fd, 1) = 1;
876             }
877              
878 210         293 my $pwrite_count = 0;
879 210         590 foreach my $fd (keys %$pwrites) {
880 0         0 $pwrite_count++;
881             }
882              
883 210         465 my $expedite_count = 0;
884 210         551 foreach my $fd (keys %$expedites) {
885 0         0 $expedite_count++;
886 0         0 vec($ein, $fd, 1) = 1;
887             }
888              
889 210         358 my $signal_count = 0;
890 210         444 foreach my $signal (keys %$signals) {
891 118         357 $signal_count++;
892             }
893              
894 210         265 if (DEBUGGING) {
895             if (defined( $timeout )) {
896             DEBUG "[POLL] Waiting a maximum of $timeout for $read_count reads, $pread_count paused reads, $write_count writes, $pwrite_count paused writes, $expedite_count expedite reads, and $signal_count signals.\n";
897             }
898             else {
899             DEBUG "[POLL] Waiting for $read_count reads, $pread_count paused reads, $write_count writes, $pwrite_count paused writes, $expedite_count expedite reads, and $signal_count signals.\n";
900             }
901             }
902              
903 210         331771466 my $nfound = CORE::select( my $rout = $rin, my $wout = $win, my $eout = $ein, $timeout );
904              
905 210         1258478 while (my ($fd, $watchers) = each %$reads) {
906 0 0       0 if (vec( $rout, $fd, 1 )) {
907 0         0 foreach my $watcher (@$watchers) {
908 0         0 $self->post( $watcher->{session}, $watcher->{event}, $watcher->{fh} );
909             }
910             }
911             }
912 210         716 while (my ($fd, $watchers) = each %$writes) {
913 0 0       0 if (vec( $wout, $fd, 1 )) {
914 0         0 foreach my $watcher (@$watchers) {
915 0         0 $self->post( $watcher->{session}, $watcher->{event}, $watcher->{fh} );
916             }
917             }
918             }
919 210         63166 while (my ($fd, $watchers) = each %$expedites) {
920 0 0       0 if (vec( $eout, $fd, 1 )) {
921 0         0 foreach my $watcher( @$watchers) {
922 0         0 $self->post( $watcher->{session}, $watcher->{event}, $watcher->{fh} );
923             }
924             }
925             }
926             }
927              
928             sub alias_set {
929 0     0 1 0 my $self = shift;
930 0         0 my $alias = $_[0];
931            
932 0         0 my $session = CURRENT_SESSION;
933 0         0 my $aliases = $self->[KR_ALIASES];
934              
935 0 0       0 if (exists( $aliases->{$alias} )) {
936 0 0       0 if ($aliases->{$alias} == $session) {
937 0         0 return 0;
938             }
939             else {
940 0         0 return EEXIST;
941             }
942             }
943             else {
944 0         0 $self->[KR_ALIASES]->{$alias} = $session;
945 0         0 return 0;
946             }
947              
948             # We can either hook into the session and wait for a DESTROY event to come back to us to clean up the alias, or we can stipulate that the session object must clean up all of it's own aliases. The latter may be better for speed and clean code.
949             }
950            
951             sub alias_remove {
952 0     0 1 0 my $self = shift;
953 0         0 my $alias = $_[0];
954              
955 0 0       0 croak( "Called alias_remove with no arguments\n" ) unless @_;
956              
957 0         0 my $aliases = $self->[KR_ALIASES];
958              
959 0 0       0 if (exists( $aliases->{$alias} )) {
960 0 0       0 if ($aliases->{$alias} == CURRENT_SESSION) {
961 0         0 delete $aliases->{$alias};
962 0         0 return 0
963             }
964             else {
965 0         0 return EPERM;
966             }
967             }
968             else {
969 0         0 return ESRCH;
970             }
971             }
972              
973             sub alias_resolve {
974 0     0 1 0 my $self = shift;
975 0         0 my $alias = $_[0];
976              
977 0         0 my $aliases = $self->[KR_ALIASES];
978 0         0 my $ids = $self->[KR_IDS];
979 0         0 my $sessions = $self->[KR_SESSIONS];
980              
981 0 0       0 if (exists( $aliases->{$alias} )) {
    0          
    0          
982 0         0 return $aliases->{$alias};
983             }
984             elsif (exists( $ids->{$alias} )) {
985 0         0 return $ids->{$alias};
986             }
987             elsif (exists( $sessions->{$alias} )) {
988 0         0 return $ids->{$sessions->{$alias}};
989             }
990              
991 0         0 $! = ESRCH;
992 0         0 return undef;
993             }
994              
995             sub alias_list {
996 0     0 1 0 my $self = shift;
997 0 0       0 my $session = (@_ ? shift : CURRENT_SESSION);
998              
999 0         0 my $aliases = $self->[KR_ALIASES];
1000            
1001 0         0 return grep { $aliases->{$_} == $session } keys %$aliases;
  0         0  
1002             }
1003              
1004             sub _data_alias_loggable {
1005 0     0   0 my $self = shift;
1006 0         0 my $session = shift;
1007              
1008 0         0 my @aliases = $self->alias_list( $session );
1009              
1010 0 0       0 "session " . $session->ID . " (" .
1011             ( @aliases
1012             ? join( ", ", @aliases )
1013             : $session
1014             ) . ")"
1015             }
1016              
1017 0     0   0 sub _warn {
1018             # DEBUG( @_ );
1019             }
1020              
1021             sub refcount_increment {
1022 0     0 1 0 my $self = shift;
1023 0         0 my $session = CURRENT_SESSION;
1024 0         0 my $refs = $self->[KR_REFS];
1025 0 0 0     0 unless (exists $refs->{$session} and ref $refs->{$session} eq 'ARRAY') {
1026 0         0 $refs->{$session} = [];
1027             }
1028              
1029 0         0 push @{$refs->{$session}}, $session;
  0         0  
1030             }
1031              
1032             sub refcount_decrement {
1033 0     0 1 0 my $self = shift;
1034 0         0 my $session = CURRENT_SESSION;
1035 0         0 my $refs = $self->[KR_REFS];
1036              
1037 0         0 shift @{$refs->{$session}};
  0         0  
1038              
1039 0 0       0 unless (@{$refs->{$session}}) {
  0         0  
1040 0         0 delete $refs->{$session};
1041             }
1042             }
1043              
1044             sub state {
1045 0     0 1 0 my $self = shift;
1046 0         0 my $session = CURRENT_SESSION;
1047              
1048 0         0 return $session->register_state( @_ );
1049             }
1050              
1051             sub register_state {
1052 0     0 0 0 my $self = shift;
1053 0         0 DEBUG "[[[BAD]]] State removal attempted as kernel, @_\n";
1054             }
1055              
1056             sub sig {
1057 106     106 1 49536 my $self = shift;
1058 106         216 my $signal_name = shift;
1059 106         216 my $event = shift;
1060              
1061 106         210 if (ASSERT_USAGE) {
1062             die "undefined signal in sig" unless(defined( $signal_name ));
1063             }
1064              
1065 106         313 my $signals = $self->[KR_SIGNALS];
1066            
1067 106         321 my $session = CURRENT_SESSION;
1068              
1069 106 100       317 if ($event) {
1070 103         103 DEBUG "[SIGNAL] Session: $session Signal: $signal_name Event: $event\n" if DEBUGGING;
1071 103 100       411 unless (exists( $signals->{$signal_name} )) {
1072 102         308 $signals->{$signal_name} = {};
1073             }
1074 103         1523 my $watcher = $signals->{$signal_name}->{$session} = [ $session, $event ];
1075              
1076             # weaken( $watcher->[0] );
1077              
1078 103 100 66     525 if ($signal_name eq 'CHLD' or $signal_name eq 'CLD') {
    50          
1079 101         505 $self->_install_chld_handler;
1080             }
1081             elsif (exists( $SIG{$signal_name} )) {
1082 0         0 $self->_install_sig_handler( $signal_name );
1083             }
1084             }
1085             else {
1086 3         16 DEBUG "[SIGNAL] Session: $session Signal: $signal_name\n" if DEBUGGING;
1087 3 50       13 if (exists( $signals->{$signal_name} )) {
1088 3         15 delete $signals->{$signal_name}->{$session};
1089             }
1090 3 100       48 unless( keys %{$signals->{$signal_name}} ) {
  3         30  
1091 2         7 delete $signals->{$signal_name};
1092 2 100       26 $SIG{$signal_name} = "DEFAULT" if exists $SIG{$signal_name};
1093             }
1094             }
1095             }
1096              
1097             sub signal {
1098 101     101 1 186 my $self = shift;
1099 101         230 my $session = shift;
1100 101         189 my $signal = $_[0];
1101 101         444 my @args = @_;
1102            
1103 101         241 my $queue = $self->[KR_QUEUE];
1104 101         964 @$queue = sort { $a <=> $b } (
  678         14544  
1105             @$queue,
1106             POE::Event::Signal->new(
1107             $self,
1108             time(),
1109             CURRENT_SESSION,
1110             $session,
1111             $signal,
1112             \@args,
1113             )
1114             );
1115             }
1116              
1117             sub signal_ui_destroy {
1118 0     0 1 0 die( "Not implemented at this time\n" );
1119             }
1120              
1121 110     110   1136 use POSIX ":sys_wait_h";
  110         327  
  110         1636  
1122              
1123             sub _install_chld_handler {
1124 167     167   421 DEBUG "Installing CHLD Handler\n" if DEBUGGING;
1125 167         346 my $kernel = shift;
1126            
1127             $SIG{CHLD} = sub {
1128             # Since this could happen between any two perl opcodes we should localize the error variable... waitpid plays with it.
1129 66     66   62995 local $!;
1130 66         55983 DEBUG( "Got CHLD SIGNAL\n" ) if DEBUGGING;
1131 66         139 my $child;
1132 66         82960 while (($child = waitpid( -1, WNOHANG)) > 0) {
1133 100         374 my $status = $?;
1134 100         477 my $watchers = $kernel->[KR_SIGNALS]->{CHLD};
1135 100         147 DEBUG( "Reaped pid $child with result $status\n" ) if DEBUGGING;
1136 100         633 while (my ($session, $watcher) = each %$watchers) {
1137 100         296 DEBUG( " Dispatching 'CHLD' to $watcher->[0]\n" ) if DEBUGGING;
1138 100         36855 $kernel->signal( $watcher->[0], 'CHLD', $child, $status );
1139             }
1140             }
1141 66         129 DEBUG( "waitpid( -1, WNOHANG ) ended with status $child ($!)\n" ) if DEBUGGING;
1142 66         77841 $kernel->_install_chld_handler; # This line could be keeping the kernel alive wrongly, not sure.
1143 167         225966 };
1144             }
1145              
1146             sub _install_sig_handler {
1147 0     0   0 my $kernel = shift;
1148 0         0 my $signal_name = shift;
1149 0         0 my @args = @_;
1150              
1151             $SIG{$signal_name} = sub {
1152 0     0   0 my $watchers = $kernel->[KR_SIGNALS]->{$signal_name};
1153 0         0 while (my ($session, $watcher) = each %$watchers) {
1154 0         0 $kernel->signal( $watcher->[0], $signal_name, @args );
1155             }
1156 0         0 $kernel->_install_sig_handler( $signal_name );
1157             }
1158 0         0 }
1159              
1160             sub _data_sig_get_safe_signals {
1161 0     0   0 return keys %SIG;
1162             }
1163              
1164             sub sig_handled {
1165 102     102 1 369490 POE::Event::Signal::HANDLED(1);
1166             }
1167              
1168             sub DESTROY {
1169 40     40   20881 DEBUG "Kernel Destruction!\n" if DEBUGGING;
1170             }
1171              
1172 234     234   1001 sub _invoke_state {
1173              
1174             }
1175              
1176             sub initialize_kernel {
1177 150     150 0 660 $poe_kernel = __PACKAGE__->new();
1178 150         810 weaken( $poe_kernel->[KR_IDS]->{$poe_kernel->ID} = $poe_kernel );
1179 150         454 $poe_kernel->[KR_SESSIONS]->{$poe_kernel} = $poe_kernel->ID;
1180             }
1181              
1182             initialize_kernel();
1183             POE::Callstack::PUSH( $poe_kernel );
1184              
1185             1;