mirror of https://github.com/mgba-emu/mgba.git
Add thread-interrupt functions for having multiple threads that want to pause the GBA thread
This commit is contained in:
parent
e9c4412819
commit
4d8a00c180
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue