Add thread-interrupt functions for having multiple threads that want to pause the GBA thread

This commit is contained in:
Jeffrey Pfau 2014-02-10 23:59:07 -08:00
parent e9c4412819
commit 4d8a00c180
3 changed files with 40 additions and 23 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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;