diff --git a/src/gba/gba-thread.c b/src/gba/gba-thread.c index 00e189c38..56a5555bd 100644 --- a/src/gba/gba-thread.c +++ b/src/gba/gba-thread.c @@ -37,6 +37,12 @@ static void _changeState(struct GBAThread* threadContext, enum ThreadState newSt MutexUnlock(&threadContext->stateMutex); } +static void _waitOnInterrupt(struct GBAThread* threadContext) { + while (threadContext->state == THREAD_INTERRUPTED) { + ConditionWait(&threadContext->stateCond, &threadContext->stateMutex); + } +} + static THREAD_ENTRY _GBAThreadRun(void* context) { #ifdef USE_PTHREADS pthread_once(&_contextOnce, _createTLS); @@ -122,7 +128,7 @@ static THREAD_ENTRY _GBAThreadRun(void* context) { } } MutexLock(&threadContext->stateMutex); - while (threadContext->state == THREAD_PAUSED) { + while (threadContext->state == THREAD_PAUSED || threadContext->state == THREAD_INTERRUPTED) { ConditionWait(&threadContext->stateCond, &threadContext->stateMutex); } MutexUnlock(&threadContext->stateMutex); @@ -239,9 +245,25 @@ void GBAThreadJoin(struct GBAThread* threadContext) { free(threadContext->rewindBuffer); } +void GBAThreadInterrupt(struct GBAThread* threadContext) { + MutexLock(&threadContext->stateMutex); + _waitOnInterrupt(threadContext); + threadContext->savedState = threadContext->state; + threadContext->state = THREAD_INTERRUPTED; + if (threadContext->debugger && threadContext->debugger->state == DEBUGGER_RUNNING) { + threadContext->debugger->state = DEBUGGER_EXITING; + } + MutexUnlock(&threadContext->stateMutex); +} + +void GBAThreadContinue(struct GBAThread* threadContext) { + _changeState(threadContext, threadContext->savedState, 1); +} + void GBAThreadPause(struct GBAThread* threadContext) { int frameOn = 1; MutexLock(&threadContext->stateMutex); + _waitOnInterrupt(threadContext); if (threadContext->state == THREAD_RUNNING) { if (threadContext->debugger && threadContext->debugger->state == DEBUGGER_RUNNING) { threadContext->debugger->state = DEBUGGER_EXITING; @@ -261,6 +283,7 @@ void GBAThreadPause(struct GBAThread* threadContext) { void GBAThreadUnpause(struct GBAThread* threadContext) { int frameOn = 1; MutexLock(&threadContext->stateMutex); + _waitOnInterrupt(threadContext); if (threadContext->state == THREAD_PAUSED) { threadContext->state = THREAD_RUNNING; ConditionWake(&threadContext->stateCond); @@ -277,6 +300,7 @@ void GBAThreadUnpause(struct GBAThread* threadContext) { int GBAThreadIsPaused(struct GBAThread* threadContext) { int isPaused; MutexLock(&threadContext->stateMutex); + _waitOnInterrupt(threadContext); isPaused = threadContext->state == THREAD_PAUSED; MutexUnlock(&threadContext->stateMutex); return isPaused; @@ -285,6 +309,7 @@ int GBAThreadIsPaused(struct GBAThread* threadContext) { void GBAThreadTogglePause(struct GBAThread* threadContext) { int frameOn = 1; MutexLock(&threadContext->stateMutex); + _waitOnInterrupt(threadContext); if (threadContext->state == THREAD_PAUSED) { threadContext->state = THREAD_RUNNING; ConditionWake(&threadContext->stateCond); diff --git a/src/gba/gba-thread.h b/src/gba/gba-thread.h index 99352ee59..b19432f3c 100644 --- a/src/gba/gba-thread.h +++ b/src/gba/gba-thread.h @@ -10,9 +10,10 @@ typedef void (*ThreadCallback)(struct GBAThread* threadContext); enum ThreadState { THREAD_INITIALIZED = -1, THREAD_RUNNING = 0, - THREAD_PAUSED = 1, - THREAD_EXITING = 2, - THREAD_SHUTDOWN = 3 + THREAD_INTERRUPTED = 1, + THREAD_PAUSED = 2, + THREAD_EXITING = 3, + THREAD_SHUTDOWN = 4 }; struct GBASync { @@ -49,6 +50,7 @@ struct GBAThread { Mutex stateMutex; Condition stateCond; + enum ThreadState savedState; GBALogHandler logHandler; ThreadCallback startCallback; @@ -71,6 +73,9 @@ int GBAThreadHasStarted(struct GBAThread* threadContext); void GBAThreadEnd(struct GBAThread* threadContext); void GBAThreadJoin(struct GBAThread* threadContext); +void GBAThreadInterrupt(struct GBAThread* threadContext); +void GBAThreadContinue(struct GBAThread* threadContext); + void GBAThreadPause(struct GBAThread* threadContext); void GBAThreadUnpause(struct GBAThread* threadContext); int GBAThreadIsPaused(struct GBAThread* threadContext); diff --git a/src/platform/sdl/sdl-events.c b/src/platform/sdl/sdl-events.c index 00de89561..af20fc3ec 100644 --- a/src/platform/sdl/sdl-events.c +++ b/src/platform/sdl/sdl-events.c @@ -55,7 +55,6 @@ static void _pauseAfterFrame(struct GBAThread* context) { static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_KeyboardEvent* event) { enum GBAKey key = 0; - int isPaused = GBAThreadIsPaused(context); switch (event->keysym.sym) { case SDLK_z: key = GBA_KEY_A; @@ -96,13 +95,9 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents context->sync.audioWait = event->type != SDL_KEYDOWN; return; case SDLK_LEFTBRACKET: - if (!isPaused) { - GBAThreadPause(context); - } + GBAThreadInterrupt(context); GBARewind(context, 10); - if (!isPaused) { - GBAThreadUnpause(context); - } + GBAThreadContinue(context); return; default: if (event->type == SDL_KEYDOWN) { @@ -138,13 +133,9 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents case SDLK_F8: case SDLK_F9: case SDLK_F10: - if (!isPaused) { - GBAThreadPause(context); - } + GBAThreadInterrupt(context); GBASaveState(context->gba, event->keysym.sym - SDLK_F1); - if (!isPaused) { - GBAThreadUnpause(context); - } + GBAThreadContinue(context); break; default: break; @@ -161,13 +152,9 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents case SDLK_F8: case SDLK_F9: case SDLK_F10: - if (!isPaused) { - GBAThreadPause(context); - } + GBAThreadInterrupt(context); GBALoadState(context->gba, event->keysym.sym - SDLK_F1); - if (!isPaused) { - GBAThreadUnpause(context); - } + GBAThreadContinue(context); break; default: break;