File Coverage

blib/lib/POE/Kernel.pm
Criterion Covered Total %
statement 694 773 89.7
branch 243 290 83.7
condition 61 96 63.5
subroutine 101 112 90.1
pod 49 49 100.0
total 1148 1320 86.9


line stmt bran cond sub pod time code
1             package POE::Kernel;
2              
3 177     177   98127 use strict;
  177         273  
  177         8587  
4              
5 177     177   1928 use vars qw($VERSION);
  177         272  
  177         10650  
6             $VERSION = '1.367'; # NOTE - Should be #.### (three decimal places)
7              
8 177     177   4848 use POE::Resource::Clock qw( monotime sleep mono2wall wall2mono walltime time );
  177         368  
  177         12685  
9              
10 177     177   999 use POSIX qw(uname);
  177         298  
  177         1502  
11 177     177   52154 use Errno qw(ESRCH EINTR ECHILD EPERM EINVAL EEXIST EAGAIN EWOULDBLOCK);
  177         333  
  177         12950  
12 177     177   956 use Carp qw(carp croak confess cluck);
  177         247  
  177         11108  
13 177     177   150154 use Sys::Hostname qw(hostname);
  177         191743  
  177         11702  
14 177     177   1175 use IO::Handle ();
  177         369  
  177         2631  
15 177     177   726 use File::Spec ();
  177         272  
  177         3387  
16             #use Time::HiRes qw(time sleep);
17              
18             # People expect these to be lexical.
19              
20 177     177   695 use vars qw($poe_kernel $poe_main_window);
  177         243  
  177         21711  
21              
22             #------------------------------------------------------------------------------
23             # A cheezy exporter to avoid using Exporter.
24              
25             my $queue_class;
26              
27             BEGIN {
28 177     177   357 eval {
29 177         42535 require POE::XS::Queue::Array;
30 0         0 POE::XS::Queue::Array->import();
31 0         0 $queue_class = "POE::XS::Queue::Array";
32             };
33 177 50       1146 unless ($queue_class) {
34 177         128075 require POE::Queue::Array;
35 177         1226 POE::Queue::Array->import();
36 177         12313 $queue_class = "POE::Queue::Array";
37             }
38             }
39              
40             sub import {
41 507     507   4463 my ($class, $args) = ($poe_kernel, @_[1..$#_]);
42 507         1452 my $package = caller();
43              
44 507 100 100     2912 croak "POE::Kernel expects its arguments in a hash ref"
45             if ($args && ref($args) ne 'HASH');
46              
47             {
48 177     177   1205 no strict 'refs';
  177         248  
  177         46419  
  506         754  
49 506         1001 *{ $package . '::poe_kernel' } = \$poe_kernel;
  506         17732  
50 506         1099 *{ $package . '::poe_main_window' } = \$poe_main_window;
  506         2087  
51             }
52              
53             # Extract the import arguments we're interested in here.
54              
55 506   100     4634 my $loop = delete $args->{loop} || $ENV{POE_EVENT_LOOP};
56              
57             # Don't accept unknown/mistyped arguments.
58              
59 506         2640 my @unknown = sort keys %$args;
60 506 100       1897 croak "Unknown POE::Kernel import arguments: @unknown" if @unknown;
61              
62             # Now do things with them.
63              
64 505 100       117828 unless (UNIVERSAL::can('POE::Kernel', 'poe_kernel_loop')) {
65 177 100       806 if (defined $loop) {
66 6         41 $loop =~ s/^(POE::)?(XS::)?(Loop::)?//;
67 6 50       37 if (defined $2) {
68 0         0 $loop = "POE::XS::Loop::$loop";
69             }
70             else {
71 6         18 $loop = "POE::Loop::$loop";
72             }
73             }
74 177         773 _test_loop($loop);
75             # Bootstrap the kernel. This is inherited from a time when multiple
76             # kernels could be present in the same Perl process.
77 175 50       2326 POE::Kernel->new() if UNIVERSAL::can('POE::Kernel', 'poe_kernel_loop');
78             }
79             }
80              
81             #------------------------------------------------------------------------------
82             # Perform some optional setup.
83              
84             BEGIN {
85 177     177   1079 local $SIG{'__DIE__'} = 'DEFAULT';
86              
87             {
88 177     177   1012 no strict 'refs';
  177         281  
  177         25218  
  177         488  
89 177 50       956 if ($^O eq 'MSWin32') {
90 0         0 *{ __PACKAGE__ . '::RUNNING_IN_HELL' } = sub { 1 };
  0         0  
  0         0  
91             } else {
92 177     3151   4381 *{ __PACKAGE__ . '::RUNNING_IN_HELL' } = sub { 0 };
  177         10847  
  3151         19920  
93             }
94             }
95             }
96              
97             BEGIN {
98             # The entire BEGIN block is a no-strict-refs zone.
99              
100 177     177   1036 no strict 'refs';
  177         281  
  177         52475  
101              
102             # Set up a constant that lets the user deactivate automatic
103             # exception handling.
104              
105 177 100   177   888 unless (defined &CATCH_EXCEPTIONS) {
106 169 100       768 my $catch_exceptions = (
107             (exists $ENV{POE_CATCH_EXCEPTIONS})
108             ? $ENV{POE_CATCH_EXCEPTIONS}
109             : 1
110             );
111              
112 169 100       444 if ($catch_exceptions) {
113 168         568 *CATCH_EXCEPTIONS = sub () { 1 };
114             }
115             else {
116 1         3 *CATCH_EXCEPTIONS = sub () { 0 };
117             }
118             }
119              
120 177 50       809 unless (defined &CHILD_POLLING_INTERVAL) {
121             # That's one second, not a true value.
122 177         304 *CHILD_POLLING_INTERVAL = sub () { 1 };
123             }
124              
125 177 100       498 unless (defined &USE_SIGCHLD) {
126             # Perl >= 5.7.3 has safe signals support
127             # perlipc.pod#Deferred_Signals_(Safe_Signals)
128             # We decided to target 5.8.1 just to be safe :)
129 161 50 33     1176 if ( $] >= 5.008001 and not RUNNING_IN_HELL ) {
130 161         334 *USE_SIGCHLD = sub () { 1 };
131             } else {
132 0         0 *USE_SIGCHLD = sub () { 0 };
133             }
134             }
135              
136 177 100       702 unless (defined &USE_SIGNAL_PIPE) {
137 174         339 my $use_signal_pipe;
138 174 50       800 if ( exists $ENV{POE_USE_SIGNAL_PIPE} ) {
139 0         0 $use_signal_pipe = $ENV{POE_USE_SIGNAL_PIPE};
140             }
141              
142 174 50       477 if (RUNNING_IN_HELL) {
143 0 0       0 if ($use_signal_pipe) {
144 0         0 _warn(
145             "Sorry, disabling USE_SIGNAL_PIPE on $^O.\n",
146             "Programs are reported to hang when it's enabled.\n",
147             );
148             }
149              
150             # Must be defined to supersede the default.
151 0         0 $use_signal_pipe = 0;
152             }
153              
154 174 50 33     978 if ($use_signal_pipe or not defined $use_signal_pipe) {
155 174         6994 *USE_SIGNAL_PIPE = sub () { 1 };
156             }
157             else {
158 0         0 *USE_SIGNAL_PIPE = sub () { 0 };
159             }
160             }
161             }
162              
163             #==============================================================================
164             # Globals, or at least package-scoped things. Data structures were
165             # moved into lexicals in 0.1201.
166              
167             # A reference to the currently active session. Used throughout the
168             # functions that act on the current session.
169             my $kr_active_session;
170             my $kr_active_event;
171             my $kr_active_event_type;
172              
173             # Needs to be lexical so that POE::Resource::Events can see it
174             # change. TODO - Something better? Maybe we call a method in
175             # POE::Resource::Events to trigger the exception there?
176 177     177   11913 use vars qw($kr_exception);
  177         303  
  177         168007  
177              
178             # The Kernel's master queue.
179             my $kr_queue;
180              
181             # The current PID, to detect when it changes
182             my $kr_pid;
183              
184             # Filehandle activity modes. They are often used as list indexes.
185             sub MODE_RD () { 0 } # read
186             sub MODE_WR () { 1 } # write
187             sub MODE_EX () { 2 } # exception/expedite
188              
189             #------------------------------------------------------------------------------
190             # Kernel structure. This is the root of a large data tree. Dumping
191             # $poe_kernel with Data::Dumper or something will show most of the
192             # data that POE keeps track of. The exceptions to this are private
193             # storage in some of the leaf objects, such as POE::Wheel. All its
194             # members are described in detail further on.
195              
196             my $kr_id_seq = 0;
197              
198             sub KR_SESSIONS () { 0 } # [ \%kr_sessions,
199             sub KR_FILENOS () { 1 } # \%kr_filenos,
200             sub KR_SIGNALS () { 2 } # \%kr_signals,
201             sub KR_ALIASES () { 3 } # \%kr_aliases,
202             sub KR_ACTIVE_SESSION () { 4 } # \$kr_active_session,
203             sub KR_QUEUE () { 5 } # \$kr_queue,
204             sub KR_ID () { 6 } # $unique_kernel_id,
205             sub KR_SESSION_IDS () { 7 } # \%kr_session_ids,
206             sub KR_SID_SEQ () { 8 } # \$kr_sid_seq,
207             sub KR_EXTRA_REFS () { 9 } # \$kr_extra_refs,
208             sub KR_SIZE () { 10 } # XXX UNUSED ???
209             sub KR_RUN () { 11 } # \$kr_run_warning
210             sub KR_ACTIVE_EVENT () { 12 } # \$kr_active_event
211             sub KR_PIDS () { 13 } # \%kr_pids_to_events
212             sub KR_ACTIVE_EVENT_TYPE () { 14 } # \$kr_active_event_type
213             # ]
214              
215             # This flag indicates that POE::Kernel's run() method was called.
216             # It's used to warn about forgetting $poe_kernel->run().
217              
218             sub KR_RUN_CALLED () { 0x01 } # $kernel->run() called
219             sub KR_RUN_SESSION () { 0x02 } # sessions created
220             sub KR_RUN_DONE () { 0x04 } # run returned
221             my $kr_run_warning = 0;
222              
223             #------------------------------------------------------------------------------
224             # Events themselves.
225              
226             sub EV_SESSION () { 0 } # [ $destination_session,
227             sub EV_SOURCE () { 1 } # $sender_session,
228             sub EV_NAME () { 2 } # $event_name,
229             sub EV_TYPE () { 3 } # $event_type,
230             sub EV_ARGS () { 4 } # \@event_parameters_arg0_etc,
231             #
232             # (These fields go towards the end
233             # because they are optional in some
234             # cases. TODO: Is this still true?)
235             #
236             sub EV_OWNER_FILE () { 5 } # $caller_filename_where_enqueued,
237             sub EV_OWNER_LINE () { 6 } # $caller_line_where_enqueued,
238             sub EV_FROMSTATE () { 7 } # $fromstate
239             sub EV_SEQ () { 8 } # Maintained by POE::Queue (unique event ID)
240             sub EV_WALLTIME () { 9 } # Walltime when event was created (for alarms)
241             sub EV_DELTA () { 10 } # Seconds past walltime for event (for alarms)
242             # ]
243              
244             # These are the names of POE's internal events. They're in constants
245             # so we don't mistype them again.
246              
247             sub EN_CHILD () { '_child' }
248             sub EN_GC () { '_garbage_collect' }
249             sub EN_PARENT () { '_parent' }
250             sub EN_SCPOLL () { '_sigchld_poll' }
251             sub EN_SIGNAL () { '_signal' }
252             sub EN_START () { '_start' }
253             sub EN_STOP () { '_stop' }
254              
255             # These are POE's event classes (types). They often shadow the event
256             # names themselves, but they can encompass a large group of events.
257             # For example, ET_ALARM describes anything enqueued as by an alarm
258             # call. Types are preferred over names because bitmask tests are
259             # faster than string equality tests.
260              
261             sub ET_POST () { 0x0001 } # User events (posted, yielded).
262             sub ET_CALL () { 0x0002 } # User events that weren't enqueued.
263             sub ET_START () { 0x0004 } # _start
264             sub ET_STOP () { 0x0008 } # _stop
265             sub ET_SIGNAL () { 0x0010 } # _signal
266             sub ET_GC () { 0x0020 } # _garbage_collect
267             sub ET_PARENT () { 0x0040 } # _parent
268             sub ET_CHILD () { 0x0080 } # _child
269             sub ET_SCPOLL () { 0x0100 } # _sigchild_poll
270             sub ET_ALARM () { 0x0200 } # Alarm events.
271             sub ET_SELECT () { 0x0400 } # File activity events.
272             sub ET_SIGCLD () { 0x0800 } # sig_child() events.
273             sub ET_SIGDIE () { 0x1000 } # SIGDIE exception events.
274              
275             # A mask for all events generated by/for users.
276             sub ET_MASK_USER () { ~(ET_GC | ET_SCPOLL) }
277              
278             # A mask for all events that are delayed by a dispatch time.
279             sub ET_MASK_DELAYED () { ET_ALARM | ET_SCPOLL }
280              
281             # Temporary signal subtypes, used during signal dispatch semantics
282             # deprecation and reformation.
283              
284             sub ET_SIGNAL_RECURSIVE () { 0x2000 } # Explicitly requested signal.
285              
286             # A hash of reserved names. It's used to test whether someone is
287             # trying to use an internal event directly.
288              
289             my %poes_own_events = (
290             +EN_CHILD => 1,
291             +EN_GC => 1,
292             +EN_PARENT => 1,
293             +EN_SCPOLL => 1,
294             +EN_SIGNAL => 1,
295             +EN_START => 1,
296             +EN_STOP => 1,
297             +EN_STAT => 1,
298             );
299              
300             # These are ways a child may come or go.
301             # TODO - It would be useful to split 'lose' into two types. One to
302             # indicate that the child has stopped, and one to indicate that it was
303             # given away.
304              
305             sub CHILD_GAIN () { 'gain' } # The session was inherited from another.
306             sub CHILD_LOSE () { 'lose' } # The session is no longer this one's child.
307             sub CHILD_CREATE () { 'create' } # The session was created as a child of this.
308              
309             # Argument offsets for different types of internally generated events.
310             # TODO Exporting (EXPORT_OK) these would let people stop depending on
311             # positions for them.
312              
313             sub EA_SEL_HANDLE () { 0 }
314             sub EA_SEL_MODE () { 1 }
315             sub EA_SEL_ARGS () { 2 }
316              
317             #------------------------------------------------------------------------------
318             # Debugging and configuration constants.
319              
320             # Shorthand for defining a trace constant.
321             sub _define_trace {
322 177     177   1137 no strict 'refs';
  177         272  
  177         23647  
323 177     177   437 foreach my $name (@_) {
324 1416 50       1201 next if defined *{"TRACE_$name"}{CODE};
  1416         5707  
325 1416         2644 my $trace_value = &TRACE_DEFAULT;
326 1416         1554 my $trace_name = "TRACE_$name";
327 1416     0   7697 *$trace_name = sub () { $trace_value };
  0         0  
328             }
329             }
330              
331             # Debugging flags for subsystems. They're done as double evals here
332             # so that someone may define them before using POE::Kernel (or POE),
333             # and the pre-defined value will take precedence over the defaults
334             # here.
335              
336             my $trace_file_handle;
337              
338             BEGIN {
339             # Shorthand for defining an assert constant.
340             sub _define_assert {
341 177     177   852 no strict 'refs';
  177         279  
  177         44133  
342 177     177   371 foreach my $name (@_) {
343 885 100       837 next if defined *{"ASSERT_$name"}{CODE};
  885         4397  
344 882         1292 my $assert_value = &ASSERT_DEFAULT;
345 882         1088 my $assert_name = "ASSERT_$name";
346 882     0   264512 *$assert_name = sub () { $assert_value };
  0         0  
347             }
348             }
349              
350             # Assimilate POE_TRACE_* and POE_ASSERT_* environment variables.
351             # Environment variables override everything else.
352 177     177   1441 while (my ($var, $val) = each %ENV) {
353 3905 100       12327 next unless $var =~ /^POE_([A-Z_]+)$/;
354              
355 11         34 my $const = $1;
356              
357 177 100 33 177   957 next unless $const =~ /^(?:TRACE|ASSERT)_/ or do { no strict 'refs'; defined &$const };
  177         300  
  177         173211  
  11         50  
  11         101  
358              
359             # Copy so we don't hurt our environment.
360 1         1 my $value = $val;
361 1         5 ($value) = ($value =~ /^([-\@\w.]+)$/); # Untaint per rt.cpan.org 81550
362 1         2 $value =~ tr['"][]d;
363 1 50       6 $value = 0 + $value if $value =~ /^\s*-?\d+(?:\.\d+)?\s*$/;
364              
365 177     177   4253 no strict 'refs';
  177         313  
  177         30205  
366 1         4 local $^W = 0;
367 1         5 local $SIG{__WARN__} = sub { }; # redefine
  0         0  
368 1         15 *$const = sub () { $value };
  0         0  
369             }
370              
371             # TRACE_FILENAME is special.
372             {
373 177     177   1001 no strict 'refs';
  177         285  
  177         34195  
  177         350  
374 177 50       571 my $trace_filename = TRACE_FILENAME() if defined &TRACE_FILENAME;
375 177 50       617 if (defined $trace_filename) {
376 0 0       0 open $trace_file_handle, ">$trace_filename"
377             or die "can't open trace file `$trace_filename': $!";
378 0         0 CORE::select((CORE::select($trace_file_handle), $| = 1)[0]);
379             }
380             }
381             # TRACE_DEFAULT changes the default value for other TRACE_*
382             # constants. Since define_trace() uses TRACE_DEFAULT internally, it
383             # can't be used to define TRACE_DEFAULT itself.
384              
385 177 100       840 defined &TRACE_DEFAULT or *TRACE_DEFAULT = sub () { 0 };
386              
387 177         593 _define_trace qw(
388             EVENTS FILES PROFILE REFCNT RETVALS SESSIONS SIGNALS STATISTICS
389             );
390              
391             # See the notes for TRACE_DEFAULT, except read ASSERT and assert
392             # where you see TRACE and trace.
393              
394 177 100       932 defined &ASSERT_DEFAULT or *ASSERT_DEFAULT = sub () { 0 };
395              
396 177         581 _define_assert qw(DATA EVENTS FILES RETVALS USAGE);
397             }
398              
399             # An "idle" POE::Kernel may still have events enqueued. These events
400             # regulate polling for signals, profiling, and perhaps other aspects of
401             # POE::Kernel's internal workings.
402             #
403             # XXX - There must be a better mechanism.
404             #
405             my $idle_queue_size;
406              
407 3     3   11 sub _idle_queue_grow { $idle_queue_size++; }
408 2     2   6 sub _idle_queue_shrink { $idle_queue_size--; }
409 5     5   35 sub _idle_queue_size { $idle_queue_size; }
410 173     173   446 sub _idle_queue_reset { $idle_queue_size = 0; }
411              
412             #------------------------------------------------------------------------------
413             # Helpers to carp, croak, confess, cluck, warn and die with whatever
414             # trace file we're using today. _trap is reserved for internal
415             # errors.
416              
417             sub _trap {
418 24     24   512 local $Carp::CarpLevel = $Carp::CarpLevel + 1;
419 24   33     118 local *STDERR = $trace_file_handle || *STDERR;
420              
421 24         3172 confess(
422             "=== $$ === Please address any warnings or errors above this message,\n",
423             "=== $$ === and try again. If there are no previous messages, or they\n",
424             "=== $$ === are from within POE, then please mail them along with the\n",
425             "=== $$ === following information to bug-POE\@rt.cpan.org:\n",
426             "---\n@_\n-----\n"
427             );
428             }
429              
430             sub _croak {
431 1     1   732 local $Carp::CarpLevel = $Carp::CarpLevel + 1;
432 1   33     8 local *STDERR = $trace_file_handle || *STDERR;
433 1         5 my $message = join("", @_);
434 1         13 $message =~ s/^/=== $$ === /mg;
435 1         7 croak $message;
436             }
437              
438             sub _confess {
439 101     101   1164 local $Carp::CarpLevel = $Carp::CarpLevel + 1;
440 101   33     463 local *STDERR = $trace_file_handle || *STDERR;
441 101         237 my $message = join("", @_);
442 101         893 $message =~ s/^/=== $$ === /mg;
443 101         13530 confess $message;
444             }
445              
446             sub _cluck {
447 4977     4977   11087 local $Carp::CarpLevel = $Carp::CarpLevel + 1;
448 4977   33     22653 local *STDERR = $trace_file_handle || *STDERR;
449 4977         11693 my $message = join("", @_);
450 4977         39304 $message =~ s/^/=== $$ === /mg;
451 4977         763010 cluck $message;
452             }
453              
454             sub _carp {
455 4674     4674   10046 local $Carp::CarpLevel = $Carp::CarpLevel + 1;
456 4674   33     21751 local *STDERR = $trace_file_handle || *STDERR;
457 4674         12435 my $message = join("", @_);
458 4674         32984 $message =~ s/^/=== $$ === /mg;
459 4674         926238 carp $message;
460             }
461              
462             sub _warn {
463 54201     54201   187705 my ($package, $file, $line) = caller();
464 54201         138888 my $message = join("", @_);
465 54201 100       234701 $message .= " at $file line $line\n" unless $message =~ /\n$/;
466 54201         440914 $message =~ s/^/=== $$ === /mg;
467 54201         2244871 warn $message;
468             }
469              
470             sub _die {
471 1     1   375 my ($package, $file, $line) = caller();
472 1         4 my $message = join("", @_);
473 1 50       10 $message .= " at $file line $line\n" unless $message =~ /\n$/;
474 1         11 $message =~ s/^/=== $$ === /mg;
475 1   33     9 local *STDERR = $trace_file_handle || *STDERR;
476 1         4 die $message;
477             }
478              
479             #------------------------------------------------------------------------------
480             # Adapt POE::Kernel's personality to whichever event loop is present.
481              
482             my @has_poe_loop;
483             sub _find_loop {
484 30907     30907   31952 my ($mod) = @_;
485              
486             # Turns O(M*N) into O(M+N). I've seen the old way take over 30
487             # seconds according to Devel::NYTProf, with egregiously long @INCs.
488 30907 100       46279 unless (@has_poe_loop) {
489 1875 100       60673 @has_poe_loop = (
490 171         643 grep { (-d "$_/POE/Loop") || (-d "$_/POE/XS/Loop") }
491             @INC
492             );
493             }
494              
495 30907         34882 foreach my $dir (@has_poe_loop) {
496 69489 100       1004008 return 1 if (-r "$dir/$mod");
497             }
498              
499 30857         86169 return 0;
500             }
501              
502             sub _load_loop {
503 177     177   467 my $loop = shift;
504              
505 177     8   1951 *poe_kernel_loop = sub { return "$loop" };
  8         7885  
506              
507             # Modules can die with "not really dying" if they've loaded
508             # something else. This exception prevents the rest of the
509             # originally used module from being parsed, so the module it's
510             # handed off to takes over.
511 177         18402 eval "require $loop";
512 177 100 66     2576 if ($@ and $@ !~ /not really dying/) {
513 2         52 die(
514             "*\n",
515             "* POE can't use $loop:\n",
516             "* $@\n",
517             "*\n",
518             );
519             }
520             }
521              
522             sub _test_loop {
523 177     177   475 my $used_first = shift;
524 177         998 local $SIG{__DIE__};
525              
526             # First see if someone wants to load a POE::Loop or XS version
527             # explicitly.
528 177 100       669 if (defined $used_first) {
529 6         17 _load_loop($used_first);
530 4         23 return;
531             }
532              
533 171         7976 foreach my $file (keys %INC) {
534 15393 50       34054 next if (substr ($file, -3) ne '.pm');
535 15393         87285 my @split_dirs = File::Spec->splitdir($file);
536              
537             # Create a module name by replacing the path separators with
538             # underscores and removing ".pm"
539 15393         29153 my $module = join("_", @split_dirs);
540 15393         15873 substr($module, -3) = "";
541              
542             # Skip the module name if it isn't legal.
543 15393 50       38440 next if $module =~ /[^\w\.]/;
544              
545             # Try for the XS version first. If it fails, try the plain
546             # version. If that fails, we're up a creek.
547 15393         33688 $module = "POE/XS/Loop/$module.pm";
548 15393 50       20146 unless (_find_loop($module)) {
549 15393         55115 $module =~ s|XS/||;
550 15393 100       37453 next unless (_find_loop($module));
551             }
552              
553 50 50 33     286 if (defined $used_first and $used_first ne $module) {
554 0         0 die(
555             "*\n",
556             "* POE can't use multiple event loops at once.\n",
557             "* You used $used_first and $module.\n",
558             "* Specify the loop you want as an argument to POE\n",
559             "* use POE qw(Loop::Select);\n",
560             "* or;\n",
561             "* use POE::Kernel { loop => 'Select' };\n",
562             "*\n",
563             );
564             }
565              
566 50         139 $used_first = $module;
567             }
568              
569             # No loop found. Default to our internal select() loop.
570 171 100       3356 unless (defined $used_first) {
571 121         348 $used_first = "POE/XS/Loop/Select.pm";
572 121 50       409 unless (_find_loop($used_first)) {
573 121         629 $used_first =~ s/XS\///;
574             }
575             }
576              
577 171         456 substr($used_first, -3) = "";
578 171         708 $used_first =~ s|/|::|g;
579 171         765 _load_loop($used_first);
580             }
581              
582             #------------------------------------------------------------------------------
583             # Include resource modules here. Later, when we have the option of XS
584             # versions, we'll adapt this to include them if they're available.
585              
586 177     177   104686 use POE::Resources;
  177         395  
  177         1677668  
587              
588             ###############################################################################
589             # Helpers.
590              
591             ### Resolve $whatever into a session reference, trying every method we
592             ### can until something succeeds.
593              
594             sub _resolve_session {
595 3940     3940   4730 my ($self, $whatever) = @_;
596 3940         3638 my $session;
597              
598             # Resolve against sessions.
599 3940         11542 $session = $self->_data_ses_resolve($whatever);
600 3940 100       10298 return $session if defined $session;
601              
602             # Resolve against IDs.
603 206         994 $session = $self->_data_sid_resolve($whatever);
604 206 100       592 return $session if defined $session;
605              
606             # Resolve against aliases.
607 123         616 $session = $self->_data_alias_resolve($whatever);
608 123 100       449 return $session if defined $session;
609              
610             # Resolve against the Kernel itself. Use "eq" instead of "==" here
611             # because $whatever is often a string.
612 6 50       28 return $whatever if $whatever eq $self;
613              
614             # We don't know what it is.
615 6         18 return undef;
616             }
617              
618             ### Test whether POE has become idle.
619              
620             sub _test_if_kernel_is_idle {
621 2769     2769   3884 my $self = shift;
622              
623 2769         3320 if (TRACE_REFCNT) {
624             _warn(
625             " ,----- Kernel Activity -----\n",
626             " | Events : ", $kr_queue->get_item_count(),
627             " (vs. idle size = ", $idle_queue_size, ")\n",
628             " | Files : ", $self->_data_handle_count(), "\n",
629             " | Extra : ", $self->_data_extref_count(), "\n",
630             " | Procs : ", $self->_data_sig_kernel_awaits_pids(), "\n",
631             " | Sess : ", $self->_data_ses_count(), "\n",
632             " `---------------------------\n",
633             " ..."
634             );
635             }
636              
637 2769         6174 if( ASSERT_DATA ) {
638             if( $kr_pid != $$ ) {
639             _trap(
640             "New process detected. " .
641             "You must call ->has_forked() in the child process."
642             );
643             }
644             }
645              
646             # Not yet idle, or SO idle that there's nothing to receive the
647             # event. Try to order these from most to least likely to be true so
648             # that the tests short-circuit quickly.
649              
650             return if (
651 2769 50 100     12604 $kr_queue->get_item_count() > $idle_queue_size or
      100        
      100        
      66        
652             $self->_data_handle_count() or
653             $self->_data_extref_count() or
654             $self->_data_sig_kernel_awaits_pids() or
655             !$self->_data_ses_count()
656             );
657              
658 1206         5385 $self->_data_ev_enqueue(
659             $self, $self, EN_SIGNAL, ET_SIGNAL, [ 'IDLE' ],
660             __FILE__, __LINE__, undef
661             );
662             }
663              
664             ### Explain why a session could not be resolved.
665              
666             sub _explain_resolve_failure {
667 556     4   1853 my ($self, $whatever, $nonfatal) = @_;
668 1271         5521 local $Carp::CarpLevel = 2;
669              
670 87         789 if (ASSERT_DATA and !$nonfatal) {
671             _trap "
Cannot resolve ``$whatever'' into a session reference";
672             }
673              
674 4         19 $! = ESRCH;
675 0         0 TRACE_RETVALS and _carp " session not resolved: $!";
676 0         0 ASSERT_RETVALS and _carp " session not resolved: $!";
677             }
678              
679             ### Explain why a function is returning unsuccessfully.
680              
681             sub _explain_return {
682 15     15   18 my ($self, $message) = @_;
683 15         20 local $Carp::CarpLevel = 2;
684              
685 15         27 ASSERT_RETVALS and _confess " $message";
686 6         6 TRACE_RETVALS and _carp " $message";
687             }
688              
689             ### Explain how the user made a mistake calling a function.
690              
691             sub _explain_usage {
692 25     25   47 my ($self, $message) = @_;
693 25         44 local $Carp::CarpLevel = 2;
694              
695 25         59 ASSERT_USAGE and _confess " $message";
696 13         43 ASSERT_RETVALS and _confess " $message";
697 1         2 TRACE_RETVALS and _carp " $message";
698             }
699              
700             #==============================================================================
701             # SIGNALS
702             #==============================================================================
703              
704             #------------------------------------------------------------------------------
705             # Register or remove signals.
706              
707             # Public interface for adding or removing signal handlers.
708              
709             sub sig {
710 281     281 1 21977 my ($self, $signal, $event_name, @args) = ($poe_kernel, @_[1..$#_]);
711              
712 281         534 if (ASSERT_USAGE) {
713             _confess " must call sig() from a running session"
714             if $kr_active_session == $self;
715             _confess " undefined signal in sig()" unless defined $signal;
716             _carp(
717             " The '$event_name' event is one of POE's own. Its " .
718             "effect cannot be achieved assigning it to a signal"
719             ) if defined($event_name) and exists($poes_own_events{$event_name});
720             };
721              
722 281 100       1314 if (defined $event_name) {
723 279         891 $self->_data_sig_add($kr_active_session, $signal, $event_name, \@args);
724             }
725             else {
726 276         1791 $self->_data_sig_remove($kr_active_session->ID, $signal);
727             }
728             }
729              
730             # Public interface for posting signal events.
731             # TODO - Like post(), signal() should return
732              
733             sub signal {
734 296     21 1 2301 my ($self, $dest_session, $signal, @etc) = ($poe_kernel, @_[1..$#_]);
735              
736 176         894 if (ASSERT_USAGE) {
737             _confess " undefined destination in signal()"
738             unless defined $dest_session;
739             _confess " undefined signal in signal()" unless defined $signal;
740             };
741              
742 141         564 my $session = $self->_resolve_session($dest_session);
743 20 100       64 unless (defined $session) {
744 17         66 $self->_explain_resolve_failure($dest_session);
745 16         46 return;
746             }
747              
748             $self->_data_ev_enqueue(
749 2         13 $session, $kr_active_session,
750             EN_SIGNAL, ET_SIGNAL, [ $signal, @etc ],
751             (caller)[1,2], $kr_active_event
752             );
753 2         5 return 1;
754             }
755              
756             # Public interface for flagging signals as handled. This will replace
757             # the handlers' return values as an implicit flag. Returns undef so
758             # it may be used as the last function in an event handler.
759              
760             sub sig_handled {
761 140     124 1 2885 my $self = $poe_kernel;
762 140         684 $self->_data_sig_handled();
763              
764 124 100       487 if ($kr_active_event eq EN_SIGNAL) {
765 0         0 _die(
766             ",----- DEPRECATION ERROR -----\n",
767             "| ", $self->_data_alias_loggable($kr_active_session->ID), ":\n",
768             "| handled a _signal event. You must register a handler with sig().\n",
769             "`-----------------------------\n",
770             );
771             }
772             }
773              
774             # Attach a window or widget's destroy/closure to the UIDESTROY signal.
775              
776             sub signal_ui_destroy {
777 0     0 1 0 my ($self, $window) = @_;
778 0         0 $self->loop_attach_uidestroy($window);
779             }
780              
781             # Handle child PIDs being reaped. Added 2006-09-15.
782              
783             sub sig_child {
784 209     209 1 20905 my ($self, $pid, $event_name, @args) = ($poe_kernel, @_[1..$#_]);
785              
786 209         458 if (ASSERT_USAGE) {
787             _confess " must call sig_chld() from a running session"
788             if $kr_active_session == $self;
789             _confess " undefined process ID in sig_chld()" unless defined $pid;
790             _carp(
791             " The '$event_name' event is one of POE's own. Its " .
792             "effect cannot be achieved assigning it to a signal"
793             ) if defined($event_name) and exists($poes_own_events{$event_name});
794             };
795              
796 209 100       763 if (defined $event_name) {
    50          
797 209         1715 $self->_data_sig_pid_watch($kr_active_session, $pid, $event_name, \@args);
798             }
799             elsif ($self->_data_sig_pids_is_ses_watching($kr_active_session->ID, $pid)) {
800 111         1105 $self->_data_sig_pid_ignore($kr_active_session->ID, $pid);
801             }
802             }
803              
804             #==============================================================================
805             # KERNEL
806             #==============================================================================
807              
808             sub new {
809 286     175 1 686 my $type = shift;
810              
811             # Prevent multiple instances, no matter how many times it's called.
812             # This is a backward-compatibility enhancement for programs that
813             # have used versions prior to 0.06. It also provides a convenient
814             # single entry point into the entirety of POE's state: point a
815             # Dumper module at it, and you'll see a hideous tree of knowledge.
816             # Be careful, though. Its apples bite back.
817 285 100       2295 unless (defined $poe_kernel) {
818              
819             # Create our master queue.
820 175         1553 $kr_queue = $queue_class->new();
821              
822             # Remember the PID
823 175         1020 $kr_pid = $$;
824              
825             # TODO - Should KR_ACTIVE_SESSIONS and KR_ACTIVE_EVENT be handled
826             # by POE::Resource::Sessions?
827             # TODO - Should the subsystems be split off into separate real
828             # objects, such as KR_QUEUE is?
829              
830 175         1062 my $self = $poe_kernel = bless [
831             undef, # KR_SESSIONS - from POE::Resource::Sessions
832             undef, # KR_FILENOS - from POE::Resource::FileHandles
833             undef, # KR_SIGNALS - from POE::Resource::Signals
834             undef, # KR_ALIASES - from POE::Resource::Aliases
835             \$kr_active_session, # KR_ACTIVE_SESSION
836             $kr_queue, # KR_QUEUE - reference to an object
837             undef, # KR_ID
838             undef, # KR_SESSION_IDS - from POE::Resource::SIDS
839             undef, # KR_SID_SEQ - from POE::Resource::SIDS
840             undef, # KR_EXTRA_REFS
841             undef, # KR_SIZE
842             \$kr_run_warning, # KR_RUN
843             \$kr_active_event, # KR_ACTIVE_EVENT
844             undef, # KR_PIDS
845             \$kr_active_event_type, # KR_ACTIVE_EVENT_TYPE
846             ], $type;
847              
848 175         1289 POE::Resources->load();
849              
850 175         1060 $self->_recalc_id();
851 175         1239 $self->_data_sid_set($self->[KR_ID], $self);
852              
853             # Initialize subsystems. The order is important.
854              
855             # We need events before sessions, and the kernel's session before
856             # it can start polling for signals.
857 175         1065 $self->_data_ev_initialize($kr_queue);
858 175         1484 $self->_initialize_kernel_session();
859 174         738 $self->_data_sig_initialize();
860 173         958 $self->_data_alias_initialize();
861              
862             # These other subsystems don't have strange interactions.
863 173         785 $self->_data_handle_initialize($kr_queue);
864              
865 173         697 _idle_queue_reset();
866             }
867              
868             # Return the global instance.
869 173         4396 $poe_kernel;
870             }
871              
872             sub CLONE {
873 0     0   0 _data_ses_clone();
874             }
875              
876             #------------------------------------------------------------------------------
877             # Send an event to a session right now. Used by _disp_select to
878             # expedite select() events, and used by run() to deliver posted events
879             # from the queue.
880              
881             # Dispatch an event to its session. A lot of work goes on here.
882              
883 252     252   55271 sub _dummy_sigdie_handler { 1 }
884              
885             sub _dispatch_signal_event {
886             my (
887 482     482   1528 $self,
888             $session, $source_session, $event, $type, $etc,
889             $file, $line, $fromstate, $priority, $seq
890             ) = @_;
891              
892             # TODO - Regrettably, duplicate checking code in:
893             # _dispatch_signal_event(), _dispatch_event().
894              
895 482         779 if (ASSERT_EVENTS) {
896             _confess " undefined dest session" unless defined $session;
897             _confess " undefined source session" unless defined $source_session;
898             };
899              
900 482         1288 if (TRACE_EVENTS) {
901             my $log_session = $session;
902             $log_session = $self->_data_alias_loggable($session->ID) unless (
903             $type & ET_START
904             );
905             my $string_etc = join(" ", map { defined() ? $_ : "(undef)" } @$etc);
906             _warn(
907             " Dispatching event $seq ``$event'' ($string_etc) from ",
908             $self->_data_alias_loggable($source_session->ID), " to $log_session"
909             );
910             }
911              
912 482         1327 my $signal = $etc->[0];
913              
914 482         833 if (TRACE_SIGNALS) {
915             _warn(
916             " dispatching ET_SIGNAL ($signal) to ",
917             $self->_data_alias_loggable($session->ID)
918             );
919             }
920              
921             # Step 1a: Reset the handled-signal flags.
922              
923 482         1175 local @POE::Kernel::kr_signaled_sessions;
924 482         1555 local $POE::Kernel::kr_signal_total_handled;
925 482         1198 local $POE::Kernel::kr_signal_type;
926              
927 625         2193 $self->_data_sig_reset_handled($signal);
928              
929             # Step 1b: Collect a list of sessions to receive the signal.
930              
931 482         1585 my @touched_sessions = ($session);
932 482         3021 my $touched_index = 0;
933 482         1177 while ($touched_index < @touched_sessions) {
934 893         2869 my $next_target = $touched_sessions[$touched_index]->ID;
935 893         11071 push @touched_sessions, $self->_data_ses_get_children($next_target);
936 1047         5786 $touched_index++;
937             }
938              
939             # Step 1c: The DIE signal propagates up through parents, too.
940              
941 636 100       1586 if ($signal eq "DIE") {
942 524         2137 my $next_target = $self->_data_ses_get_parent($session->ID);
943 370   100     1126 while (defined($next_target) and $next_target != $self) {
944 202         348 unshift @touched_sessions, $next_target;
945 202         809 $next_target = $self->_data_ses_get_parent($next_target->ID);
946             }
947             }
948              
949             # Step 2: Propagate the signal to the explicit watchers in the
950             # child tree. Ensure the full tree is touched regardless
951             # whether there are explicit watchers.
952              
953 812 100       2613 if ($self->_data_sig_explicitly_watched($signal)) {
954 721         2080 my %signal_watchers = $self->_data_sig_watchers($signal);
955              
956 883         2402 $touched_index = @touched_sessions;
957 388         1575 while ($touched_index--) {
958 198         391 my $target_session = $touched_sessions[$touched_index];
959 198         701 $self->_data_sig_touched_session($target_session);
960              
961 355         652 my $target_sid = $target_session->ID;
962 355 100       1132 next unless exists $signal_watchers{$target_sid};
963 545         1783 my ($target_event, $target_etc) = @{$signal_watchers{$target_sid}};
  505         2291  
964              
965 352         611 if (TRACE_SIGNALS) {
966             _warn(
967             " propagating explicit signal $target_event ($signal) ",
968             "(@$target_etc) to ", $self->_data_alias_loggable($target_sid)
969             );
970             }
971              
972             # ET_SIGNAL_RECURSIVE is used here to avoid repropagating
973             # the signal ad nauseam.
974             $self->_dispatch_event(
975 352         2183 $target_session, $self,
976             $target_event, ET_SIGNAL_RECURSIVE | $type, [ @$etc, @$target_etc ],
977             $file, $line, $fromstate, monotime(), -__LINE__
978             );
979             }
980             }
981             else {
982 654         958 $touched_index = @touched_sessions;
983 654         2858 while ($touched_index--) {
984 891         1970 $self->_data_sig_touched_session($touched_sessions[$touched_index]);
985             }
986             }
987              
988             # Step 3: Check to see if the signal was handled.
989              
990 512         1908 $self->_data_sig_free_terminated_sessions();
991              
992             # If the signal was SIGDIE, then propagate the exception.
993              
994 286         669 my $handled_session_count = (_data_sig_handled_status())[0];
995 451 100 100     1765 if ($signal eq "DIE" and !$handled_session_count) {
996 338 100       901 $kr_exception = $etc->[1]{error_str} . (
997             (defined $kr_exception)
998             ? "Additional error thrown in handler for previous error:\n$kr_exception"
999             : ''
1000             );
1001             }
1002              
1003             # Signal completely dispatched. Thanks for flying!
1004 448         2274 return;
1005             }
1006              
1007             sub _dispatch_event {
1008             my (
1009 8313     8145   25838 $self,
1010             $session, $source_session, $event, $type, $etc,
1011             $file, $line, $fromstate, $priority, $seq
1012             ) = @_;
1013              
1014 8350         11023 if (ASSERT_EVENTS) {
1015             _confess " undefined dest session" unless defined $session;
1016             _confess " undefined source session" unless defined $source_session;
1017             };
1018              
1019 8188         16454 if (TRACE_EVENTS) {
1020             my $log_session = $session;
1021             $log_session = $self->_data_alias_loggable($session->ID) unless (
1022             $type & ET_START
1023             );
1024             my $string_etc = join(" ", map { defined() ? $_ : "(undef)" } @$etc);
1025             _warn(
1026             " Dispatching event $seq ``$event'' ($string_etc) from ",
1027             $self->_data_alias_loggable($source_session->ID), " to $log_session"
1028             );
1029             }
1030              
1031             ### Pre-dispatch processing.
1032              
1033             # Some sessions don't do anything in _start and expect their
1034             # creators to provide a start-up event. This means we can't
1035             # &_collect_garbage at _start time. Instead, an ET_GC event is
1036             # posted as part of session allocation. Simply dispatching it
1037             # will trigger a GC sweep.
1038              
1039 8449 100       19516 return 0 if $type & ET_GC;
1040              
1041             # Preprocess signals. This is where _signal is translated into
1042             # its registered handler's event name, if there is one.
1043              
1044 8224         9295 if (TRACE_EVENTS) {
1045             _warn(
1046             " dispatching event $seq ``$event'' to ",
1047             $self->_data_alias_loggable($session->ID)
1048             );
1049             if ($event eq EN_SIGNAL) {
1050             _warn(" signal($etc->[0])");
1051             }
1052             }
1053              
1054             # Prepare to call the appropriate handler. Push the current active
1055             # session on Perl's call stack.
1056              
1057 8221         14335 my ($hold_active_session, $hold_active_event, $hold_active_event_type) = (
1058             $kr_active_session, $kr_active_event, $kr_active_event_type
1059             );
1060             (
1061 8000         24453 $kr_active_session, $kr_active_event, $kr_active_event_type
1062             ) = ($session, $event, $type);
1063              
1064             # We only care about the return value and calling context if it's
1065             # ET_CALL.
1066              
1067 7787         14706 my $return;
1068 9274         23166 my $wantarray = wantarray();
1069              
1070 7787 100       22692 confess 'please report this stacktrace to bug-poe@rt.cpan.org' unless (
1071             defined $session
1072             );
1073              
1074             # Quiet SIGDIE if it's DEFAULT. If it's something special, then
1075             # someone had better know what they're doing.
1076             # 'DEFAULT', undef and '' are all the same.
1077              
1078 7787         31733 my $old_sig_die = $SIG{__DIE__};
1079 7501 100 66     25847 $SIG{__DIE__} = \&_dummy_sigdie_handler if (
      100        
1080             not defined $old_sig_die or $old_sig_die eq 'DEFAULT' or $old_sig_die eq ''
1081             );
1082              
1083 7470         25701 eval {
1084 7501 100       39924 if ($wantarray) {
    100          
1085 2039         4364 $return = [
1086             $session->_invoke_state(
1087             $source_session, $event, $etc, $file, $line, $fromstate
1088             )
1089             ];
1090             }
1091             elsif (defined $wantarray) {
1092 5978         13212 $return = $session->_invoke_state(
1093             $source_session, $event, $etc, $file, $line, $fromstate
1094             );
1095             }
1096             else {
1097 5358         14720 $session->_invoke_state(
1098             $source_session, $event, $etc, $file, $line, $fromstate
1099             );
1100             }
1101             };
1102              
1103             # An exception happened?
1104             # It was intially thrown under the $SIG{__DIE__} conditions that the
1105             # user wanted. Any formatting, logging, etc. is already done.
1106              
1107 6139 100 66     31210 if (ref($@) or $@ ne '') {
1108 5179         9632 if (CATCH_EXCEPTIONS) {
1109 5733         29588 if (TRACE_EVENTS) {
1110             _warn(
1111             " exception occurred in $event when invoked on ",
1112             $self->_data_alias_loggable($session->ID)
1113             );
1114             }
1115              
1116             # Exceptions in _stop are rethrown unconditionally.
1117             # We can't enqueue them--the session is about to go away.
1118             # Also if the active session has been forced back to $self via
1119             # POE::Kernel->stop().
1120 3861 100 66     10096 if ($type & (ET_STOP | ET_SIGDIE) or $kr_active_session eq $self) {
1121             # Propagate the exception up to the safe rethrow point.
1122 3843         33107 $kr_exception = $@;
1123             }
1124             else {
1125 3920         6552 $self->_data_ev_enqueue(
1126             $session, $self, EN_SIGNAL, ET_SIGDIE, [
1127             'DIE' => {
1128             source_session => $source_session,
1129             dest_session => $session,
1130             event => $event,
1131             file => $file,
1132             line => $line,
1133             from_state => $fromstate,
1134             error_str => $@,
1135             },
1136             ], __FILE__, __LINE__, undef
1137             );
1138             }
1139             }
1140             else {
1141             # Propagate the exception up to the safe rethrow point.
1142             $kr_exception = $@;
1143             }
1144             }
1145              
1146             # Global $sig{__DIE__} changed? For shame!
1147             # TODO - This warning is only needed if a SIGDIE handler is active.
1148             # TODO - Likewise, setting a SIGDIE with a __DIE__ handler in play
1149             # will be tricky or impossible. There should be some message.
1150              
1151 5542 100 100     22114 if (
      66        
1152             (not defined $old_sig_die or $old_sig_die eq 'DEFAULT') and
1153             $SIG{__DIE__} ne \&_dummy_sigdie_handler
1154             ) {
1155 32         126 _warn(
1156             " Event handler redefined global __DIE__ signal handler.\n",
1157             " This may conflict with CATCH_EXCEPTIONS handling.\n",
1158             " If global redefinition is necessary, do it in global code.\n",
1159             );
1160              
1161 2751         19633 $SIG{__DIE__} = $old_sig_die;
1162             }
1163              
1164             # Clear out the event arguments list, in case there are POE-ish
1165             # things in it. This allows them to destruct happily before we set
1166             # the current session back.
1167              
1168 4803         18940 @$etc = ( );
1169              
1170             # Stringify the handler's return value if it belongs in the POE
1171             # namespace. $return's scope exists beyond the post-dispatch
1172             # processing, which includes POE's garbage collection. The scope
1173             # bleed was known to break determinism in surprising ways.
1174              
1175 5502 100 100     290515 if (defined $return and substr(ref($return), 0, 5) eq 'POE::') {
1176 1907         3714 $return = "$return";
1177             }
1178              
1179             # Pop the active session and event, now that they're no longer
1180             # active.
1181              
1182 3601         9165 ($kr_active_session, $kr_active_event, $kr_active_event_type) = (
1183             $hold_active_session, $hold_active_event, $hold_active_event_type
1184             );
1185              
1186 1983         3161 if (TRACE_EVENTS) {
1187             my $string_ret = $return;
1188             $string_ret = "undef" unless defined $string_ret;
1189             _warn(" event $seq ``$event'' returns ($string_ret)\n");
1190             }
1191              
1192             # Return doesn't matter unless ET_CALL, ET_START or ET_STOP.
1193 3504 100       13481 return unless $type & (ET_CALL | ET_START | ET_STOP);
1194              
1195             # Return what the handler did. This is used for call().
1196 2024 100       3347 return( $wantarray ? @$return : $return );
1197             }
1198              
1199             #------------------------------------------------------------------------------
1200             # POE's main loop! Now with Tk and Event support!
1201              
1202             # Do pre-run start-up. Initialize the event loop, and allocate a
1203             # session structure to represent the Kernel.
1204              
1205             sub _initialize_kernel_session {
1206 2145     269   7412 my $self = shift;
1207              
1208 4606         29466 $self->loop_initialize();
1209              
1210 302         584 $kr_exception = undef;
1211 396         817 $kr_active_session = $self;
1212 4052         10507 $self->_data_ses_allocate($self, $self->[KR_ID], undef);
1213             }
1214              
1215             # Do post-run cleanup.
1216              
1217             sub _finalize_kernel {
1218 4008     190   12583 my $self = shift;
1219              
1220             # Disable signal watching since there's now no place for them to go.
1221 330         1608 foreach ($self->_data_sig_get_safe_signals()) {
1222 10278         22467 $self->loop_ignore_signal($_);
1223             }
1224              
1225             # Remove the kernel session's signal watcher.
1226 4008         6455 $self->_data_sig_remove($self->ID, "IDLE");
1227              
1228             # The main loop is done, no matter which event library ran it.
1229             # sig before loop so that it clears the signal_pipe file handler
1230 3932         6121 $self->_data_sig_finalize();
1231 3914         10366 $self->loop_finalize();
1232 3897         15396 $self->_data_extref_finalize();
1233 3880         32183 $self->_data_sid_finalize();
1234 1029         6132 $self->_data_alias_finalize();
1235 190         1349 $self->_data_handle_finalize();
1236 190         1614 $self->_data_ev_finalize();
1237 190         916 $self->_data_ses_finalize();
1238             }
1239              
1240             sub run_while {
1241 0     0 1 0 my ($self, $scalar_ref) = ($poe_kernel, @_[1..$#_]);
1242 0   0     0 1 while $$scalar_ref and $self->run_one_timeslice();
1243             }
1244              
1245             sub run_one_timeslice {
1246 0     0 1 0 my $self = $poe_kernel;
1247              
1248 0 100       0 unless ($self->_data_ses_count()) {
1249 0         0 $self->_finalize_kernel();
1250 0         0 $kr_run_warning |= KR_RUN_DONE;
1251 0 100       0 $kr_exception and $self->_rethrow_kr_exception();
1252 0         0 return;
1253             }
1254              
1255 0         0 $self->loop_do_timeslice();
1256 0 100       0 $kr_exception and $self->_rethrow_kr_exception();
1257              
1258 0         0 return 1;
1259             }
1260              
1261             sub run {
1262             # So run() can be called as a class method.
1263 201 100   201 1 11355 POE::Kernel->new unless defined $poe_kernel;
1264 201         440 my $self = $poe_kernel;
1265              
1266             # Flag that run() was called.
1267 201         955 $kr_run_warning |= KR_RUN_CALLED;
1268              
1269             # TODO is this check expensive? ( do people run() more than 1 time? )
1270 201 100       1643 if( $kr_pid != $$ ) {
1271 0         0 if ( ASSERT_USAGE ) {
1272             _warn "Detected a fork, automatically calling ->has_forked()";
1273             }
1274 0         0 $self->has_forked;
1275             }
1276              
1277             # Don't run the loop if we have no sessions.
1278             # Loop::Event will blow up, so we're doing this sanity check.
1279             # It may never trigger, however: See rt.cpan.org 101227.
1280 34 50       338 if ( $self->_data_ses_count() == 0 ) {
1281             # Emit noise only if we are under debug mode
1282 167         1431 if ( ASSERT_DATA ) {
1283             _warn("Not running the event loop because we have no sessions!\n");
1284             }
1285             } else {
1286             # All signals must be explicitly watched now. We do it here because
1287             # it's too early in initialize_kernel_session.
1288 33         228 $self->_data_sig_add($self, "IDLE", EN_SIGNAL);
1289              
1290             # Run the loop!
1291 35         254 $self->loop_run();
1292              
1293             # Cleanup
1294 190         1968 $self->_finalize_kernel();
1295             }
1296              
1297             # Clean up afterwards.
1298 190         1411 $kr_run_warning |= KR_RUN_DONE;
1299              
1300 190 100       1009 $kr_exception and $self->_rethrow_kr_exception();
1301             }
1302              
1303             sub _rethrow_kr_exception {
1304 179     11   439 my $self = shift;
1305              
1306             # It's quite common to see people wrap POE::Kernel->run() in an eval
1307             # block and start things again if an exception is caught.
1308             #
1309             # This little lexical dance is actually important. It allows
1310             # $kr_exception to be cleared if the die() is caught.
1311              
1312 177         1084 my $exception = $kr_exception;
1313 11         24 $kr_exception = undef;
1314              
1315             # The die is cast.
1316 11         80 die $exception;
1317             }
1318              
1319             # Stops the kernel cold. XXX Experimental!
1320             # No events happen as a result of this, all structures are cleaned up
1321             # except the kernel's. Even the current session and POE::Kernel are
1322             # cleaned up, which may introduce inconsistencies in the current
1323             # session... as _dispatch_event() attempts to clean up for a defunct
1324             # session.
1325              
1326             sub stop {
1327             # So stop() can be called as a class method.
1328 18     18 1 54 my $self = $poe_kernel;
1329              
1330             # May be called when the kernel's already stopped. Avoid problems
1331             # trying to find child sessions when the kernel isn't registered.
1332 18 100       67 if ($self->_data_ses_exists($self->ID)) {
1333 7         16 my @children = ($self);
1334 7         14 foreach my $session (@children) {
1335 19         44 push @children, $self->_data_ses_get_children($session->ID);
1336             }
1337              
1338             # Don't stop believin'. Nor the POE::Kernel singleton.
1339 7         15 shift @children;
1340              
1341             # Walk backwards to avoid inconsistency errors.
1342 7         15 foreach my $session (reverse @children) {
1343 12         45 $self->_data_ses_stop($session->ID);
1344             }
1345             }
1346              
1347             # Roll back whether sessions were started.
1348 18         91 $kr_run_warning &= ~KR_RUN_SESSION;
1349              
1350             # So new sessions will not be child of the current defunct session.
1351 18         51 $kr_active_session = $self;
1352              
1353             # The GC mark list may prevent sessions from DESTROYing.
1354             # Clean it up.
1355 18         80 $self->_data_ses_gc_sweep();
1356              
1357             # Running stop() is recommended in a POE::Wheel::Run coderef
1358             # Program, before setting up for the next POE::Kernel->run(). When
1359             # the PID has changed, imply _data_sig_has_forked() during stop().
1360              
1361 18 50       98 $poe_kernel->has_forked() if $kr_pid != $$;
1362              
1363             # TODO - If we're polling for signals, then the reset gets it wrong.
1364             # The reset doesn't count sigchld polling. If we must put this
1365             # back, it MUST account for all internal events currently in play,
1366             # or the child process will stall if it reruns POE::Kernel's loop.
1367             #_idle_queue_reset();
1368              
1369 18         82 return;
1370             }
1371              
1372             # Less invasive form of ->stop() + ->run()
1373             sub has_forked {
1374 4 50   4 1 4003 if( $kr_pid == $$ ) {
1375 0         0 if ( ASSERT_USAGE ) {
1376             _warn "You should only call ->has_forked() from the child process.";
1377             }
1378 0         0 return;
1379             }
1380              
1381             # So has_forked() can be called as a class method.
1382 0         0 my $self = $poe_kernel;
1383              
1384 4         67 $kr_pid = $$;
1385 4         64 $self->_recalc_id();
1386              
1387             # reset some stuff for the signals
1388 4         210 $poe_kernel->_data_sig_has_forked;
1389             }
1390              
1391             #------------------------------------------------------------------------------
1392              
1393             sub DESTROY {
1394 4     0   52 my $self = shift;
1395              
1396             # Warn that a session never had the opportunity to run if one was
1397             # created but run() was never called.
1398              
1399 0 0       0 unless ($kr_run_warning & KR_RUN_CALLED) {
1400 0 0       0 if ($kr_run_warning & KR_RUN_SESSION) {
1401 0         0 _warn(
1402             "Sessions were started, but POE::Kernel's run() method was never\n",
1403             "called to execute them. This usually happens because an error\n",
1404             "occurred before POE::Kernel->run() could be called. Please fix\n",
1405             "any errors above this notice, and be sure that POE::Kernel->run()\n",
1406             "is called. See documentation for POE::Kernel's run() method for\n",
1407             "another way to disable this warning.\n",
1408             );
1409             }
1410             }
1411             }
1412              
1413             #------------------------------------------------------------------------------
1414             # _invoke_state is what _dispatch_event calls to dispatch a transition
1415             # event. This is the kernel's _invoke_state so it can receive events.
1416             # These are mostly signals, which are propagated down in
1417             # _dispatch_event.
1418              
1419             sub _invoke_state {
1420 1606     1606   3094 my ($self, $source_session, $event, $etc) = @_;
1421              
1422             # This is an event loop to poll for child processes without needing
1423             # to catch SIGCHLD.
1424              
1425 1606 100       5748 if ($event eq EN_SCPOLL) {
    100          
1426 371         2715 $self->_data_sig_handle_poll_event($etc->[0]);
1427             }
1428              
1429             # A signal was posted. Because signals propagate depth-first, this
1430             # _invoke_state is called last in the dispatch. If the signal was
1431             # SIGIDLE, then post a SIGZOMBIE if the main queue is still idle.
1432              
1433             elsif ($event eq EN_SIGNAL) {
1434 190 50       870 if ($etc->[0] eq 'IDLE') {
1435 190 50 33     909 unless (
1436             $kr_queue->get_item_count() > $idle_queue_size or
1437             $self->_data_handle_count()
1438             ) {
1439 190         2518 $self->_data_ev_enqueue(
1440             $self, $self, EN_SIGNAL, ET_SIGNAL, [ 'ZOMBIE' ],
1441             __FILE__, __LINE__, undef
1442             );
1443             }
1444             }
1445             }
1446              
1447 1606         3629 return 0;
1448             }
1449              
1450             #==============================================================================
1451             # SESSIONS
1452             #==============================================================================
1453              
1454             # Dispatch _start to a session, allocating it in the kernel's data
1455             # structures as a side effect.
1456              
1457             sub session_alloc {
1458 799     799 1 3771 my ($self, $session, @args) = ($poe_kernel, @_[1..$#_]);
1459              
1460             # If we already returned, then we must reinitialize. This is so
1461             # $poe_kernel->run() will work correctly more than once.
1462 799 100       2688 if ($kr_run_warning & KR_RUN_DONE) {
1463 94         212 $kr_run_warning &= ~KR_RUN_DONE;
1464 94         562 $self->_initialize_kernel_session();
1465 94         497 $self->_data_sig_initialize();
1466             }
1467              
1468 799         1037 if (ASSERT_DATA) {
1469             if (defined $session->ID) {
1470             _trap(
1471             " ", $self->_data_alias_loggable($session->ID),
1472             " already allocated\a"
1473             );
1474             }
1475             }
1476              
1477             # Register that a session was created.
1478 799         2380 $kr_run_warning |= KR_RUN_SESSION;
1479              
1480             # Allocate the session's data structure. This must be done before
1481             # we dispatch anything regarding the new session.
1482 155         1252 my $new_sid = $self->_data_sid_allocate();
1483 798         2044 $session->_set_id($new_sid);
1484 798         3535 $self->_data_ses_allocate($session, $new_sid, $kr_active_session->ID);
1485              
1486 798         3414 my $loggable = $self->_data_alias_loggable($new_sid);
1487              
1488             # Tell the new session that it has been created. Catch the _start
1489             # state's return value so we can pass it to the parent with the
1490             # _child create.
1491             #
1492             # TODO - Void the context if the parent has no _child handler?
1493              
1494 798         3350 my $return = $self->_dispatch_event(
1495             $session, $kr_active_session,
1496             EN_START, ET_START, \@args,
1497             __FILE__, __LINE__, undef, monotime(), -__LINE__
1498             );
1499              
1500 784 100       4237 unless($self->_data_ses_exists($new_sid)) {
1501 644         5180 if(TRACE_SESSIONS) {
1502             _warn(" ", $loggable, " disappeared during ", EN_START);
1503             }
1504 595         3957 return $return;
1505             }
1506              
1507             # If the child has not detached itself---that is, if its parent is
1508             # the currently active session---then notify the parent with a
1509             # _child create event. Otherwise skip it, since we'd otherwise
1510             # throw a create without a lose.
1511             $self->_dispatch_event(
1512 126         525 $self->_data_ses_get_parent($session->ID), $self,
1513             EN_CHILD, ET_CHILD, [ CHILD_CREATE, $session, $return ],
1514             __FILE__, __LINE__, undef, monotime(), -__LINE__
1515             );
1516              
1517 140 50       639 unless ($self->_data_ses_exists($new_sid)) {
1518 249         786 if (TRACE_SESSIONS) {
1519             _warn(" ", $loggable, " disappeared during ", EN_CHILD, " dispatch");
1520             }
1521 595         2194 return $return;
1522             }
1523              
1524             # Enqueue a delayed garbage-collection event so the session has time
1525             # to do its thing before it goes.
1526             $self->_data_ev_enqueue(
1527 486         3133 $session, $session, EN_GC, ET_GC, [],
1528             __FILE__, __LINE__, undef
1529             );
1530             }
1531              
1532             # Detach a session from its parent. This breaks the parent/child
1533             # relationship between the current session and its parent. Basically,
1534             # the current session is given to the Kernel session. Unlike with
1535             # _stop, the current session's children follow their parent.
1536              
1537             sub detach_myself {
1538 11     11 1 1233 my $self = $poe_kernel;
1539              
1540 260         2320 if (ASSERT_USAGE) {
1541             _confess " must call detach_myself() from a running session"
1542             if $kr_active_session == $self;
1543             }
1544              
1545             # Can't detach from the kernel.
1546 11 100       56 if ($self->_data_ses_get_parent($kr_active_session->ID) == $self) {
1547 370         3515 $! = EPERM;
1548 0         0 return;
1549             }
1550              
1551 0         0 my $old_parent = $self->_data_ses_get_parent($kr_active_session->ID);
1552              
1553             # Tell the old parent session that the child is departing.
1554             # But not if the active event is ET_START, since that would generate
1555             # a CHILD_LOSE without a CHILD_CREATE.
1556 10 50       37 $self->_dispatch_event(
1557             $old_parent, $self,
1558             EN_CHILD, ET_CHILD, [ CHILD_LOSE, $kr_active_session, undef ],
1559             (caller)[1,2], undef, monotime(), -__LINE__
1560             )
1561             unless $kr_active_event_type & ET_START;
1562              
1563             # Tell the new parent (kernel) that it's gaining a child.
1564             # (Actually it doesn't care, so we don't do that here, but this is
1565             # where the code would go if it ever does in the future.)
1566              
1567             # Tell the current session that its parentage is changing.
1568 10         113 $self->_dispatch_event(
1569             $kr_active_session, $self,
1570             EN_PARENT, ET_PARENT, [ $old_parent, $self ],
1571             (caller)[1,2], undef, monotime(), -__LINE__
1572             );
1573              
1574 10         121 $self->_data_ses_move_child($kr_active_session->ID, $self->ID);
1575              
1576             # Success!
1577 10         62 return 1;
1578             }
1579              
1580             # Detach a child from this, the parent. The session being detached
1581             # must be a child of the current session.
1582              
1583             sub detach_child {
1584 20     10 1 3122 my ($self, $child) = ($poe_kernel, @_[1..$#_]);
1585              
1586 10         18 if (ASSERT_USAGE) {
1587             _confess " must call detach_child() from a running session"
1588             if $kr_active_session == $self;
1589             }
1590              
1591 10         47 my $child_session = $self->_resolve_session($child);
1592 9 100       29 unless (defined $child_session) {
1593 9         30 $self->_explain_resolve_failure($child);
1594 0         0 return;
1595             }
1596              
1597             # Can't detach if it belongs to the kernel. TODO We shouldn't need
1598             # to check for this.
1599 0 50       0 if ($kr_active_session == $self) {
1600 8         28 $! = EPERM;
1601 0         0 return;
1602             }
1603              
1604             # Can't detach if it's not a child of the current session.
1605 0 50       0 unless (
1606             $self->_data_ses_is_child($kr_active_session->ID, $child_session->ID)
1607             ) {
1608 8         39 $! = EPERM;
1609 0         0 return;
1610             }
1611              
1612             # Tell the current session that the child is departing.
1613             $self->_dispatch_event(
1614 0         0 $kr_active_session, $self,
1615             EN_CHILD, ET_CHILD, [ CHILD_LOSE, $child_session, undef ],
1616             (caller)[1,2], undef, monotime(), -__LINE__
1617             );
1618              
1619             # Tell the new parent (kernel) that it's gaining a child.
1620             # (Actually it doesn't care, so we don't do that here, but this is
1621             # where the code would go if it ever does in the future.)
1622              
1623             # Tell the child session that its parentage is changing.
1624 8         97 $self->_dispatch_event(
1625             $child_session, $self,
1626             EN_PARENT, ET_PARENT, [ $kr_active_session, $self ],
1627             (caller)[1,2], undef, monotime(), -__LINE__
1628             );
1629              
1630 8         122 $self->_data_ses_move_child($child_session->ID, $self->ID);
1631              
1632             # Success!
1633 8         49 return 1;
1634             }
1635              
1636             ### Helpful accessors.
1637              
1638             sub get_active_session {
1639 1027     1019 1 8309 return $kr_active_session;
1640             }
1641              
1642             sub get_active_event {
1643 0     0 1 0 return $kr_active_event;
1644             }
1645              
1646             # FIXME - Should this exist?
1647             sub get_event_count {
1648 0     0 1 0 return $kr_queue->get_item_count();
1649             }
1650              
1651             # FIXME - Should this exist?
1652             sub get_next_event_time {
1653 0     0 1 0 return $kr_queue->get_next_priority();
1654             }
1655              
1656             #==============================================================================
1657             # EVENTS
1658             #==============================================================================
1659              
1660             #------------------------------------------------------------------------------
1661             # Post an event to the queue.
1662              
1663             sub post {
1664 326     326 1 21285 my ($self, $dest_session, $event_name, @etc) = ($poe_kernel, @_[1..$#_]);
1665              
1666 326         489 if (ASSERT_USAGE) {
1667             _confess " destination is undefined in post()"
1668             unless defined $dest_session;
1669             _confess " event is undefined in post()" unless defined $event_name;
1670             _carp(
1671             " The '$event_name' event is one of POE's own. Its " .
1672             "effect cannot be achieved by posting it"
1673             ) if exists $poes_own_events{$event_name};
1674             };
1675              
1676             # Attempt to resolve the destination session reference against
1677             # various things.
1678              
1679 326         925 my $session = $self->_resolve_session($dest_session);
1680 325 100       772 unless (defined $session) {
1681 317         1041 $self->_explain_resolve_failure($dest_session);
1682 316         1128 return;
1683             }
1684              
1685             # Enqueue the event for "now", which simulates FIFO in our
1686             # time-ordered queue.
1687              
1688             $self->_data_ev_enqueue(
1689 323         836 $session, $kr_active_session, $event_name, ET_POST, \@etc,
1690             (caller)[1,2], $kr_active_event
1691             );
1692 7         22 return 1;
1693             }
1694              
1695             #------------------------------------------------------------------------------
1696             # Post an event to the queue for the current session.
1697              
1698             sub yield {
1699 752     752 1 4052793 my ($self, $event_name, @etc) = ($poe_kernel, @_[1..$#_]);
1700              
1701 1068         3829 if (ASSERT_USAGE) {
1702             _confess " must call yield() from a running session"
1703             if $kr_active_session == $self;
1704             _confess " event name is undefined in yield()"
1705             unless defined $event_name;
1706             _carp(
1707             " The '$event_name' event is one of POE's own. Its " .
1708             "effect cannot be achieved by yielding it"
1709             ) if exists $poes_own_events{$event_name};
1710             };
1711              
1712 1068         4077 $self->_data_ev_enqueue(
1713             $kr_active_session, $kr_active_session, $event_name, ET_POST, \@etc,
1714             (caller)[1,2], $kr_active_event
1715             );
1716              
1717 751         2198 undef;
1718             }
1719              
1720             #------------------------------------------------------------------------------
1721             # Call an event handler directly.
1722              
1723             sub call {
1724 4265     3572 1 33150 my ($self, $dest_session, $event_name, @etc) = ($poe_kernel, @_[1..$#_]);
1725              
1726 4265         9437 if (ASSERT_USAGE) {
1727             _confess " destination is undefined in call()"
1728             unless defined $dest_session;
1729             _confess " event is undefined in call()" unless defined $event_name;
1730             _carp(
1731             " The '$event_name' event is one of POE's own. Its " .
1732             "effect cannot be achieved by calling it"
1733             ) if exists $poes_own_events{$event_name};
1734             };
1735              
1736             # Attempt to resolve the destination session reference against
1737             # various things.
1738              
1739 4265         10436 my $session = $self->_resolve_session($dest_session);
1740 3571 100       6626 unless (defined $session) {
1741 1122         3020 $self->_explain_resolve_failure($dest_session);
1742 1121         2833 return;
1743             }
1744              
1745             # Dispatch the event right now, bypassing the queue altogether.
1746             # This tends to be a Bad Thing to Do.
1747              
1748             # TODO The difference between synchronous and asynchronous events
1749             # should be made more clear in the documentation, so that people
1750             # have a tendency not to abuse them. I discovered in xws that
1751             # mixing the two types makes it harder than necessary to write
1752             # deterministic programs, but the difficulty can be ameliorated if
1753             # programmers set some base rules and stick to them.
1754              
1755 3569 100       8823 if (wantarray) {
1756 2 100       12 my @return_value = (
1757             ($session == $kr_active_session)
1758             ? $session->_invoke_state(
1759             $session, $event_name, \@etc, (caller)[1,2],
1760             $kr_active_event
1761             )
1762             : $self->_dispatch_event(
1763             $session, $kr_active_session,
1764             $event_name, ET_CALL, \@etc,
1765             (caller)[1,2], $kr_active_event, monotime(), -__LINE__
1766             )
1767             );
1768              
1769 1 50       408 $kr_exception and $self->_rethrow_kr_exception();
1770              
1771 1122         2505 $! = 0;
1772 1         4 return @return_value;
1773             }
1774              
1775 2446 100       3916 if (defined wantarray) {
1776 2 50       15 my $return_value = (
1777             $session == $kr_active_session
1778             ? $session->_invoke_state(
1779             $session, $event_name, \@etc, (caller)[1,2],
1780             $kr_active_event
1781             )
1782             : $self->_dispatch_event(
1783             $session, $kr_active_session,
1784             $event_name, ET_CALL, \@etc,
1785             (caller)[1,2], $kr_active_event, monotime(), -__LINE__
1786             )
1787             );
1788              
1789 2 50       801 $kr_exception and $self->_rethrow_kr_exception();
1790              
1791 1123         2263 $! = 0;
1792 167         1267 return $return_value;
1793             }
1794              
1795 2609 100       6129 if ($session == $kr_active_session) {
1796 2600         10936 $session->_invoke_state(
1797             $session, $event_name, \@etc, (caller)[1,2],
1798             $kr_active_event
1799             );
1800             }
1801             else {
1802 174         577 $self->_dispatch_event(
1803             $session, $kr_active_session,
1804             $event_name, ET_CALL, \@etc,
1805             (caller)[1,2], $kr_active_event, monotime(), -__LINE__
1806             );
1807             }
1808              
1809 3389 50       27133 $kr_exception and $self->_rethrow_kr_exception();
1810              
1811 3323         9086 $! = 0;
1812 2499         9618 return;
1813             }
1814              
1815             #==============================================================================
1816             # DELAYED EVENTS
1817             #==============================================================================
1818              
1819             sub alarm {
1820 3659     2703 1 780611 my ($self, $event_name, $time, @etc) = ($poe_kernel, @_[1..$#_]);
1821              
1822 3659         5298 if (ASSERT_USAGE) {
1823             _confess " must call alarm() from a running session"
1824             if $kr_active_session == $self;
1825             _confess " event name is undefined in alarm()"
1826             unless defined $event_name;
1827             _carp(
1828             " The '$event_name' event is one of POE's own. Its " .
1829             "effect cannot be achieved by setting an alarm for it"
1830             ) if exists $poes_own_events{$event_name};
1831             };
1832              
1833 3659 100       13095 unless (defined $event_name) {
1834 2541         5988 $self->_explain_return("invalid parameter to alarm() call");
1835 2539         7534 return EINVAL;
1836             }
1837              
1838 2700         6353 $self->_data_ev_clear_alarm_by_name($kr_active_session->ID(), $event_name);
1839              
1840             # Add the new alarm if it includes a time. Calling _data_ev_enqueue
1841             # directly is faster than calling alarm_set to enqueue it.
1842 161 50       693 if (defined $time) {
1843 0         0 $self->_data_ev_enqueue
1844             ( $kr_active_session, $kr_active_session,
1845             $event_name, ET_ALARM, [ @etc ],
1846             (caller)[1,2], $kr_active_event, $time,
1847             );
1848             }
1849             else {
1850             # The event queue has become empty? Stop the time watcher.
1851 2700 100       6781 $self->loop_pause_time_watcher() unless $kr_queue->get_item_count();
1852             }
1853              
1854 2700         9826 return 0;
1855             }
1856              
1857             # Add an alarm without clobbering previous alarms of the same name.
1858             sub alarm_add {
1859 1258     16 1 11366 my ($self, $event_name, $time, @etc) = ($poe_kernel, @_[1..$#_]);
1860              
1861 1313         5579 if (ASSERT_USAGE) {
1862             _confess " must call alarm_add() from a running session"
1863             if $kr_active_session == $self;
1864             _confess " undefined event name in alarm_add()"
1865             unless defined $event_name;
1866             _confess " undefined time in alarm_add()" unless defined $time;
1867             _carp(
1868             " The '$event_name' event is one of POE's own. Its " .
1869             "effect cannot be achieved by adding an alarm for it"
1870             ) if exists $poes_own_events{$event_name};
1871             };
1872              
1873 2555 100 66     13606 unless (defined $event_name and defined $time) {
1874 15         35 $self->_explain_return("invalid parameter to alarm_add() call");
1875 13         27 return EINVAL;
1876             }
1877              
1878             $self->_data_ev_enqueue
1879 12         27 ( $kr_active_session, $kr_active_session,
1880             $event_name, ET_ALARM, [ @etc ],
1881             (caller)[1,2], $kr_active_event, $time,
1882             );
1883              
1884 12         55 return 0;
1885             }
1886              
1887             # Add a delay, which is like an alarm relative to the current time.
1888             sub delay {
1889 1121     1121 1 19212 my ($self, $event_name, $delay, @etc) = ($poe_kernel, @_[1..$#_]);
1890 1121         3442 my $pri = monotime();
1891              
1892 1133         1205 if (ASSERT_USAGE) {
1893             _confess " must call delay() from a running session"
1894             if $kr_active_session == $self;
1895             _confess " undefined event name in delay()" unless defined $event_name;
1896             _carp(
1897             " The '$event_name' event is one of POE's own. Its " .
1898             "effect cannot be achieved by setting a delay for it"
1899             ) if exists $poes_own_events{$event_name};
1900             };
1901              
1902 1133 100       3717 unless (defined $event_name) {
1903 287         731 $self->_explain_return("invalid parameter to delay() call");
1904 285         900 return EINVAL;
1905             }
1906              
1907 1118 100       2539 if (defined $delay) {
1908 672         2101 $self->_data_ev_clear_alarm_by_name($kr_active_session->ID(), $event_name);
1909              
1910             # Add the new alarm if it includes a time. Calling _data_ev_enqueue
1911             # directly is faster than calling alarm_set to enqueue it.
1912 672         7872 $self->_data_ev_enqueue
1913             ( $kr_active_session, $kr_active_session,
1914             $event_name, ET_ALARM, [ @etc ],
1915             (caller)[1,2], $kr_active_event, undef, $delay, $pri+$delay
1916             );
1917             }
1918             else {
1919 446         1234 $self->alarm($event_name);
1920             }
1921              
1922 1063         3247 return 0;
1923             }
1924              
1925             # Add a delay without clobbering previous delays of the same name.
1926             sub delay_add {
1927 240     10 1 4031 my ($self, $event_name, $delay, @etc) = ($poe_kernel, @_[1..$#_]);
1928 65         336 my $pri = monotime();
1929              
1930 295         1275 if (ASSERT_USAGE) {
1931             _confess " must call delay_add() from a running session"
1932             if $kr_active_session == $self;
1933             _confess " undefined event name in delay_add()"
1934             unless defined $event_name;
1935             _confess " undefined time in delay_add()" unless defined $delay;
1936             _carp(
1937             " The '$event_name' event is one of POE's own. Its " .
1938             "effect cannot be achieved by adding a delay for it"
1939             ) if exists $poes_own_events{$event_name};
1940             };
1941              
1942 10 100 66     44 unless (defined $event_name and defined $delay) {
1943 9         40 $self->_explain_return("invalid parameter to delay_add() call");
1944 7         24 return EINVAL;
1945             }
1946              
1947             $self->_data_ev_enqueue
1948 6         19 ( $kr_active_session, $kr_active_session,
1949             $event_name, ET_ALARM, [ @etc ],
1950             (caller)[1,2], $kr_active_event, undef, $delay, $pri+$delay
1951             );
1952              
1953 6         46 return 0;
1954             }
1955              
1956             #------------------------------------------------------------------------------
1957             # New style alarms.
1958              
1959             # Set an alarm. This does more *and* less than plain alarm(). It
1960             # only sets alarms (that's the less part), but it also returns an
1961             # alarm ID (that's the more part).
1962              
1963             sub alarm_set {
1964 241     241 1 8112 my ($self, $event_name, $time, @etc) = ($poe_kernel, @_[1..$#_]);
1965              
1966 241         292 if (ASSERT_USAGE) {
1967             _confess " must call alarm_set() from a running session"
1968             if $kr_active_session == $self;
1969             }
1970              
1971 247 100       647 unless (defined $event_name) {
1972 245         497 $self->_explain_usage("undefined event name in alarm_set()");
1973 1         7 $! = EINVAL;
1974 0         0 return;
1975             }
1976              
1977 1 100       4 unless (defined $time) {
1978 238         411 $self->_explain_usage("undefined time in alarm_set()");
1979 1         4 $! = EINVAL;
1980 0         0 return;
1981             }
1982              
1983 0         0 if (ASSERT_USAGE) {
1984             _carp(
1985             " The '$event_name' event is one of POE's own. Its " .
1986             "effect cannot be achieved by setting an alarm for it"
1987             ) if exists $poes_own_events{$event_name};
1988             }
1989              
1990 236         193 return $self->_data_ev_enqueue
1991             ( $kr_active_session, $kr_active_session, $event_name, ET_ALARM, [ @etc ],
1992             (caller)[1,2], $kr_active_event, $time,
1993             );
1994             }
1995              
1996             # Remove an alarm by its ID. TODO Now that alarms and events have
1997             # been recombined, this will remove an event by its ID. However,
1998             # nothing returns an event ID, so nobody knows what to remove.
1999              
2000             sub alarm_remove {
2001 466     230 1 5999 my ($self, $alarm_id) = ($poe_kernel, @_[1..$#_]);
2002              
2003 466         1620 if (ASSERT_USAGE) {
2004             _confess " must call alarm_remove() from a running session"
2005             if $kr_active_session == $self;
2006             }
2007              
2008 230 100       628 unless (defined $alarm_id) {
2009 221         426 $self->_explain_usage("undefined alarm id in alarm_remove()");
2010 1         5 $! = EINVAL;
2011 0         0 return;
2012             }
2013              
2014 8         22 my ($time, $event) =
2015             $self->_data_ev_clear_alarm_by_id($kr_active_session->ID(), $alarm_id);
2016 227 100       570 return unless defined $time;
2017              
2018             # In a list context, return the alarm that was removed. In a scalar
2019             # context, return a reference to the alarm that was removed. In a
2020             # void context, return nothing. Either way this returns a defined
2021             # value when someone needs something useful from it.
2022              
2023 227 100       610 return unless defined wantarray;
2024 219 100       1124 return ( $event->[EV_NAME], $time, $event->[EV_ARGS] ) if wantarray;
2025 4         104 return [ $event->[EV_NAME], $time, $event->[EV_ARGS] ];
2026             }
2027              
2028             # Move an alarm to a new time. This virtually removes the alarm and
2029             # re-adds it somewhere else. In reality, adjust_priority() is
2030             # optimized for this sort of thing.
2031              
2032             sub alarm_adjust {
2033 37     35 1 10448 my ($self, $alarm_id, $delta) = ($poe_kernel, @_[1..$#_]);
2034              
2035 35         58 if (ASSERT_USAGE) {
2036             _confess " must call alarm_adjust() from a running session"
2037             if $kr_active_session == $self;
2038             }
2039              
2040 35 100       154 unless (defined $alarm_id) {
2041 33         88 $self->_explain_usage("undefined alarm id in alarm_adjust()");
2042 1         4 $! = EINVAL;
2043 0         0 return;
2044             }
2045              
2046 1 100       4 unless (defined $delta) {
2047 32         80 $self->_explain_usage("undefined alarm delta in alarm_adjust()");
2048 1         5 $! = EINVAL;
2049 0         0 return;
2050             }
2051              
2052             my $my_alarm = sub {
2053 30     3758   157 $_[0]->[EV_SESSION] == $kr_active_session;
2054 0         0 };
2055            
2056 3758         8867 return $self->_data_ev_adjust( $alarm_id, $my_alarm, undef, $delta );
2057             }
2058              
2059             # A convenient function for setting alarms relative to now. It also
2060             # uses whichever time() POE::Kernel can find, which may be
2061             # Time::HiRes'.
2062              
2063             sub delay_set {
2064             # Always always always grab time() ASAP, so that the eventual
2065             # time we set the delay for is as close as possible to the time
2066             # at which they ASKED for the delay, not when we actually set it.
2067 50     20 1 5955 my $t = walltime();
2068 20         82 my $pri = monotime();
2069              
2070             # And now continue as normal
2071 20         116 my ($self, $event_name, $seconds, @etc) = ($poe_kernel, @_[1..$#_]);
2072              
2073 20         32 if (ASSERT_USAGE) {
2074             _confess " must call delay_set() from a running session"
2075             if $kr_active_session == $self;
2076             }
2077              
2078 20 100       89 unless (defined $event_name) {
2079 10         55 $self->_explain_usage("undefined event name in delay_set()");
2080 1         5 $! = EINVAL;
2081 0         0 return;
2082             }
2083              
2084 9         15 if (ASSERT_USAGE) {
2085             _carp(
2086             " The '$event_name' event is one of POE's own. Its " .
2087             "effect cannot be achieved by setting a delay for it"
2088             ) if exists $poes_own_events{$event_name};
2089             }
2090              
2091 17 100       46 unless (defined $seconds) {
2092 9         45 $self->_explain_usage("undefined seconds in delay_set()");
2093 8         34 $! = EINVAL;
2094 1         5 return;
2095             }
2096              
2097 8         185 return $self->_data_ev_enqueue
2098             ( $kr_active_session, $kr_active_session, $event_name, ET_ALARM, [ @etc ],
2099             (caller)[1,2], $kr_active_event, $t, $seconds, $pri+$seconds
2100             );
2101             }
2102              
2103             # Move a delay to a new offset from time(). As with alarm_adjust(),
2104             # this is optimized internally for this sort of activity.
2105              
2106             sub delay_adjust {
2107             # Always always always grab time() ASAP, so that the eventual
2108             # time we set the delay for is as close as possible to the time
2109             # at which they ASKED for the delay, not when we actually set it.
2110 5     5 1 2648 my $t = walltime();
2111 12         158 my $pri = monotime();
2112              
2113             # And now continue as normal
2114 5         21 my ($self, $alarm_id, $seconds) = ($poe_kernel, @_[1..$#_]);
2115              
2116 5         9 if (ASSERT_USAGE) {
2117             _confess " must call delay_adjust() from a running session"
2118             if $kr_active_session == $self;
2119             }
2120              
2121 5 100       23 unless (defined $alarm_id) {
2122 3         13 $self->_explain_usage("undefined delay id in delay_adjust()");
2123 1         5 $! = EINVAL;
2124 0         0 return;
2125             }
2126              
2127 1 100       7 unless (defined $seconds) {
2128 2         11 $self->_explain_usage("undefined delay seconds in delay_adjust()");
2129 1         5 $! = EINVAL;
2130 0         0 return;
2131             }
2132              
2133             my $my_delay = sub {
2134 0     0   0 $_[0]->[EV_SESSION] == $kr_active_session;
2135 0         0 };
2136              
2137 0         0 if (TRACE_EVENTS) {
2138             _warn(" adjusted event $alarm_id by $seconds seconds from $t");
2139             }
2140              
2141 0         0 return $self->_data_ev_set($alarm_id, $my_delay, $t, $pri, $seconds );
2142             }
2143              
2144             # Remove all alarms for the current session.
2145              
2146             sub alarm_remove_all {
2147 4     4 1 592 my $self = $poe_kernel;
2148              
2149 4         8 if (ASSERT_USAGE) {
2150             _confess " must call alarm_remove_all() from a running session"
2151             if $kr_active_session == $self;
2152             }
2153              
2154             # This should never happen, actually.
2155 4 100       23 _trap "unknown session in alarm_remove_all call" unless (
2156             $self->_data_ses_exists($kr_active_session->ID)
2157             );
2158              
2159             # Free every alarm owned by the session. This code is ripped off
2160             # from the _stop code to flush everything.
2161              
2162 2         8 my @removed = $self->_data_ev_clear_alarm_by_session(
2163             $kr_active_session->ID()
2164             );
2165              
2166 2 50       9 return unless defined wantarray;
2167 2 50       14 return @removed if wantarray;
2168 0         0 return \@removed;
2169             }
2170              
2171             #==============================================================================
2172             # SELECTS
2173             #==============================================================================
2174              
2175             sub _internal_select {
2176 2777     2777   4862 my ($self, $session, $handle, $event_name, $mode, $args) = @_;
2177              
2178             # If an event is included, then we're defining a filehandle watcher.
2179              
2180 2777 100       5195 if ($event_name) {
2181 1160         9068 $self->_data_handle_add($handle, $mode, $session, $event_name, $args);
2182             }
2183             else {
2184 1617         4806 $self->_data_handle_remove($handle, $mode, $session->ID);
2185             }
2186             }
2187              
2188             # A higher-level select() that manipulates read, write and expedite
2189             # selects together.
2190              
2191             sub select {
2192 112     112 1 1868 my ($self, $handle, $event_r, $event_w, $event_e, @args) = (
2193             $poe_kernel, @_[1..$#_]
2194             );
2195              
2196 112         136 if (ASSERT_USAGE) {
2197             _confess " must call select() from a running session"
2198             if $kr_active_session == $self;
2199             _confess " undefined filehandle in select()" unless defined $handle;
2200             _confess " invalid filehandle in select()"
2201             unless defined fileno($handle);
2202             foreach ($event_r, $event_w, $event_e) {
2203             next unless defined $_;
2204             _carp(
2205             " The '$_' event is one of POE's own. Its " .
2206             "effect cannot be achieved by setting a file watcher to it"
2207             ) if exists($poes_own_events{$_});
2208             }
2209             }
2210              
2211             $self->_internal_select(
2212 112         327 $kr_active_session, $handle, $event_r, MODE_RD, \@args
2213             );
2214 111         251 $self->_internal_select(
2215             $kr_active_session, $handle, $event_w, MODE_WR, \@args
2216             );
2217 110         402 $self->_internal_select(
2218             $kr_active_session, $handle, $event_e, MODE_EX, \@args
2219             );
2220 109         211 return 0;
2221             }
2222              
2223             # Only manipulate the read select.
2224             sub select_read {
2225 1828     1546 1 17830 my ($self, $handle, $event_name, @args) = ($poe_kernel, @_[1..$#_]);
2226              
2227 1548         1910 if (ASSERT_USAGE) {
2228             _confess " must call select_read() from a running session"
2229             if $kr_active_session == $self;
2230             _confess " undefined filehandle in select_read()"
2231             unless defined $handle;
2232             _confess " invalid filehandle in select_read()"
2233             unless defined fileno($handle);
2234             _carp(
2235             " The '$event_name' event is one of POE's own. Its " .
2236             "effect cannot be achieved by setting a file watcher to it"
2237             ) if defined($event_name) and exists($poes_own_events{$event_name});
2238             };
2239              
2240 1640         5360 $self->_internal_select(
2241             $kr_active_session, $handle, $event_name, MODE_RD, \@args
2242             );
2243 1639         6755 return 0;
2244             }
2245              
2246             # Only manipulate the write select.
2247             sub select_write {
2248 1893     914 1 9600 my ($self, $handle, $event_name, @args) = ($poe_kernel, @_[1..$#_]);
2249              
2250 1888         6106 if (ASSERT_USAGE) {
2251             _confess " must call select_write() from a running session"
2252             if $kr_active_session == $self;
2253             _confess " undefined filehandle in select_write()"
2254             unless defined $handle;
2255             _confess " invalid filehandle in select_write()"
2256             unless defined fileno($handle);
2257             _carp(
2258             " The '$event_name' event is one of POE's own. Its " .
2259             "effect cannot be achieved by setting a file watcher to it"
2260             ) if defined($event_name) and exists($poes_own_events{$event_name});
2261             };
2262              
2263 1794         13653 $self->_internal_select(
2264             $kr_active_session, $handle, $event_name, MODE_WR, \@args
2265             );
2266 1793         9857 return 0;
2267             }
2268              
2269             # Only manipulate the expedite select.
2270             sub select_expedite {
2271 686     3 1 4370 my ($self, $handle, $event_name, @args) = ($poe_kernel, @_[1..$#_]);
2272              
2273 685         10074 if (ASSERT_USAGE) {
2274             _confess " must call select_expedite() from a running session"
2275             if $kr_active_session == $self;
2276             _confess " undefined filehandle in select_expedite()"
2277             unless defined $handle;
2278             _confess " invalid filehandle in select_expedite()"
2279             unless defined fileno($handle);
2280             _carp(
2281             " The '$event_name' event is one of POE's own. Its " .
2282             "effect cannot be achieved by setting a file watcher to it"
2283             ) if defined($event_name) and exists($poes_own_events{$event_name});
2284             };
2285              
2286 685         4249 $self->_internal_select(
2287             $kr_active_session, $handle, $event_name, MODE_EX, \@args
2288             );
2289 684         2457 return 0;
2290             }
2291              
2292             # Turn off a handle's write mode bit without doing
2293             # garbage-collection things.
2294             sub select_pause_write {
2295 853     852 1 5103 my ($self, $handle) = ($poe_kernel, @_[1..$#_]);
2296              
2297 852         1086 if (ASSERT_USAGE) {
2298             _confess " must call select_pause_write() from a running session"
2299             if $kr_active_session == $self;
2300             _confess " undefined filehandle in select_pause_write()"
2301             unless defined $handle;
2302             _confess " invalid filehandle in select_pause_write()"
2303             unless defined fileno($handle);
2304             };
2305              
2306 852 100       2682 return 0 unless $self->_data_handle_is_good($handle, MODE_WR);
2307              
2308 851         2644 $self->_data_handle_pause($handle, MODE_WR);
2309              
2310 850         2543 return 1;
2311             }
2312              
2313             # Turn on a handle's write mode bit without doing garbage-collection
2314             # things.
2315             sub select_resume_write {
2316 1171     520 1 8096 my ($self, $handle) = ($poe_kernel, @_[1..$#_]);
2317              
2318 1171         4153 if (ASSERT_USAGE) {
2319             _confess " must call select_resume_write() from a running session"
2320             if $kr_active_session == $self;
2321             _confess " undefined filehandle in select_resume_write()"
2322             unless defined $handle;
2323             _confess " invalid filehandle in select_resume_write()"
2324             unless defined fileno($handle);
2325             };
2326              
2327 1171 100       4322 return 0 unless $self->_data_handle_is_good($handle, MODE_WR);
2328              
2329 519         1387 $self->_data_handle_resume($handle, MODE_WR);
2330              
2331 518         2082 return 1;
2332             }
2333              
2334             # Turn off a handle's read mode bit without doing garbage-collection
2335             # things.
2336             sub select_pause_read {
2337 498     73 1 3358 my ($self, $handle) = ($poe_kernel, @_[1..$#_]);
2338              
2339 498         1770 if (ASSERT_USAGE) {
2340             _confess " must call select_pause_read() from a running session"
2341             if $kr_active_session == $self;
2342             _confess " undefined filehandle in select_pause_read()"
2343             unless defined $handle;
2344             _confess " invalid filehandle in select_pause_read()"
2345             unless defined fileno($handle);
2346             };
2347              
2348 498 100       1336 return 0 unless $self->_data_handle_is_good($handle, MODE_RD);
2349              
2350 72         195 $self->_data_handle_pause($handle, MODE_RD);
2351              
2352 71         238 return 1;
2353             }
2354              
2355             # Turn on a handle's read mode bit without doing garbage-collection
2356             # things.
2357             sub select_resume_read {
2358 141     71 1 2014 my ($self, $handle) = ($poe_kernel, @_[1..$#_]);
2359              
2360 141         374 if (ASSERT_USAGE) {
2361             _confess " must call select_resume_read() from a running session"
2362             if $kr_active_session == $self;
2363             _confess " undefined filehandle in select_resume_read()"
2364             unless defined $handle;
2365             _confess " invalid filehandle in select_resume_read()"
2366             unless defined fileno($handle);
2367             };
2368              
2369 141 100       423 return 0 unless $self->_data_handle_is_good($handle, MODE_RD);
2370              
2371 70         204 $self->_data_handle_resume($handle, MODE_RD);
2372              
2373 69         357 return 1;
2374             }
2375              
2376             #==============================================================================
2377             # Aliases: These functions expose the internal alias accessors with
2378             # extra fun parameter/return value checking.
2379             #==============================================================================
2380              
2381             ### Set an alias in the current session.
2382              
2383             sub alias_set {
2384 261     193 1 5841 my ($self, $name) = ($poe_kernel, @_[1..$#_]);
2385              
2386 261         572 if (ASSERT_USAGE) {
2387             _confess " undefined alias in alias_set()" unless defined $name;
2388             };
2389              
2390             # Don't overwrite another session's alias.
2391 261         729 my $existing_session = $self->_data_alias_resolve($name);
2392 192 100       752 if (defined $existing_session) {
2393 181 100       499 if ($existing_session != $kr_active_session) {
2394 42         108 $self->_explain_usage("alias '$name' is in use by another session");
2395 1         8 return EEXIST;
2396             }
2397 4         15 return 0;
2398             }
2399              
2400 51         123 $self->_data_alias_add($kr_active_session, $name);
2401 146         526 return 0;
2402             }
2403              
2404             ### Remove an alias from the current session.
2405              
2406             sub alias_remove {
2407 201     66 1 2745 my ($self, $name) = ($poe_kernel, @_[1..$#_]);
2408              
2409 66         99 if (ASSERT_USAGE) {
2410             _confess " undefined alias in alias_remove()" unless defined $name;
2411             };
2412              
2413 66         177 my $existing_session = $self->_data_alias_resolve($name);
2414              
2415 65 100       227 unless (defined $existing_session) {
2416 56         168 $self->_explain_usage("alias '$name' does not exist");
2417 2         11 return ESRCH;
2418             }
2419              
2420 9 100       38 if ($existing_session != $kr_active_session) {
2421 54         189 $self->_explain_usage("alias '$name' does not belong to current session");
2422 1         7 return EPERM;
2423             }
2424              
2425 8         33 $self->_data_alias_remove($kr_active_session, $name);
2426 60         197 return 0;
2427             }
2428              
2429             ### Resolve an alias into a session.
2430              
2431             sub alias_resolve {
2432 63     11 1 3033 my ($self, $name) = ($poe_kernel, @_[1..$#_]);
2433              
2434 11         16 if (ASSERT_USAGE) {
2435             _confess " undefined alias in alias_resolve()" unless defined $name;
2436             };
2437              
2438 11         33 return $self->_resolve_session($name);
2439             }
2440              
2441             ### List the aliases for a given session.
2442              
2443             sub alias_list {
2444 18     8 1 589 my ($self, $search_session) = ($poe_kernel, @_[1..$#_]);
2445 8   66     45 my $session =
2446             $self->_resolve_session($search_session || $kr_active_session);
2447              
2448 8 100       21 unless (defined $session) {
2449 0         0 $self->_explain_resolve_failure($search_session, "nonfatal");
2450 0         0 return;
2451             }
2452              
2453             # Return whatever can be found.
2454 8         24 my @alias_list = $self->_data_alias_list($session->ID);
2455 8 100       56 return wantarray() ? @alias_list : $alias_list[0];
2456             }
2457              
2458             #==============================================================================
2459             # Kernel and Session IDs
2460             #==============================================================================
2461              
2462             # Return the Kernel's "unique" ID. There's only so much uniqueness
2463             # available; machines on separate private 10/8 networks may have
2464             # identical kernel IDs. The chances of a collision are vanishingly
2465             # small.
2466              
2467             # The Kernel and Session IDs are based on Philip Gwyn's code. I hope
2468             # he still can recognize it.
2469              
2470             sub _recalc_id {
2471 179     179   552 my $self = shift;
2472              
2473 179         1435 my $old_id = $self->[KR_ID];
2474              
2475 179         386 my $hostname = eval { (uname)[1] };
  179         3324  
2476 179 50       902 $hostname = hostname() unless defined $hostname;
2477              
2478 537         2721 my $new_id = $self->[KR_ID] = join(
2479             "-", $hostname,
2480 537         2635 map { unpack "H*", $_ }
2481 179         2176 map { pack "N", $_ }
2482             (monotime(), $$, ++$kr_id_seq)
2483             );
2484              
2485 179 100       1039 if (defined $old_id) {
2486 4         108 $self->_data_sig_relocate_kernel_id($old_id, $new_id);
2487 4         68 $self->_data_ses_relocate_kernel_id($old_id, $new_id);
2488 4         87 $self->_data_sid_relocate_kernel_id($old_id, $new_id);
2489 4         84 $self->_data_handle_relocate_kernel_id($old_id, $new_id);
2490 4         56 $self->_data_ev_relocate_kernel_id($old_id, $new_id);
2491 4         67 $self->_data_alias_relocate_kernel_id($old_id, $new_id);
2492             }
2493             }
2494              
2495 15153     15153 1 98186 sub ID { $poe_kernel->[KR_ID] }
2496              
2497             # Resolve an ID to a session reference. This function is virtually
2498             # moot now that _resolve_session does it too. This explicit call will
2499             # be faster, though, so it's kept for things that can benefit from it.
2500              
2501             sub ID_id_to_session {
2502 6     6 1 425 my ($self, $id) = ($poe_kernel, @_[1..$#_]);
2503              
2504 6         12 if (ASSERT_USAGE) {
2505             _confess " undefined ID in ID_id_to_session()" unless defined $id;
2506             };
2507              
2508 6         23 my $session = $self->_data_sid_resolve($id);
2509 5 100       18 return $session if defined $session;
2510              
2511 5         27 $self->_explain_return("ID does not exist");
2512 0         0 $! = ESRCH;
2513 0         0 return;
2514             }
2515              
2516             # Resolve a session reference to its corresponding ID.
2517              
2518             sub ID_session_to_id {
2519 33     33 1 1097 my ($self, $session) = ($poe_kernel, @_[1..$#_]);
2520              
2521 33         50 if (ASSERT_USAGE) {
2522             _confess " undefined session in ID_session_to_id()"
2523             unless defined $session;
2524             };
2525              
2526 33         121 my $id = $self->_data_ses_resolve_to_id($session);
2527 32 100       124 if (defined $id) {
2528 31         94 $! = 0;
2529 31         76 return $id;
2530             }
2531              
2532 32         133 $self->_explain_return("session ($session) does not exist");
2533 0         0 $! = ESRCH;
2534 0         0 return;
2535             }
2536              
2537             #==============================================================================
2538             # Extra reference counts, to keep sessions alive when things occur.
2539             # They take session IDs because they may be called from resources at
2540             # times where the session reference is otherwise unknown.
2541             #==============================================================================
2542              
2543             sub refcount_increment {
2544 105     105 1 1703 my ($self, $session_id, $tag) = ($poe_kernel, @_[1..$#_]);
2545              
2546 105         154 if (ASSERT_USAGE) {
2547             _confess " undefined session ID in refcount_increment()"
2548             unless defined $session_id;
2549             _confess " undefined reference count tag in refcount_increment()"
2550             unless defined $tag;
2551             };
2552              
2553 105 100       344 unless ($self->_data_ses_exists($session_id)) {
2554 103         463 $self->_explain_return("session id $session_id does not exist");
2555 101         1021 $! = ESRCH;
2556 0         0 return;
2557             }
2558              
2559 1         6 my $refcount = $self->_data_extref_inc($session_id, $tag);
2560             # TODO trace it here
2561 1         5 return $refcount;
2562             }
2563              
2564             sub refcount_decrement {
2565 205     104 1 3524 my ($self, $session_id, $tag) = ($poe_kernel, @_[1..$#_]);
2566              
2567 205         1649 if (ASSERT_USAGE) {
2568             _confess " undefined session ID in refcount_decrement()"
2569             unless defined $session_id;
2570             _confess " undefined reference count tag in refcount_decrement()"
2571             unless defined $tag;
2572             };
2573              
2574 104 100       463 unless ($self->_data_ses_exists($session_id)) {
2575 102         399 $self->_explain_return("session id $session_id does not exist");
2576 100         445 $! = ESRCH;
2577 0         0 return;
2578             }
2579              
2580 1         11 my $refcount = $self->_data_extref_dec($session_id, $tag);
2581              
2582             # TODO trace it here
2583 1         4 return $refcount;
2584             }
2585              
2586             #==============================================================================
2587             # HANDLERS
2588             #==============================================================================
2589              
2590             # Add or remove event handlers from sessions.
2591             sub state {
2592 2170     2070 1 9154 my ($self, $event, $state_code, $state_alias) = ($poe_kernel, @_[1..$#_]);
2593 2170 100       5927 $state_alias = $event unless defined $state_alias;
2594              
2595 2070         2390 if (ASSERT_USAGE) {
2596             _confess " must call state() from a running session"
2597             if $kr_active_session == $self;
2598             _confess " undefined event name in state()" unless defined $event;
2599             _confess " can't call state() outside a session" if (
2600             $kr_active_session == $self
2601             );
2602             };
2603              
2604 2070 100 66     10186 if (
2605             (ref($kr_active_session) ne '') &&
2606             (ref($kr_active_session) ne 'POE::Kernel')
2607             ) {
2608 2062         8267 $kr_active_session->_register_state($event, $state_code, $state_alias);
2609 2061         5133 return 0;
2610             }
2611              
2612             # TODO A terminal signal (such as UIDESTROY) kills a session. The
2613             # Kernel deallocates the session, which cascades destruction to its
2614             # HEAP. That triggers a Wheel's destruction, which calls
2615             # $kernel->state() to remove a state from the session. The session,
2616             # though, is already gone. If TRACE_RETVALS and/or ASSERT_RETVALS
2617             # is set, this causes a warning or fatal error.
2618              
2619 1279         9083 $self->_explain_return("session ($kr_active_session) does not exist");
2620 1278         7130 return ESRCH;
2621             }
2622              
2623             1;
2624              
2625             __END__