Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Perl forking and shared memory strangeness under Windows

by Roger (Parson)
on Feb 23, 2004 at 04:50 UTC ( [id://331029]=perlquestion: print w/replies, xml ) Need Help??

Roger has asked for the wisdom of the Perl Monks concerning the following question:

Hi Folks, I have recently discoverred a strange behaviour of forking and shared memory under windows. Below is the code in concern:
#!C:/Perl/bin/perl -w use strict; use Win32::MMF::Shareable; if( fork ) { my $ns = tie( my %share, 'Win32::MMF::Shareable', 'share' ) || die; sleep 1; $share{parent} = 1; # select undef, undef, undef, 2.0; <----- dummy line } else { my $ns = tie( my %share, 'Win32::MMF::Shareable', 'share' ) || die; $share{child} = 1; }

When I remove the dummy line, which is commented anyway, the code crashes Perl with "Free to wrong pool <address> not <address> during global destruction" error. When I leave the dummy line, the code executes without problem, on my machine anyway.

I am out of ideas as why this is happenning. Can anyone see what might be causing this strange behaviour? I have researched on the web, and I found the following description:

usually under ithreads when the interpreter context is wrong and a memory from the wrong pool is allocated.

What does this mean? Does it have anything to do with the behavious I am getting?

Thanks for your suggestions.

Update:
I put a '!' (negation) in front of fork, and it seems not to crash any more. It seems that the parent must finish first?

if( ! fork ) { my $ns = tie( my %share, 'Win32::MMF::Shareable', 'share' ) || die; sleep 1; $share{parent} = 1; } else { my $ns = tie( my %share, 'Win32::MMF::Shareable', 'share' ) || die; $share{child} = 1; }

Replies are listed 'Best First'.
Re: Perl forking and shared memory strangeness under Windows
by BrowserUk (Patriarch) on Feb 23, 2004 at 05:22 UTC

    When you fork in AS perl under win32 (I think cygwin builds work differently), you aren't creating another process, You are instantiating another interpreter on a new thread. That's the tie-in to iThreads.

    The "Free to wrong pool" indicates that a piece of memory allocated by one instance of the interpreter has come up for destruction by a different interpreter.

    Quite how this is alleviated by the presence of a commented out line that references no variables I can't imagine, but as a fix, you might try requireing Win32::MMF::Shareable within each branch of the if( fork ) { statement.

    I'm hazarding a guess that some load-time (BEGIN|INIT|CHECK} code is allocating a variable in the parent thread and the child thread is inheriting it and trying to free it.

    This is mostly guesswork, but it would be worth a try.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    Timing (and a little luck) are everything!
      Thanks for the suggestion BrowserUk, I have reviewed the module code for Win32::MMF::Shareable, and after extensive debugging, I (think that I) have discoverred that the module might not be thread safe. I am doing some experiments at the moment to see if I could have independend sets of data both child and parents so they don't interfere with each other, as currently the child and parent share the same set of global data.

      I tried your suggestion: I removed the use Win32::MMF::Shareable line at the start, which gets loaded at compile time, and then added require in each parent and child processes after the fork. The problem some how has gone away. The following is the test code I used:
      #!C:/Perl/bin/perl -w use strict; use Data::Dumper; if( fork ) { require Win32::MMF::Shareable; my $ns = tie( my %share, 'Win32::MMF::Shareable', 'share' ) || die; sleep(1); $share{parent} = 1; print Dumper(\%share); } else { require Win32::MMF::Shareable; my $ns = tie( my %share, 'Win32::MMF::Shareable', 'share' ) || die; $share{child} = 1; }

      Is this because the require is executed at run-time, which causes two different copy of Storable to be loaded at run-time, which in turn gets freed properly in their own instances?

      And thanks again!

        Is this because the require is executed at run-time, which causes two different copy of Storable to be loaded at run-time, which in turn gets freed properly in their own instances?

        Yes. YW :)


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "Think for yourself!" - Abigail
        Timing (and a little luck) are everything!
Re: Perl forking and shared memory strangeness under Windows
by NetWallah (Canon) on Feb 23, 2004 at 05:57 UTC
    In my case, (Win XP, perl 5.8.0, MMF 0.09), perl crashes regardless of whether or not the line is commented.

    The crash is at 77C43038 in msvcrt.dll, which is called from Storable.dll!00335423() . Hopefully, that will clue the author of the dll (Roger?).

    "Experience is a wonderful thing. It enables you to recognize a mistake when you make it again."
      Thanks NetWallah for the debug information, now I have something to start with.

      I changed the tie() variable to a simple scalar, so that it will be go through shareable, and tested again, the following code, almost exactly the same as before, works with no problems. So I guess the problem is really in Shareable.
      #!C:/Perl/bin/perl -w use strict; use Win32::MMF; use Win32::MMF::Shareable; if( fork ) { my $ns = tie( my $share, 'Win32::MMF::Shareable', 'share' ) || die; sleep(1); $share = 'PARENT'; } else { my $ns = tie( my $share, 'Win32::MMF::Shareable', 'share' ) || die; $share = 'CHILD'; }

      Now the question comes down to why Storable is causing Perl to crash? Is the Storable module thread safe? Is there a thread safe alternative?

      Update:
      I have tried BrowserUk's suggestion and the problem seems to have gone away. I am currently investigating on why having require in each process after fork cures the problem.

Re: Perl forking and shared memory strangeness under Windows
by leriksen (Curate) on Feb 23, 2004 at 05:15 UTC
    Nice one, absence of a comment causes Perl to crash !!

    As a first try, check to see if B::Deparse results in the same code with and without the comment - having said that, I'm not hopeful that will reveal much, but it will discount one possible cause.

    +++++++++++++++++
    #!/usr/bin/perl
    use warnings;use strict;use brain;

Re: Perl forking and shared memory strangeness under Windows
by flyingmoose (Priest) on Feb 23, 2004 at 13:55 UTC
    Repeat to yourself.... "thou shalt not fork under Windows"...

    The whole fact that "fork doesn't really fork" should be enough to scare people away from doing it...of course, naming the method fork() doesn't seem to advertise that fact very well.

    Since this app is pure Win32 (using the Win32 memory mapped file stuff), it makes sense to remove the forking altogether...after all, forking on Win32 is pretty much a hack...could it be moved over a threaded model, with locks (if needed) where needed?

Re: Perl forking and shared memory strangeness under Windows
by xiper (Friar) on Feb 23, 2004 at 21:26 UTC
    I think you'll find your original program was crashing regardless, you just weren't seeing the error message when the comment was there (i had a similar problem with data after an __END__ token that also hid the error). Can't explain why tho'...

    The require trick mentioned above still doesn't solve the following scenario:

    use strict; require Win32::MMF::Shareable; $|++; tie( my $share, 'Win32::MMF::Shareable', 'share' ) || die; $share = 'foo'; # do some unrelated forking with $share in scope unless( fork ) { exit 0 } # make sure child exits before continuing sleep 1; # set/get crashes print "----before\n"; $share = 'bar'; my $temp = $share; print "----after\n"; __END__ ----before

    - ><iper

    use japh; print;
      Hi xiper, as BrowserUk has suggested earlier, there is a problem with forking under Windows. The cure is to create two separate instances of Shareable, one in child and one in parent. So the require should be after the fork. I modified the code to below and it ran without problems.
      use strict; $|++; # do some unrelated forking with $share in scope unless( fork ) { exit 0 } require Win32::MMF::Shareable; tie( my $share, 'Win32::MMF::Shareable', 'share' ) || die; $share = 'foo'; # make sure child exits before continuing sleep 1; # set/get crashes print "----before\n"; $share = 'bar'; my $temp = $share; print "----after\n";

        Yes, but a solution that changes the logic of a program isn't practical. You're effectivly saying that "you can't fork with a tied variable in scope" - even if the child has nothing to do with the tied variable. My point was it isn't always possible (nor should it be) to redesign a program around this 'solution'.

        - ><iper

        use japh; print;

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://331029]
Approved by jweed
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (7)
As of 2024-04-25 16:15 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found