Skip to content

Commit

Permalink
ActiveState Perl + Tk + POE::Wheel::Run + coderefs = Pain.
Browse files Browse the repository at this point in the history
ActiveState Perl emulates fork() with iThreads.  Only Perl's core
exit() will properly "exit" a "process".  Tk overrides exit() with its
own XS magic.  This seems to kill off the parent "process".  When
POE::Wheel::Run is used to run subroutines (coderefs) in child
processes, it must somehow exit() the child process, simulating exec.
Under Windows, that's Perl's core exit(), which is usurped by Tk,
which causes ALL MANNER OF EVIL!  DON'T GO THERE!  WE SURE AREN'T!
  • Loading branch information
rcaputo committed Apr 23, 2005
1 parent 12e00dc commit 5bca0e5
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 22 deletions.
55 changes: 34 additions & 21 deletions lib/POE/Wheel/Run.pm
Expand Up @@ -395,7 +395,7 @@ sub new {
close $stdin_write;
close $stdout_read;
close $stderr_read if defined $stderr_read;

# Need to close on Win32 because std handles aren't dup'ed, no
# harm elsewhere. Close STDERR later to not influence possible
# die.
Expand All @@ -412,7 +412,8 @@ sub new {
open( STDOUT, ">&" . fileno($stdout_write) )
or die "can't redirect stdout in child pid $$: $!";

# Need to close on Win32 because std handles aren't dup'ed, no harm elsewhere
# Need to close on Win32 because std handles aren't dup'ed, no
# harm elsewhere
close STDERR;

# Redirect STDERR to the write end of the stderr pipe. If the
Expand All @@ -432,15 +433,27 @@ sub new {
close $sem_pipe_write;

if (POE::Kernel::RUNNING_IN_HELL) {
# The Win32 pseudo fork sets up the std handles in the child based on the true win32 handles
# For the exec these get remembered, so manipulation of STDIN/OUT/ERR is not enough. Only
# necessary for the exec, as Perl CODE subroutine goes through 0/1/2 which are correct.
# But ofcourse that coderef might invoke exec, so better do it regardless.
# HACK: Using Win32::Console as nothing else exposes SetStdHandle
Win32::Console::_SetStdHandle(STD_INPUT_HANDLE(), FdGetOsFHandle(fileno($stdin_read)));
Win32::Console::_SetStdHandle(STD_OUTPUT_HANDLE(), FdGetOsFHandle(fileno($stdout_write)));
Win32::Console::_SetStdHandle(STD_ERROR_HANDLE(), FdGetOsFHandle(fileno($stderr_write)));
# The Win32 pseudo fork sets up the std handles in the child
# based on the true win32 handles For the exec these get
# remembered, so manipulation of STDIN/OUT/ERR is not enough.
# Only necessary for the exec, as Perl CODE subroutine goes
# through 0/1/2 which are correct. But ofcourse that coderef
# might invoke exec, so better do it regardless.
# HACK: Using Win32::Console as nothing else exposes SetStdHandle
Win32::Console::_SetStdHandle(
STD_INPUT_HANDLE(),
FdGetOsFHandle(fileno($stdin_read))
);
Win32::Console::_SetStdHandle(
STD_OUTPUT_HANDLE(),
FdGetOsFHandle(fileno($stdout_write))
);
Win32::Console::_SetStdHandle(
STD_ERROR_HANDLE(),
FdGetOsFHandle(fileno($stderr_write))
);
}

# Exec the program depending on its form.
if (ref($program) eq 'CODE') {

Expand All @@ -465,20 +478,20 @@ sub new {
# Give up with a plain exit if we must.
# On win32 cannot _exit as it will kill *all* threads, meaning parent too
unless (POE::Kernel::RUNNING_IN_HELL) {
eval { POSIX::_exit(0); };
eval { kill KILL => $$; };
eval { exec("$^X -e 0"); };
eval { POSIX::_exit(0); };
eval { kill KILL => $$; };
eval { exec("$^X -e 0"); };
};
exit(0);
} else {
if (ref($program) eq 'ARRAY') {
exec(@$program, @$prog_args)
or die "can't exec (@$program) in child pid $$: $!";
}
else {
exec(join(" ", $program, @$prog_args))
or die "can't exec ($program) in child pid $$: $!";
}
if (ref($program) eq 'ARRAY') {
exec(@$program, @$prog_args)
or die "can't exec (@$program) in child pid $$: $!";
}
else {
exec(join(" ", $program, @$prog_args))
or die "can't exec ($program) in child pid $$: $!";
}
}
die "insanity check passed";
}
Expand Down
8 changes: 7 additions & 1 deletion tests/30_loops/00_base/wheel_run.pm
Expand Up @@ -231,7 +231,13 @@ my $program =

my $coderef_flush_count = 0;

{ my $program = sub {
if ($^O eq "MSWin32" and exists $INC{"Tk.pm"}) {
ok(23, "SKIP: Wheel::Run + Tk + ActiveState + CODE program = pain");
ok(24, "SKIP: Wheel::Run + Tk + ActiveState + CODE program = pain");
$coderef_flush_count = 3;
}
else {
my $program = sub {
my ($out, $err) = @_;
local $/ = q(!);
OUTER: while (1) {
Expand Down

0 comments on commit 5bca0e5

Please sign in to comment.