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);
|
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) {
|
static THREAD_ENTRY _GBAThreadRun(void* context) {
|
||||||
#ifdef USE_PTHREADS
|
#ifdef USE_PTHREADS
|
||||||
pthread_once(&_contextOnce, _createTLS);
|
pthread_once(&_contextOnce, _createTLS);
|
||||||
|
@ -122,7 +128,7 @@ static THREAD_ENTRY _GBAThreadRun(void* context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MutexLock(&threadContext->stateMutex);
|
MutexLock(&threadContext->stateMutex);
|
||||||
while (threadContext->state == THREAD_PAUSED) {
|
while (threadContext->state == THREAD_PAUSED || threadContext->state == THREAD_INTERRUPTED) {
|
||||||
ConditionWait(&threadContext->stateCond, &threadContext->stateMutex);
|
ConditionWait(&threadContext->stateCond, &threadContext->stateMutex);
|
||||||
}
|
}
|
||||||
MutexUnlock(&threadContext->stateMutex);
|
MutexUnlock(&threadContext->stateMutex);
|
||||||
|
@ -239,9 +245,25 @@ void GBAThreadJoin(struct GBAThread* threadContext) {
|
||||||
free(threadContext->rewindBuffer);
|
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) {
|
void GBAThreadPause(struct GBAThread* threadContext) {
|
||||||
int frameOn = 1;
|
int frameOn = 1;
|
||||||
MutexLock(&threadContext->stateMutex);
|
MutexLock(&threadContext->stateMutex);
|
||||||
|
_waitOnInterrupt(threadContext);
|
||||||
if (threadContext->state == THREAD_RUNNING) {
|
if (threadContext->state == THREAD_RUNNING) {
|
||||||
if (threadContext->debugger && threadContext->debugger->state == DEBUGGER_RUNNING) {
|
if (threadContext->debugger && threadContext->debugger->state == DEBUGGER_RUNNING) {
|
||||||
threadContext->debugger->state = DEBUGGER_EXITING;
|
threadContext->debugger->state = DEBUGGER_EXITING;
|
||||||
|
@ -261,6 +283,7 @@ void GBAThreadPause(struct GBAThread* threadContext) {
|
||||||
void GBAThreadUnpause(struct GBAThread* threadContext) {
|
void GBAThreadUnpause(struct GBAThread* threadContext) {
|
||||||
int frameOn = 1;
|
int frameOn = 1;
|
||||||
MutexLock(&threadContext->stateMutex);
|
MutexLock(&threadContext->stateMutex);
|
||||||
|
_waitOnInterrupt(threadContext);
|
||||||
if (threadContext->state == THREAD_PAUSED) {
|
if (threadContext->state == THREAD_PAUSED) {
|
||||||
threadContext->state = THREAD_RUNNING;
|
threadContext->state = THREAD_RUNNING;
|
||||||
ConditionWake(&threadContext->stateCond);
|
ConditionWake(&threadContext->stateCond);
|
||||||
|
@ -277,6 +300,7 @@ void GBAThreadUnpause(struct GBAThread* threadContext) {
|
||||||
int GBAThreadIsPaused(struct GBAThread* threadContext) {
|
int GBAThreadIsPaused(struct GBAThread* threadContext) {
|
||||||
int isPaused;
|
int isPaused;
|
||||||
MutexLock(&threadContext->stateMutex);
|
MutexLock(&threadContext->stateMutex);
|
||||||
|
_waitOnInterrupt(threadContext);
|
||||||
isPaused = threadContext->state == THREAD_PAUSED;
|
isPaused = threadContext->state == THREAD_PAUSED;
|
||||||
MutexUnlock(&threadContext->stateMutex);
|
MutexUnlock(&threadContext->stateMutex);
|
||||||
return isPaused;
|
return isPaused;
|
||||||
|
@ -285,6 +309,7 @@ int GBAThreadIsPaused(struct GBAThread* threadContext) {
|
||||||
void GBAThreadTogglePause(struct GBAThread* threadContext) {
|
void GBAThreadTogglePause(struct GBAThread* threadContext) {
|
||||||
int frameOn = 1;
|
int frameOn = 1;
|
||||||
MutexLock(&threadContext->stateMutex);
|
MutexLock(&threadContext->stateMutex);
|
||||||
|
_waitOnInterrupt(threadContext);
|
||||||
if (threadContext->state == THREAD_PAUSED) {
|
if (threadContext->state == THREAD_PAUSED) {
|
||||||
threadContext->state = THREAD_RUNNING;
|
threadContext->state = THREAD_RUNNING;
|
||||||
ConditionWake(&threadContext->stateCond);
|
ConditionWake(&threadContext->stateCond);
|
||||||
|
|
|
@ -10,9 +10,10 @@ typedef void (*ThreadCallback)(struct GBAThread* threadContext);
|
||||||
enum ThreadState {
|
enum ThreadState {
|
||||||
THREAD_INITIALIZED = -1,
|
THREAD_INITIALIZED = -1,
|
||||||
THREAD_RUNNING = 0,
|
THREAD_RUNNING = 0,
|
||||||
THREAD_PAUSED = 1,
|
THREAD_INTERRUPTED = 1,
|
||||||
THREAD_EXITING = 2,
|
THREAD_PAUSED = 2,
|
||||||
THREAD_SHUTDOWN = 3
|
THREAD_EXITING = 3,
|
||||||
|
THREAD_SHUTDOWN = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GBASync {
|
struct GBASync {
|
||||||
|
@ -49,6 +50,7 @@ struct GBAThread {
|
||||||
|
|
||||||
Mutex stateMutex;
|
Mutex stateMutex;
|
||||||
Condition stateCond;
|
Condition stateCond;
|
||||||
|
enum ThreadState savedState;
|
||||||
|
|
||||||
GBALogHandler logHandler;
|
GBALogHandler logHandler;
|
||||||
ThreadCallback startCallback;
|
ThreadCallback startCallback;
|
||||||
|
@ -71,6 +73,9 @@ int GBAThreadHasStarted(struct GBAThread* threadContext);
|
||||||
void GBAThreadEnd(struct GBAThread* threadContext);
|
void GBAThreadEnd(struct GBAThread* threadContext);
|
||||||
void GBAThreadJoin(struct GBAThread* threadContext);
|
void GBAThreadJoin(struct GBAThread* threadContext);
|
||||||
|
|
||||||
|
void GBAThreadInterrupt(struct GBAThread* threadContext);
|
||||||
|
void GBAThreadContinue(struct GBAThread* threadContext);
|
||||||
|
|
||||||
void GBAThreadPause(struct GBAThread* threadContext);
|
void GBAThreadPause(struct GBAThread* threadContext);
|
||||||
void GBAThreadUnpause(struct GBAThread* threadContext);
|
void GBAThreadUnpause(struct GBAThread* threadContext);
|
||||||
int GBAThreadIsPaused(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) {
|
static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents* sdlContext, const struct SDL_KeyboardEvent* event) {
|
||||||
enum GBAKey key = 0;
|
enum GBAKey key = 0;
|
||||||
int isPaused = GBAThreadIsPaused(context);
|
|
||||||
switch (event->keysym.sym) {
|
switch (event->keysym.sym) {
|
||||||
case SDLK_z:
|
case SDLK_z:
|
||||||
key = GBA_KEY_A;
|
key = GBA_KEY_A;
|
||||||
|
@ -96,13 +95,9 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents
|
||||||
context->sync.audioWait = event->type != SDL_KEYDOWN;
|
context->sync.audioWait = event->type != SDL_KEYDOWN;
|
||||||
return;
|
return;
|
||||||
case SDLK_LEFTBRACKET:
|
case SDLK_LEFTBRACKET:
|
||||||
if (!isPaused) {
|
GBAThreadInterrupt(context);
|
||||||
GBAThreadPause(context);
|
|
||||||
}
|
|
||||||
GBARewind(context, 10);
|
GBARewind(context, 10);
|
||||||
if (!isPaused) {
|
GBAThreadContinue(context);
|
||||||
GBAThreadUnpause(context);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
if (event->type == SDL_KEYDOWN) {
|
if (event->type == SDL_KEYDOWN) {
|
||||||
|
@ -138,13 +133,9 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents
|
||||||
case SDLK_F8:
|
case SDLK_F8:
|
||||||
case SDLK_F9:
|
case SDLK_F9:
|
||||||
case SDLK_F10:
|
case SDLK_F10:
|
||||||
if (!isPaused) {
|
GBAThreadInterrupt(context);
|
||||||
GBAThreadPause(context);
|
|
||||||
}
|
|
||||||
GBASaveState(context->gba, event->keysym.sym - SDLK_F1);
|
GBASaveState(context->gba, event->keysym.sym - SDLK_F1);
|
||||||
if (!isPaused) {
|
GBAThreadContinue(context);
|
||||||
GBAThreadUnpause(context);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -161,13 +152,9 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLEvents
|
||||||
case SDLK_F8:
|
case SDLK_F8:
|
||||||
case SDLK_F9:
|
case SDLK_F9:
|
||||||
case SDLK_F10:
|
case SDLK_F10:
|
||||||
if (!isPaused) {
|
GBAThreadInterrupt(context);
|
||||||
GBAThreadPause(context);
|
|
||||||
}
|
|
||||||
GBALoadState(context->gba, event->keysym.sym - SDLK_F1);
|
GBALoadState(context->gba, event->keysym.sym - SDLK_F1);
|
||||||
if (!isPaused) {
|
GBAThreadContinue(context);
|
||||||
GBAThreadUnpause(context);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue