Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

"Segmentation fault after destroying window"

by mnooning (Sexton)
on Mar 07, 2006 at 21:00 UTC ( #535033=perlquestion: print w/ replies, xml ) Need Help??
mnooning has asked for the wisdom of the Perl Monks concerning the following question:

Hello,

I have a segmentation fault problem on more than one Linux variant. I
have gathered information about my problem from searching and visiting
from the URL
http://rt.cpan.org/Public/Bug/Display.html?id=16053
and some others that had to do with
"Segmentation fault after destroying non-dependent window"

The comments at those sites make it apparent that I am going about what
I do in the wrong way.

In essense, my old code has a while loop wherein I call a main menu,
amongst other things. From the main menu I get back one of many
possible choices. Each choice may or may not call other subroutines
that may or may not each invoke there own Tk pop ups. Each pop up has
it's own main window, and it's own MainLoop. When the user clicks an
"Okay" button on the popups, the main window is destroyed and I
eventually get back to the original while loop. While this works fine
on Windows, it causes segmentation faults in a number of Linux
variants. It is the equivalent of having the code below:

my $count = 0; my $message = "Get a Segmentation fault within 20 clicks of Okay: "; my $answer = "Okay"; while ($answer eq "okay") { pop_up_a_message($message . $count); $answer = return_exit_if_count_gt_5($count++); }

I tried a simple redesign wherein I first instantiate a MainWindow
($mw), hiding it right away. I changed the routine
pop_up_a_message to send in $mw as well as the $message, and within
pop_up_a_message I have the statement

$we_top = $mw->Toplevel();

I then use $we_top to instantiate the pop up Label (which has the
message) and an "Okay" button. When the user clicks the Okay button
in my pop_up_a_message() routine, $we_top gets destroyed and the
pop_up_a_message() routine returns.

At first I had the "MainLoop;" in the pop_up_a_message() routine. I
forgot that it would not work because even though $we_top was
destroyed when the user clicked the Okay button, the MainWindow was
still alive, and hence would not get past the Mainloop of the
pop_up_a_message() routine. I next moved the MainLoop statement to
after the end of the while loop. I immediately got 5 pop ups, so that
would not work either.

I then moved the "MainLoop;" statement to be the last statement within
the while loop. I got the first pop up, but then no more since $mw is
still alive. It will not get past the MainLoop.

So ... how does one be able to have a program with pop ups at
different times, in different places, given widely varying user
responses. A lot of these popups have Yes/No and other answers that
need to get returned.

Just to be complete, the segmentation fault code that I posted on the
other forums is shown below.

#!/usr/bin/perl -w # File test_pop_up_a_message.pl use Tk; use strict; our $answer = "okay"; ############ sub response { my ($we_top, $button_response) = @_; $we_top->destroy; $answer = $button_response; } ############ sub pop_up_a_message { my ($message) = @_; my $okay_button; my $exit_button; print("Can allways see\n"); my $we_top = new MainWindow; print("Cannot see if Segmentation fault\n"); $we_top->Label ( -text => $message)->pack(); #......... $okay_button = $we_top->Button( -text => 'Okay', -command => [ \&response, $we_top, 'okay' ] )->pack(); #......... $exit_button = $we_top->Button( -text => 'Exit', -command => [ \&response, $we_top, 'exit' ] )->pack(); #......... $we_top->MainLoop; } ############ my $message = ""; my $count = 1; while ($answer eq "okay") { $message = "On at least Slackware and Mandriva, Perl 5.8.7 or 5.8.8, this code +will\n" . " get a Segmentation fault within 20 clicks of Okay \n " . $count++ . "\n"; pop_up_a_message($message); print ("You pressed $answer\n"); }

Any ideas?

Thanks

Edited by planetscape - added readmore tags

Comment on "Segmentation fault after destroying window"
Select or Download Code
Re: "Segmentation fault after destroying window"
by zentara (Archbishop) on Mar 07, 2006 at 21:38 UTC
    Hi, Elsewhere I told you that your "bug" is actually a design flaw, where you repeatedly create and destroy the event-loop (mainwindow), in a loop. You are "hoping" that the event loop can recreate another one, before your destroy takes effect. This will depend on the timing going on in the system, and is why you get sporadic results.

    So here is an outline of the way to do it ( others may have similar solutions). Basically you need to only create the mainwindow once, then use Dialogs to ask your questions. This way the mainloop will run solid until you hit the exit button.

    I only put rudimentary logic into the analyze_results sub, but your should be able to see the way to analyze your results, and ask new questions.

    #!/usr/bin/perl use warnings; use strict; use Tk; require Tk::Dialog; my $result = 'Starting'; my $we_top = new MainWindow; my $message = "Cannot see if Segmentation fault\n"; my $count = 1; $we_top->Label ( -text => $message)->pack(); my $count_lab = $we_top->Label ( -textvariable => \$count)->pack(); my $okay_button = $we_top->Button( -text => 'Get Response', -command => [\&get_response, $result] )->pack(); my $exit_button = $we_top->Button( -text => 'Exit', -command => sub {exit} )->pack(); $we_top->MainLoop; ########################################## sub analyze_response { my $answer = shift; if( $answer eq 'Yes' ){ $result = "Continue at count $count ?"; } if( $answer eq 'No' ){ $result = "Rerun ?"; } if( $answer eq 'Cancel' ){ $result = "Cancelled ?"; } } ########################################### sub get_response { my $answer = do_dialog(); $count++; print "$answer\n"; &analyze_response( $answer ); } ####################################### sub do_dialog { my $dlg = $we_top->Dialog( -title=>"Here is a question for you.", -buttons => ["Cancel", "No", "Yes"], -default_button => "No", -text => $result, -font => "Helvetica" ); my $return = $dlg->Show(); return $return; } __END__

    I'm not really a human, but I play one on earth. flash japh
Re: "Segmentation fault after destroying window"
by mnooning (Sexton) on Mar 15, 2006 at 21:37 UTC
    I am redesigning so that all of the windows are now based on their own
    Toplevel, which of course are all off of the one, single MainWindow.
    When a window is needed, I will simply use the "Popup" command. Otherwise
    the withdraw command will keep it hidden. A small proof of concept
    program I have showed it to work.

    There will be about 18 windows (some are pretty complicated) that will
    be staying in existence througout the life of the program. Most of
    the other windows (trivial popups) will use your suggested Dialog.
    A lot of extra memory may be taken up by the program, but it should
    work. Thanks for the tip.

    I am now a little scared to implement the redesign in the real program
    at work. It is a pretty big program. I would hate to spend the
    couple of weeks needed just to find out it won't work. My fear is
    that third party modules that I use, such as Tk::FileSelect, will lead
    me to the "Segmentation Fault" because it obviously pops up a
    mini-browser, and when done, destroys it.

    I notice in the module Fileselect the author uses this call:

    Tk::DialogWrapper('fileselect',$cmd, %args);<br>

    I could not find any documentation for Tk::DialogWrapper but in
    file Tk.pm, sub DialogWrapper has the line

    my $w = delete $args{'-parent'};<br>

    Further in sub DialogWrapper, this line appears

    $w->destroy if $created;<br>

    Ouch!

    The var $created becomes 1 (and we created a new MainWindow) if $w is
    undefined after the afforementioned line. This is important because
    it would seem to ruin my chances of success here.

    Equally bad, the parameters passed in to DialogWrapper are

    my ($method,$kind,%args) = @_;<br>

    and I do not know what the parameters are really for, or how to use
    them. Nor do I have a clue as to why deleting '-parent' from the
    %args hash should cause a new MainWindow to be created.

    Is there some documentation that can explain this? I have, and read
    most of, Mastering Perl/Tk, but it does not touch upon it. Is there
    another book I can purchase that can explain it. Neither google,
    dogpile or search.cpan.org seemed to help.

    I wonder, could it be possible to wrap all third-party modules that
    pop up something, cpan or otherwise, in a so-called DialogWrapper?

    All this could be avoided if there were just some way to tell if
    the $mw->destroy command was really behind-the-scenes finished, so
    that when a new MainWindow was needed, my program could be free to
    just go ahead and create one. I tried Exists($mw), but Exists passes
    sometimes even when the previous $mw->destroy seems done.

    Thanks

      I have another answer I can live with a little easier. I wrote another
      proof of concept script wherein the MainWindow is kept as mentioned before.
      It looks like I can create and destroy Toplevel windows as I need to,
      while keeping the MainWindow withdrawn.

      This works without getting a segmentation fault:

      sub service_for_mw_button_press { my ($mw) = shift; my $top_level = $mw->Toplevel

      and then later, when I no longer need the $top_level,

      $top_level->destroy; undef($top_level); $mw->deiconify; $mw_raise;

      This idea, plus a redesign to make the real program an event driven
      design from the beginning, should do the job. Thanks for all of your
      help.

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (13)
As of 2014-09-30 19:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (383 votes), past polls