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