File Coverage

blib/lib/POE/Kernel.pm
Criterion Covered Total %
statement 700 773 90.5
branch 246 290 84.8
condition 62 96 64.5
subroutine 101 112 90.1
pod 49 49 100.0
total 1158 1320 87.7


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