- I was getting occasional thread bugs and crashes when I click on
Quit while the simulation was running. I used to just do wxFrame::Close(TRUE) in the wxwindows thread, but the simulation thread would keep on running even after the window had disappeared. If the simulation thread sent any messages to the gui, it could segfault. Now, when you click on Quit it asks the simulator to quit, but does not close the gui. When the simulator thread finally quits, THEN it calls wxFrame::Close(TRUE) from the sim_thread (with appropriate gui mutex). Such tricks are only needed when the simulation is running. I hope this will fix bug #616142: "wx: crash from events after gui shutdown". - move MyFrame::closing flag out into a global variable wxBochsClosing so that it will be valid even when the MyFrame is deleted. See comments on in wxmain.h. - when wxBochsClosing is set, don't create any new windows. If any errors appear, just print them to stderr because the gui is just about to be closed. - fix comment in SimThread::Entry to talk about longjmp instead of kill_bochs_request - (minor) move contents of DefaultCallback2 into DefaultCallback. It doesn't refer to the wxApp at all. This is a bit safer in case it gets called when the wxApp is in the process of being deleted. - modified: gui/wxmain.cc gui/wxmain.h
This commit is contained in:
parent
d7a16521c4
commit
84c33ec824
@ -1,5 +1,5 @@
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// $Id: wxmain.cc,v 1.63 2002-10-06 19:21:05 bdenney Exp $
|
||||
// $Id: wxmain.cc,v 1.64 2002-10-07 04:00:59 bdenney Exp $
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// wxmain.cc implements the wxWindows frame, toolbar, menus, and dialogs.
|
||||
@ -73,6 +73,21 @@
|
||||
MyFrame *theFrame = NULL;
|
||||
MyPanel *thePanel = NULL;
|
||||
|
||||
// The wxBochsClosing flag is used to keep track of when the wxWindows GUI is
|
||||
// shutting down. Shutting down can be somewhat complicated because the
|
||||
// simulation may be running for a while in another thread before it realizes
|
||||
// that it should shut down. The wxBochsClosing flag is a global variable, as
|
||||
// opposed to a field of some C++ object, so that it will be valid at any stage
|
||||
// of the program. wxBochsClosing starts out false (not wxBochsClosing). When
|
||||
// the GUI decides to shut down, it sets wxBochsClosing=true. If there
|
||||
// is not a simulation running, everything is quite simple and it can just
|
||||
// call Close(TRUE). If a simulation is running, it calls OnKillSim to
|
||||
// ask the simulation to stop. When the simulation thread stops, it calls
|
||||
// Close(TRUE) on the frame. During the time that the simulation is
|
||||
// still running and afterward, the wxBochsClosing flag is used to suppress
|
||||
// any events that might reference parts of the GUI or create new dialogs.
|
||||
bool wxBochsClosing = false;
|
||||
|
||||
bool isSimThread () {
|
||||
wxThread *current = wxThread::This ();
|
||||
if (current == (wxThread*) theFrame->GetSimThread ()) {
|
||||
@ -96,7 +111,6 @@ virtual int OnExit();
|
||||
// so that events coming from the simulator code can be handled.
|
||||
// The primary culprit is panics which cause an BX_SYNC_EVT_LOG_ASK.
|
||||
static BxEvent *DefaultCallback (void *thisptr, BxEvent *event);
|
||||
BxEvent *DefaultCallback2 (BxEvent *event);
|
||||
};
|
||||
|
||||
// SimThread is the thread in which the Bochs simulator runs. It is created
|
||||
@ -172,31 +186,32 @@ int MyApp::OnExit ()
|
||||
BxEvent *
|
||||
MyApp::DefaultCallback (void *thisptr, BxEvent *event)
|
||||
{
|
||||
MyApp *me = (MyApp *)thisptr;
|
||||
// call the normal non-static method now that we know the this pointer.
|
||||
return me->DefaultCallback2 (event);
|
||||
}
|
||||
|
||||
BxEvent *
|
||||
MyApp::DefaultCallback2 (BxEvent *event)
|
||||
{
|
||||
wxLogDebug ("DefaultCallback2: event type %d", event->type);
|
||||
wxLogDebug ("DefaultCallback: event type %d", event->type);
|
||||
event->retcode = -1; // default return code
|
||||
switch (event->type)
|
||||
{
|
||||
case BX_ASYNC_EVT_LOG_MSG:
|
||||
case BX_SYNC_EVT_LOG_ASK: {
|
||||
wxLogDebug ("DefaultCallback2: log ask event");
|
||||
wxLogDebug ("DefaultCallback: log ask event");
|
||||
wxString text;
|
||||
text.Printf ("Error: %s", event->u.logmsg.msg);
|
||||
wxMessageBox (text, "Error", wxOK | wxICON_ERROR );
|
||||
// maybe I can make OnLogMsg display something that looks appropriate.
|
||||
// theFrame->OnLogMsg (event);
|
||||
event->retcode = BX_LOG_ASK_CHOICE_CONTINUE;
|
||||
if (wxBochsClosing) {
|
||||
// gui closing down, do something simple and nongraphical.
|
||||
fprintf (stderr, "%s\n", text.c_str ());
|
||||
} else {
|
||||
wxMessageBox (text, "Error", wxOK | wxICON_ERROR );
|
||||
// maybe I can make OnLogMsg display something that looks appropriate.
|
||||
// theFrame->OnLogMsg (event);
|
||||
}
|
||||
event->retcode = BX_LOG_ASK_CHOICE_DIE;
|
||||
// There is only one thread at this point. if I choose DIE here, it will
|
||||
// call fatal() and kill the whole app.
|
||||
break;
|
||||
}
|
||||
case BX_SYNC_EVT_TICK:
|
||||
if (wxBochsClosing)
|
||||
event->retcode = -1;
|
||||
break;
|
||||
case BX_ASYNC_EVT_REFRESH:
|
||||
case BX_ASYNC_EVT_DBG_MSG:
|
||||
break; // ignore
|
||||
@ -204,7 +219,7 @@ MyApp::DefaultCallback2 (BxEvent *event)
|
||||
case BX_SYNC_EVT_GET_DBG_COMMAND:
|
||||
break; // ignore
|
||||
default:
|
||||
wxLogDebug ("unknown event type %d", event->type);
|
||||
wxLogDebug ("DefaultCallback: unknown event type %d", event->type);
|
||||
}
|
||||
if (BX_EVT_IS_ASYNC(event->type)) {
|
||||
delete event;
|
||||
@ -213,7 +228,6 @@ MyApp::DefaultCallback2 (BxEvent *event)
|
||||
return event;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// MyFrame: the top level frame for the Bochs application
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@ -323,7 +337,6 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size,
|
||||
// init variables
|
||||
sim_thread = NULL;
|
||||
start_bochs_times = 0;
|
||||
closing = false;
|
||||
showCpu = NULL;
|
||||
showKbd = NULL;
|
||||
debugCommand = NULL;
|
||||
@ -859,13 +872,16 @@ MyFrame::DebugCommand (const char *cmd)
|
||||
|
||||
void MyFrame::OnQuit(wxCommandEvent& event)
|
||||
{
|
||||
closing = true;
|
||||
Close( TRUE );
|
||||
OnKillSim (event);
|
||||
#if 0
|
||||
if (SIM)
|
||||
SIM->quit_sim(0); // give bochs a chance to shut down
|
||||
#endif
|
||||
wxBochsClosing = true;
|
||||
if (!sim_thread) {
|
||||
// no simulation thread is running. Just close the window.
|
||||
Close( TRUE );
|
||||
} else {
|
||||
SIM->set_notify_callback (&MyApp::DefaultCallback, this);
|
||||
// ask the simulator to stop. When it stops it will close this frame.
|
||||
SetStatusText ("Waiting for simulation to stop...");
|
||||
OnKillSim (event);
|
||||
}
|
||||
}
|
||||
|
||||
void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
|
||||
@ -1372,11 +1388,9 @@ SimThread::Entry (void)
|
||||
// - sim continues to run until the next time it reaches SIM->periodic().
|
||||
// - SIM->periodic() sends a synchronous tick event to the GUI, which
|
||||
// finally calls TestDestroy() and realizes it needs to stop. It
|
||||
// sets the sync event return code to -1. SIM->periodic() sets the
|
||||
// kill_bochs_request flag in cpu #0.
|
||||
// - cpu loop notices kill_bochs_request and returns to main.cc:
|
||||
// bx_continue_after_config_interface(), which notices the
|
||||
// kill_bochs_request and returns back to this Entry() function.
|
||||
// sets the sync event return code to -1. SIM->periodic() notices
|
||||
// the -1 and calls quit_sim, which longjumps to quit_context, which is
|
||||
// right here in SimThread::Entry.
|
||||
// - Entry() exits and the thread stops. Whew.
|
||||
wxLogDebug ("in SimThread, starting at bx_continue_after_config_interface");
|
||||
static jmp_buf context; // this must not go out of scope. maybe static not needed
|
||||
@ -1392,11 +1406,18 @@ SimThread::Entry (void)
|
||||
SIM->set_quit_context (NULL);
|
||||
// it is possible that the whole interface has already been shut down.
|
||||
// If so, we must end immediately.
|
||||
if (!theFrame->IsClosing ()) {
|
||||
wxMutexGuiEnter();
|
||||
// we're in the sim thread, so we must get a gui mutex before calling
|
||||
// wxwindows methods.
|
||||
wxLogDebug ("SimThread::Entry: get gui mutex");
|
||||
wxMutexGuiEnter();
|
||||
if (!wxBochsClosing) {
|
||||
wxLogDebug ("SimThread::Entry: sim thread ending. call simStatusChanged");
|
||||
theFrame->simStatusChanged (theFrame->Stop, true);
|
||||
wxMutexGuiLeave();
|
||||
} else {
|
||||
wxLogMessage ("SimThread::Entry: the gui is waiting for sim to finish. Now that it has finished, I will close the frame.");
|
||||
theFrame->Close (TRUE);
|
||||
}
|
||||
wxMutexGuiLeave();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// $Id: wxmain.h,v 1.31 2002-09-25 18:40:15 bdenney Exp $
|
||||
// $Id: wxmain.h,v 1.32 2002-10-07 04:01:00 bdenney Exp $
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// This file defines variables and classes that the wxWindows .cc files
|
||||
// share. It should be included only by wx.cc and wxmain.cc.
|
||||
@ -16,6 +16,9 @@ class ParamDialog;
|
||||
extern MyFrame *theFrame;
|
||||
extern MyPanel *thePanel;
|
||||
|
||||
// wxBochsClosing flag, see comments in wxmain.h
|
||||
extern bool wxBochsClosing;
|
||||
|
||||
#define MAX_EVENTS 256
|
||||
extern unsigned long num_events;
|
||||
extern BxEvent event_queue[MAX_EVENTS];
|
||||
@ -156,15 +159,10 @@ private:
|
||||
class MyFrame: public wxFrame
|
||||
{
|
||||
MyPanel *panel;
|
||||
// closing is set as soon as the Close(TRUE) is called. This informs any
|
||||
// actions that may occur after the closing of the frame, so that they can
|
||||
// quit A.S.A.P.
|
||||
bool closing;
|
||||
public:
|
||||
MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size, const long style);
|
||||
~MyFrame();
|
||||
enum StatusChange { Start, Stop, Pause, Resume };
|
||||
bool IsClosing () { return closing; }
|
||||
void simStatusChanged (StatusChange change, Boolean popupNotify=false);
|
||||
void OnConfigNew(wxCommandEvent& event);
|
||||
void OnConfigRead(wxCommandEvent& event);
|
||||
|
Loading…
x
Reference in New Issue
Block a user