From b97bf287b2b4e4e4c1978df16fc4cedcea6e3856 Mon Sep 17 00:00:00 2001 From: mjbudd77 Date: Sun, 2 May 2021 19:45:36 -0400 Subject: [PATCH] Bug fix for Qt GUI when closing ROM while the emulation thread is haning on a breakpoint. Now the thread is allowed to complete its frame so that it is idle with a minimal call stack before the ROM is closed. This prevents the emulation thread from coming out of its breakpoint wait loop at attempting to continue running its frame with no ROM data loaded. This fixes a segmentation fault crash that was mentioned in the project Qt issues thread. --- src/drivers/Qt/ConsoleDebugger.cpp | 16 ++++++++++++++-- src/drivers/Qt/ConsoleDebugger.h | 2 ++ src/drivers/Qt/ConsoleWindow.cpp | 1 + src/drivers/Qt/fceuWrapper.cpp | 25 ++++++++++++++++++++++++- 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/drivers/Qt/ConsoleDebugger.cpp b/src/drivers/Qt/ConsoleDebugger.cpp index 50cf140c..42c96b30 100644 --- a/src/drivers/Qt/ConsoleDebugger.cpp +++ b/src/drivers/Qt/ConsoleDebugger.cpp @@ -76,6 +76,7 @@ static std::list dbgWinList; static void DeleteBreak(int sel); static bool waitingAtBp = false; +static bool bpDebugEnable = true; static int lastBpIdx = 0; //---------------------------------------------------------------------------- ConsoleDebugger::ConsoleDebugger(QWidget *parent) @@ -2565,11 +2566,16 @@ void ConsoleDebugger::vbarChanged(int value) asmView->setLine( value ); } //---------------------------------------------------------------------------- +void bpDebugSetEnable(bool val) +{ + bpDebugEnable = val; +} +//---------------------------------------------------------------------------- void FCEUD_DebugBreakpoint( int bpNum ) { std::list ::iterator it; - if ( !nes_shm->runEmulator ) + if ( !nes_shm->runEmulator || !bpDebugEnable ) { return; } @@ -2585,7 +2591,8 @@ void FCEUD_DebugBreakpoint( int bpNum ) (*it)->breakPointNotify( bpNum ); } - while ( nes_shm->runEmulator && FCEUI_EmulationPaused() && !FCEUI_EmulationFrameStepped()) + while ( nes_shm->runEmulator && bpDebugEnable && + FCEUI_EmulationPaused() && !FCEUI_EmulationFrameStepped()) { // HACK: break when Frame Advance is pressed extern bool frameAdvanceRequested; @@ -2617,6 +2624,11 @@ bool debuggerWindowIsOpen(void) return (dbgWinList.size() > 0); } //---------------------------------------------------------------------------- +bool debuggerWaitingAtBreakpoint(void) +{ + return waitingAtBp; +} +//---------------------------------------------------------------------------- void updateAllDebuggerWindows( void ) { std::list ::iterator it; diff --git a/src/drivers/Qt/ConsoleDebugger.h b/src/drivers/Qt/ConsoleDebugger.h index 20f9a1a4..ff9a78d4 100644 --- a/src/drivers/Qt/ConsoleDebugger.h +++ b/src/drivers/Qt/ConsoleDebugger.h @@ -344,6 +344,8 @@ class ConsoleDebugger : public QDialog }; bool debuggerWindowIsOpen(void); +bool debuggerWaitingAtBreakpoint(void); +void bpDebugSetEnable(bool val); void saveGameDebugBreakpoints(void); void loadGameDebugBreakpoints(void); void debuggerClearAllBreakpoints(void); diff --git a/src/drivers/Qt/ConsoleWindow.cpp b/src/drivers/Qt/ConsoleWindow.cpp index d86b3e3c..3cf32881 100644 --- a/src/drivers/Qt/ConsoleWindow.cpp +++ b/src/drivers/Qt/ConsoleWindow.cpp @@ -48,6 +48,7 @@ #include "../../input.h" #include "../../movie.h" #include "../../version.h" +#include "common/os_utils.h" #ifdef _S9XLUA_H #include "../../fceulua.h" diff --git a/src/drivers/Qt/fceuWrapper.cpp b/src/drivers/Qt/fceuWrapper.cpp index 20c86a9d..c8be7e51 100644 --- a/src/drivers/Qt/fceuWrapper.cpp +++ b/src/drivers/Qt/fceuWrapper.cpp @@ -381,9 +381,32 @@ CloseGame(void) { std::string filename; - if(!isloaded) { + if (!isloaded) { return(0); } + + // If the emulation thread is stuck hanging at a breakpoint, + // disable breakpoint debugging and wait for the thread to + // complete its frame. So that it is idle with a minimal call + // stack when we close the ROM. After thread has completed the + // frame, it is then safe to re-enable breakpoint debugging. + if ( debuggerWaitingAtBreakpoint() ) + { + bpDebugSetEnable(false); + + if ( fceuWrapperIsLocked() ) + { + fceuWrapperUnLock(); + msleep(100); + fceuWrapperLock(); + } + else + { + msleep(100); + } + bpDebugSetEnable(true); + } + hexEditorSaveBookmarks(); saveGameDebugBreakpoints(); debuggerClearAllBreakpoints();