Skip Menu |

This queue is for tickets about the POE CPAN distribution.

Report information
The Basics
Id: 48715
Status: rejected
Priority: 0/
Queue: POE

People
Owner: Nobody in particular
Requestors: craig [...] alcatel-lucent.com
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in: 1.006
Fixed in: (no value)



Subject: POE::Wheel::Run/Tk/MSWin32 Problem
This issue was discussed at http://www.perlmonks.org/?node_id=787371 The attached program works under both Unix and windows as expected. To make it work under windows (ActiveState perl), I had to run the command "dir & pause", otherwise the Tk window will go away (I want it to stick around until the user deletes it). It should have worked by just running the "dir" command, because I put in "postback('DontDie')" to prevent the Tk window from being shut down. Using POE::Wheel::Run::Win32 doesn't seem to help, as it burps up an "ERR: Free to wrong pool" message. After some discussion, Rocco asked me to submit this bug report. -Craig
Subject: tst00.pl
use English; use strict; use warnings; use Tk; use POE; use POE::Wheel::Run; # Setup program to run... my $PGM = 'ls'; if ($OSNAME eq 'MSWin32') { $PGM = 'dir & pause' }; #if ($OSNAME eq 'MSWin32') { $PGM = 'dir' }; # This doesn't work! print STDERR "$OSNAME PGM=$PGM\n"; my $TEXT; # Global for text widget... # Setup POE session... my $session = _poeSetup(); # Create dummy postback so the session won't die once input is done... my $subref = $session->postback('DontDie'); # Go... $poe_kernel->run(); ################# # POE Subroutines ################# sub _poeSetup { my $session = POE::Session->create( inline_states=>{ _start => \&_startUp, KidOut => \&_GetStdout, KidErr => \&_GetStderr, KidClose => \&_DoClose, }, ); return($session); } # POE Session Supporting Routines... sub _startUp { $TEXT=$poe_main_window->Scrolled('Text', -wrap=>'none')->pack; $poe_main_window->update; my $child = POE::Wheel::Run->new( Program => $PGM, StdoutEvent => 'KidOut', StderrEvent => 'KidErr', CloseEvent => 'KidClose', ); $_[KERNEL]->sig_child($child->PID, '_DoSig'); $_[HEAP]{Kids}{WID}{$child->ID} = $child; $_[HEAP]{Kids}{PID}{$child->PID} = $child; } sub _GetStdout { my ($line, $wid) = @_[ARG0, ARG1]; my $child = $_[HEAP]{Kids}{WID}{$wid}; $TEXT->insert('end', $child->PID . " OUT: $line\n"); $TEXT->see('end'); $poe_main_window->update; } sub _GetStderr { my ($line, $wid) = @_[ARG0, ARG1]; my $child = $_[HEAP]{Kids}{WID}{$wid}; $TEXT->insert('end', $child->PID . " ERR: $line\n"); $TEXT->see('end'); $poe_main_window->update; } sub _DoClose { my $wid = $_[ARG0]; my $child = $_[HEAP]{Kids}{WID}{$wid}; unless (defined $child) { print STDERR "wid $wid closed all pipes.\n"; return; } print STDERR "wid $wid closed all pipes.\n"; delete $_[HEAP]{Kids}{PID}{$child->PID}; } sub _DoSig { print STDERR "pid $_[ARG1] exited with status $_[ARG2].\n"; my $child = delete $_[HEAP]{Kids}{PID}{$_[ARG1]}; return unless defined $child; delete $_[HEAP]{Kids}{WID}{$child->ID}; }
I finally had a chance to try this in Windows. It's not just that the window goes away---ActiveState Perl crashes entirely: Problem signature: Problem Event Name: APPCRASH Application Name: perl.exe Application Version: 5.10.0.1005 Application Timestamp: 4a199d7b Fault Module Name: perl510.dll Fault Module Version: 5.10.0.1005 Fault Module Timestamp: 4a199d7a Exception Code: c0000005 Exception Offset: 0009b108 OS Version: 6.0.6001.2.1.0.256.1 Locale ID: 3081 Additional Information 1: 8fa1 Additional Information 2: 9d2d51358673427ced829a737938897f Additional Information 3: 6265 Additional Information 4: 2456740ed2fc16fef02c5739ea89bba3 Read our privacy statement: http://go.microsoft.com/fwlink/?linkid=50163&clcid=0x0409 It also crashes Strawberry Perl: Problem signature: Problem Event Name: APPCRASH Application Name: perl.exe Application Version: 0.0.0.0 Application Timestamp: 4a5dfcf6 Fault Module Name: perl510.dll Fault Module Version: 0.0.0.0 Fault Module Timestamp: 4a5dfcf3 Exception Code: c0000005 Exception Offset: 000ecb5d OS Version: 6.0.6001.2.1.0.256.1 Locale ID: 3081 Additional Information 1: 2176 Additional Information 2: 709cf08a65a5fcb33db7eae39a257507 Additional Information 3: 6ef1 Additional Information 4: a725b524d2b0ed25f426f8a9e2e9ad03 Read our privacy statement: http://go.microsoft.com/fwlink/?linkid=50163&clcid=0x0409
I have reduced the problem to a four-line test case that does not use POE. The conclusion is that Tk and fork() don't work together in Windows. use Tk; my $mw = Tk::MainWindow->new(); sleep 1 if fork (); exit; For this problem to be fixed, Tk must support being forked under MSWin32. Show quoted text
--- Notes Follow --- Using POE::Wheel::Run, Perl crashes on child exit. http://w4.lns.cornell.edu/~pvhp/ptk/ptkFAQ.html discusses fork() and exit() issues: Slaven Rezic addresses another aspect of fork()ing. Suppose you want the child to unload all the Tk stuff without attempting to destroy it, that is, to tell it to undef every Tk var it has, everywhere. You'll want to POSIX::exit(0); or CORE::exit(0); rather than exit(0); in the child process. The unqualified exit() is evaluated as Tk::exit. This, of course, destroys all MainWindows, which is the effect we want to avoid. ... Explicitly calling POSIX::_exit(0) exits both the parent and child process. They are really separate threads in the same process, so the C-level exit() stops them both. Explicitly calling Tk::exit(0) crashes Perl in a new and interesting way: "Free to wrong pool (hex) not (hex) at ...." This is most likely because a child thread is trying to shutdown Tk, which is owned by and still running in the parent thread. Explicitly calling CORE::exit(0) allows the program to crash in the way that was reported in this ticket. kill -9, $$ in the child process also triggers the crash. exec() also triggers the crash.
I'm sorry, but I must reject this ticket. As shown by the four-line test case, there is an underlying problem using Tk and fork() on Windows. Tk is not thread-safe, and fork() uses threads on Windows. Together, they crash spectacularly, whether or not POE is involved. Perhaps POE has a problem, but it's impossible to detect without first resolving Tk's issue with fork() on Windows. I invite you to open a ticket against Tk with my test case. Please reopen this ticket if you find a work-around, or if problems persist after Tk is fixed. I would love to resolve this, if possible.
From: craig [...] alcatel-lucent.com
Rocco- No problem rejecting the ticket. I understand the problem lies elsewhere. There already seems to have been a fork bug written against Tk, that's been hanging around for 5 years now (http://rt.cpan.org/Public/Bug/Display.html?id=6351). I don't expect to see it get fixed anytime soon. Sorry to be a bit dense on this, but a couple of things are not clear to me: 1.) I'm able to avoid the problem by adding "& pause" to the command I want to run. This prevents the forked child from exiting, and everything else seems to be working fine. Is everything else actually, really, working fine or are there some other problems lurking there that I have not run into yet? In other words, is the specific problem with Tk and windows fork only in the exiting of the child? 2.) Should I continue to use the "& pause" workaround, or is there a better one? 3.) Is it POE that decided to use fork, or something that POE is using, that is using fork? I'm wondering if we could eliminate the problem by finding some non-thread fork alternative for windows (is there one)? Thanks -Craig
1. Avoiding the problem by using pause. You're keeping the child process around until the parent program is ready to exit. If you intend to run the program more than once, it will approach the full resources of your machine to keep them around. On UNIX systems, this ends when the OS has no more resources to start new programs, and someone at the console hard boots the machine. 2. Continue using pause? You can try, but I don't recommend it. 3. Is POE deciding to fork? POE::Wheel::Run is a module that uses fork() to run some code or an external program in the background. Your application is choosing to fork() by using this module. You may be able to avoid fork() if whatever you want to do doesn't really need it. I can't answer more specifically until I know what you're trying to do. As far as I know, there's no non-threaded fork() for Windows. There may be Windows-specific calls that do something like fork(). If you can find the proper invocation, I may be able to add it to POE::Wheel::Run for compatibility.
Show quoted text
> There may > be Windows-specific calls that do something like fork(). If you can > find the proper invocation, I may be able to add it to POE::Wheel::Run > for compatibility.
Here is what I use in a perl script when I want to run command.pl on unix, but command.exe on windows: use strict; use warnings; use English; # Setup command variables... my $cmd = "command"; # Command root to run my $cmdopts = "INPUT001"; # Options for command my $cmdpath; if($OSNAME=~/MSWin32/) { $cmd .= '.exe'; # Find full path name (using current directory and desktop)... use Cwd; foreach my $p (getcwd, "$ENV{USERPROFILE}\\Desktop") { if(-x "$p\\$cmd") {$cmdpath=$p; last}; } # Verify the found command is executable... if(! $cmdpath) { die "\n\n PC ERROR: Can't find executable $cmd\n\t"; } # Run command... print STDERR "WINDOWS: $cmdpath\\$cmd"; require Win32::Process; no strict; # Doesn't like NORMAL_PRIORITY_CLASS my $process; Win32::Process::Create($process, "$cmdpath\\$cmd", " $cmdopts", 1, NORMAL_PRIORITY_CLASS, "$cmdpath") || die "\n\nPC ERROR: Can't run $cmd\n\t", Win32::FormatMessage( Win32::GetLastError() ); use strict; }else{ $cmdpath = '.'; # Default for unix $cmd .= '.pl'; # Verify command is executable... if(-x "$cmdpath/$cmd") {print STDERR "executable found\n"} else{ die "Cannot find executable $cmdpath/$cmd" } print STDERR "Running: $cmdpath/$cmd $cmdopts\n"; system("$cmdpath/$cmd $cmdopts &"); }
On Fri Sep 04 11:06:53 2009, cmv wrote: Show quoted text
> > There may > > be Windows-specific calls that do something like fork(). If you can > > find the proper invocation, I may be able to add it to
> POE::Wheel::Run
> > for compatibility.
> > Here is what I use in a perl script when I want to run command.pl on > unix, but command.exe > on windows:
[...] I've just applied someone's patch to incorporate POE::Wheel::Run::Win32 in POE::Wheel::Run (with the ::Win32 author's blessing). It uses more Win32:: calls, but not Win32::Process::Create(). Is Win32::Process::Create() compatible with Tk?
On Fri Oct 02 00:10:33 2009, RCAPUTO wrote: Show quoted text
> I've just applied someone's patch to incorporate POE::Wheel::Run::Win32 > in POE::Wheel::Run (with the ::Win32 author's blessing). It uses more > Win32:: calls, but not Win32::Process::Create(). > > Is Win32::Process::Create() compatible with Tk?
I've been using Win32::Process::Create in my Tk-based tools here at work for a number of years (wow, approaching 10 now), and have never encountered a problem with it. However, my use is very simplistic - I usually have my perl-Tk based GUI startup process spawn the perl-Tk based GUI analysis process after setting up the input data stream. I would hope that using Win32::Process::Create would avoid the problem discovered here, but can't be sure.
On Fri Oct 02 09:09:28 2009, cmv wrote: Show quoted text
> On Fri Oct 02 00:10:33 2009, RCAPUTO wrote:
> > I've just applied someone's patch to incorporate
> POE::Wheel::Run::Win32
> > in POE::Wheel::Run (with the ::Win32 author's blessing). It uses
> more
> > Win32:: calls, but not Win32::Process::Create(). > > > > Is Win32::Process::Create() compatible with Tk?
> > I've been using Win32::Process::Create in my Tk-based tools here at > work for a number of > years (wow, approaching 10 now), and have never encountered a problem > with it. However, > my use is very simplistic - I usually have my perl-Tk based GUI > startup process spawn the > perl-Tk based GUI analysis process after setting up the input data > stream. > > I would hope that using Win32::Process::Create would avoid the problem > discovered here, > but can't be sure.
I'm not sure either. Looking at it closer, the code doesn't set up STDIN/STDOUT/STDERR communications between the parent and child processes. That's a very important part of POE::Wheel::Run's job.
Win32::Process::Create seems to be awkward for POE::Wheel::Run's pipe/fork/exec model. There doesn't seem to be a way to wait for child processes without polling or blocking. Web research indicates that it's not easy to set up pipes to processes created this way.