diff --git a/bochs/gui/control.cc b/bochs/gui/control.cc index cf7fd1a86..61c53d721 100644 --- a/bochs/gui/control.cc +++ b/bochs/gui/control.cc @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////// -// $Id: control.cc,v 1.56 2002-08-27 16:27:57 vruppert Exp $ +// $Id: control.cc,v 1.57 2002-08-27 18:11:13 bdenney Exp $ ///////////////////////////////////////////////////////////////////////// // // This is code for a text-mode configuration interfac. Note that this file @@ -627,7 +627,7 @@ config_interface_notify_callback (void *unused, BxEvent *event) case BX_ASYNC_EVT_SHUTDOWN_GUI: fprintf (stderr, "BX_ASYNC_EVT_SHUTDOWN_GUI\n"); return event; - case BX_ASYNC_EVT_LOG_MSG: + case BX_SYNC_EVT_LOG_ASK: { int level = event->u.logmsg.level; fprintf (stderr, "========================================================================\n"); diff --git a/bochs/gui/siminterface.cc b/bochs/gui/siminterface.cc index d4c604a8b..e2a9768d8 100644 --- a/bochs/gui/siminterface.cc +++ b/bochs/gui/siminterface.cc @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////// -// $Id: siminterface.cc,v 1.45 2002-08-26 15:31:20 bdenney Exp $ +// $Id: siminterface.cc,v 1.46 2002-08-27 18:11:13 bdenney Exp $ ///////////////////////////////////////////////////////////////////////// // // See siminterface.h for description of the siminterface concept. @@ -32,9 +32,12 @@ class bx_real_sim_c : public bx_simulator_interface_c { bx_param_c **param_registry; int registry_alloc_size; int enabled; + // save context to jump to if we must quit unexpectedly + jmp_buf *quit_context; public: bx_real_sim_c (); virtual ~bx_real_sim_c (); + virtual void set_quit_context (jmp_buf *context) { quit_context = context; } virtual int get_init_done () { return init_done; } virtual int set_init_done (int n) { init_done = n; return 0;} virtual void get_param_id_range (int *min, int *max) { @@ -136,6 +139,7 @@ bx_real_sim_c::bx_real_sim_c () param_registry = new bx_param_c* [registry_alloc_size]; for (i=0; itype = BX_ASYNC_EVT_SHUTDOWN_GUI; - sim_to_cui_event (event); - // set something that will cause the cpu loop to exit. - // or use setjmp/longjmp, or something. - //FIXME! -#endif BX_INFO (("quit_sim called")); + // use longjmp to quit cleanly, no matter where in the stack we are. + //fprintf (stderr, "using longjmp() to jump directly to the quit context!\n"); + longjmp (*quit_context, 1); + BX_PANIC (("in bx_real_sim_c::quit_sim, longjmp should never return")); #if BX_WITH_WX // in wxWindows, the whole simulator is running in a separate thread. // our only job is to end the thread as soon as possible, NOT to shut @@ -349,7 +344,7 @@ int bx_real_sim_c::log_msg (const char *prefix, int level, char *msg) { BxEvent *be = new BxEvent (); - be->type = BX_ASYNC_EVT_LOG_MSG; + be->type = BX_SYNC_EVT_LOG_ASK; be->u.logmsg.prefix = (char *)prefix; be->u.logmsg.level = level; be->u.logmsg.msg = msg; diff --git a/bochs/gui/siminterface.h b/bochs/gui/siminterface.h index 00fa74f5d..b444543b0 100644 --- a/bochs/gui/siminterface.h +++ b/bochs/gui/siminterface.h @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////// -// $Id: siminterface.h,v 1.47 2002-08-26 15:31:21 bdenney Exp $ +// $Id: siminterface.h,v 1.48 2002-08-27 18:11:13 bdenney Exp $ ///////////////////////////////////////////////////////////////////////// // // Before I can describe what this file is for, I have to make the @@ -306,6 +306,7 @@ typedef enum { BX_SYNC_EVT_GET_PARAM, // CUI -> simulator -> CUI BX_SYNC_EVT_ASK_PARAM, // simulator -> CUI -> simulator BX_SYNC_EVT_TICK, // simulator -> CUI, wait for response. + BX_SYNC_EVT_LOG_ASK, // simulator -> CUI, wait for response. __ALL_EVENTS_BELOW_ARE_ASYNC__, BX_ASYNC_EVT_KEY, // vga window -> simulator BX_ASYNC_EVT_MOUSE, // vga window -> simulator @@ -401,7 +402,7 @@ typedef struct { // some kind of "flow control" since the simulator will be able to produce // new events much faster than the gui can accept them. -// Event type: BX_ASYNC_EVT_LOG_MSG +// Event type: BX_ASYNC_EVT_LOG_MSG (unused) // // Asynchronous event from the simulator to the CUI. When a BX_PANIC, // BX_ERROR, BX_INFO, or BX_DEBUG is found in the simulator code, this @@ -421,12 +422,20 @@ typedef struct { // skip over huge bursts of log entries without allocating memory, // synchronizing threads, etc. for each. typedef struct { - // type is BX_EVT_LOG_MSG Bit8u level; char *prefix; char *msg; } BxLogMsgEvent; +// Event type: BX_SYNC_EVT_LOG_ASK +// +// This is a synchronous version of BX_ASYNC_EVT_LOG_MSG, which is used +// when the "action=ask" setting is used. If the simulator runs into a +// panic, it sends a synchronous BX_SYNC_EVT_LOG_ASK to the CUI to be +// displayed. The CUI shows a dialog that asks if the user wants to +// continue, quit, etc. and sends the answer back to the simulator. +// This event also uses BxLogMsgEvent. + // Event type: BX_EVT_TOOLBAR // Asynchronous event from the VGAW to the simulator, sent when the user // clicks on a toolbar button. This may one day become something more @@ -724,9 +733,12 @@ struct bx_cdrom_options // I'm not longer sure that having a base class is going to be of any // use... -Bryce +#include + class bx_simulator_interface_c { public: bx_simulator_interface_c (); + virtual void set_quit_context (jmp_buf *context) {} virtual int get_init_done () { return -1; } virtual int set_init_done (int n) {return -1;} virtual void get_param_id_range (int *min, int *max) {} diff --git a/bochs/gui/wxmain.cc b/bochs/gui/wxmain.cc index 260671828..650c3a9b3 100644 --- a/bochs/gui/wxmain.cc +++ b/bochs/gui/wxmain.cc @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////// -// $Id: wxmain.cc,v 1.8 2002-08-26 15:31:22 bdenney Exp $ +// $Id: wxmain.cc,v 1.9 2002-08-27 18:11:13 bdenney Exp $ ///////////////////////////////////////////////////////////////// // // wxmain.cc implements the wxWindows frame, toolbar, menus, and dialogs. @@ -314,6 +314,39 @@ void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) wxMessageBox( str, "About Bochs", wxOK | wxICON_INFORMATION ); } +// update the menu items, status bar, etc. +void MyFrame::simStatusChanged (StatusChange change, Boolean popupNotify) { + switch (change) { + case Start: // running + menuConfiguration->Enable (ID_Config_New, FALSE); + menuConfiguration->Enable (ID_Config_Read, FALSE); + menuSimulate->Enable (ID_Simulate_Start, FALSE); + menuSimulate->Enable (ID_Simulate_PauseResume, TRUE); + menuSimulate->Enable (ID_Simulate_Stop, TRUE); + menuSimulate->SetLabel (ID_Simulate_PauseResume, "&Pause"); + break; + case Stop: // not running + menuSimulate->Enable (ID_Simulate_Start, TRUE); + menuSimulate->Enable (ID_Simulate_PauseResume, FALSE); + menuSimulate->Enable (ID_Simulate_Stop, FALSE); + menuSimulate->SetLabel (ID_Simulate_PauseResume, "&Pause"); + // This should only be used if the simulation stops due to error. + // Obviously if the user asked it to stop, they don't need to be told. + if (popupNotify) + wxMessageBox("Bochs simulation has stopped.", "Bochs Stopped", + wxOK | wxICON_INFORMATION); + break; + case Pause: // pause + SetStatusText ("Pausing the Bochs simulation"); + menuSimulate->SetLabel (ID_Simulate_PauseResume, "&Resume"); + break; + case Resume: // resume + SetStatusText ("Resuming the Bochs simulation"); + menuSimulate->SetLabel (ID_Simulate_PauseResume, "&Pause"); + break; + } +} + void MyFrame::OnStartSim(wxCommandEvent& WXUNUSED(event)) { wxCriticalSectionLocker lock(sim_thread_lock); @@ -327,7 +360,7 @@ void MyFrame::OnStartSim(wxCommandEvent& WXUNUSED(event)) start_bochs_times++; if (start_bochs_times>1) { wxMessageBox ( - "You have already started the simulator once this session. Due to memory leaks, you may get unstable behavior.", + "You have already started the simulator once this session. Due to memory leaks and bugs in init code, you may get unstable behavior.", "2nd time warning", wxOK | wxICON_WARNING); } num_events = 0; // clear the queue of events for bochs to handle @@ -337,13 +370,7 @@ void MyFrame::OnStartSim(wxCommandEvent& WXUNUSED(event)) wxLogDebug ("Simulator thread has started."); // set up callback for events from simulator thread SIM->set_notify_callback (&SimThread::SiminterfaceCallback, sim_thread); - // fix up menu choices - menuConfiguration->Enable (ID_Config_New, FALSE); - menuConfiguration->Enable (ID_Config_Read, FALSE); - menuSimulate->Enable (ID_Simulate_Start, FALSE); - menuSimulate->Enable (ID_Simulate_PauseResume, TRUE); - menuSimulate->Enable (ID_Simulate_Stop, TRUE); - menuSimulate->SetLabel (ID_Simulate_PauseResume, "&Pause"); + simStatusChanged (Start); } void MyFrame::OnPauseResumeSim(wxCommandEvent& WXUNUSED(event)) @@ -351,13 +378,11 @@ void MyFrame::OnPauseResumeSim(wxCommandEvent& WXUNUSED(event)) wxCriticalSectionLocker lock(sim_thread_lock); if (sim_thread) { if (sim_thread->IsPaused ()) { - SetStatusText ("Resuming the Bochs simulation"); + simStatusChanged (Resume); sim_thread->Resume (); - menuSimulate->SetLabel (ID_Simulate_PauseResume, "&Pause"); } else { - SetStatusText ("Pausing the Bochs simulation"); + simStatusChanged (Pause); sim_thread->Pause (); - menuSimulate->SetLabel (ID_Simulate_PauseResume, "&Resume"); } } } @@ -367,13 +392,12 @@ void MyFrame::OnKillSim(wxCommandEvent& WXUNUSED(event)) // DON'T use a critical section here. Delete implicitly calls // OnSimThreadExit, which also tries to lock sim_thread_lock. // If we grab the lock at this level, deadlock results. + wxLogDebug ("OnKillSim()"); if (sim_thread) { - SetStatusText ("Killing the Bochs simulation"); - sim_thread->Delete (); - menuSimulate->Enable (ID_Simulate_Start, TRUE); - menuSimulate->Enable (ID_Simulate_PauseResume, FALSE); - menuSimulate->Enable (ID_Simulate_Stop, FALSE); - menuSimulate->SetLabel (ID_Simulate_PauseResume, "&Pause"); + sim_thread->Delete (); + // Next time the simulator reaches bx_real_sim_c::periodic() it + // will quit. This is better than killing the thread because it + // gives it a chance to clean up after itself. } } @@ -501,9 +525,9 @@ MyFrame::HandleAskParam (BxEvent *event) return -1; // could not display } -// This is called when a Sim2Cui event from the simulator thread is discovered -// on the GUI thread's event queue. (It got there via wxPostEvent in -// SiminterfaceCallback2, which is executed in the simulator Thread.) +// This is called from the wxWindows GUI thread, when a Sim2Cui event +// is found. (It got there via wxPostEvent in SiminterfaceCallback2, which is +// executed in the simulator Thread.) void MyFrame::OnSim2CuiEvent (wxCommandEvent& event) { @@ -530,12 +554,16 @@ MyFrame::OnSim2CuiEvent (wxCommandEvent& event) Close (TRUE); wxExit (); return; + case BX_SYNC_EVT_LOG_ASK: case BX_ASYNC_EVT_LOG_MSG: wxLogDebug ("log msg: level=%d, prefix='%s', msg='%s'", be->u.logmsg.level, be->u.logmsg.prefix, be->u.logmsg.msg); - wxMutexGuiEnter(); + if (be->type == BX_ASYNC_EVT_LOG_MSG) { + // don't ask for user response + return; + } string.Printf ("%s", be->u.logmsg.msg); choice = ::wxGetSingleChoiceIndex ( string, @@ -543,7 +571,7 @@ MyFrame::OnSim2CuiEvent (wxCommandEvent& event) if (choice<0) choice = 2; // treat cancel the same as "die" be->retcode = choice; wxLogDebug ("you chose %d", choice); - wxMutexGuiLeave(); + sim_thread->SendSyncResponse (be); return; default: wxLogDebug ("OnSim2CuiEvent: event type %d ignored", (int)be->type); @@ -593,7 +621,6 @@ SimThread::Entry (void) { int argc=1; char *argv[] = {"bochs"}; - wxLogDebug ("in SimThread, starting at bx_continue_after_config_interface"); // run all the rest of the Bochs simulator code. This function will // run forever, unless a "kill_bochs_request" is issued. The shutdown // procedure is as follows: @@ -608,8 +635,18 @@ SimThread::Entry (void) // bx_continue_after_config_interface(), which notices the // kill_bochs_request and returns back to this Entry() function. // - Entry() exits and the thread stops. Whew. - bx_continue_after_config_interface (argc, argv); - wxLogDebug ("in SimThread, bx_continue_after_config_interface exited"); + 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 + if (setjmp (context) == 0) { + SIM->set_quit_context (&context); + bx_continue_after_config_interface (argc, argv); + wxLogDebug ("in SimThread, bx_continue_after_config_interface exited normally"); + } else { + wxLogDebug ("in SimThread, bx_continue_after_config_interface exited by longjmp"); + } + wxMutexGuiEnter(); + theFrame->simStatusChanged (theFrame->Stop, true); + wxMutexGuiLeave(); return NULL; } @@ -672,14 +709,6 @@ SimThread::SiminterfaceCallback2 (BxEvent *event) wxevent.SetEventObject ((wxEvent *)event); wxLogDebug ("Sending an event to the window"); wxPostEvent (frame, wxevent); - if (event->type == BX_ASYNC_EVT_LOG_MSG) { - // wait until the GUI thread has processed the event and changed - // retcode. bbd: This is a strange case. Shouldn't this just be - // called a sync event? - event->retcode = -1; - while (event->retcode == -1) this->Sleep(500); - return event; - } // if it is an asynchronous event, return immediately if (async) return NULL; wxLogDebug ("SiminterfaceCallback2: synchronous event; waiting for response"); diff --git a/bochs/gui/wxmain.h b/bochs/gui/wxmain.h index 452096238..9b950dbc7 100644 --- a/bochs/gui/wxmain.h +++ b/bochs/gui/wxmain.h @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////// -// $Id: wxmain.h,v 1.4 2002-08-26 15:31:23 bdenney Exp $ +// $Id: wxmain.h,v 1.5 2002-08-27 18:11:13 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. @@ -53,6 +53,8 @@ class MyFrame: public wxFrame MyPanel *panel; public: MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size, const long style); + enum StatusChange { Start, Stop, Pause, Resume }; + void simStatusChanged (StatusChange change, Boolean popupNotify=false); void OnConfigRead(wxCommandEvent& event); void OnConfigSave(wxCommandEvent& event); void OnQuit(wxCommandEvent& event); diff --git a/bochs/main.cc b/bochs/main.cc index 8e2206b4b..a00bb0b0b 100644 --- a/bochs/main.cc +++ b/bochs/main.cc @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////// -// $Id: main.cc,v 1.122 2002-08-27 16:43:40 bdenney Exp $ +// $Id: main.cc,v 1.123 2002-08-27 18:11:13 bdenney Exp $ ///////////////////////////////////////////////////////////////////////// // // Copyright (C) 2002 MandrakeSoft S.A. @@ -1099,7 +1099,14 @@ int main (int argc, char *argv[]) bx_init_main (argc, argv); bx_do_text_config_interface (argc, argv); bx_config_interface (BX_CI_INIT); - bx_continue_after_config_interface (argc, argv); + static jmp_buf context; + if (setjmp (context) == 0) { + SIM->set_quit_context (&context); + bx_continue_after_config_interface (argc, argv); + // function returned normally + } else { + // quit via longjmp + } } #endif