GBA Thread: Make GBAThreadInterrupt and -Continue check for the thread status, resolving several deadlocks

This commit is contained in:
Jeffrey Pfau 2014-11-09 20:31:24 -08:00
parent 6e62ba8bb2
commit d83520c5a2
4 changed files with 24 additions and 27 deletions

View File

@ -426,10 +426,14 @@ void GBAThreadJoin(struct GBAThread* threadContext) {
} }
} }
bool GBAThreadIsActive(struct GBAThread* threadContext) {
return threadContext->state >= THREAD_RUNNING && threadContext->state < THREAD_EXITING;
}
void GBAThreadInterrupt(struct GBAThread* threadContext) { void GBAThreadInterrupt(struct GBAThread* threadContext) {
MutexLock(&threadContext->stateMutex); MutexLock(&threadContext->stateMutex);
++threadContext->interruptDepth; ++threadContext->interruptDepth;
if (threadContext->interruptDepth > 1) { if (threadContext->interruptDepth > 1 || !GBAThreadIsActive(threadContext)) {
MutexUnlock(&threadContext->stateMutex); MutexUnlock(&threadContext->stateMutex);
return; return;
} }
@ -447,7 +451,7 @@ void GBAThreadInterrupt(struct GBAThread* threadContext) {
void GBAThreadContinue(struct GBAThread* threadContext) { void GBAThreadContinue(struct GBAThread* threadContext) {
MutexLock(&threadContext->stateMutex); MutexLock(&threadContext->stateMutex);
--threadContext->interruptDepth; --threadContext->interruptDepth;
if (threadContext->interruptDepth < 1) { if (threadContext->interruptDepth < 1 && GBAThreadIsActive(threadContext)) {
threadContext->state = threadContext->savedState; threadContext->state = threadContext->savedState;
ConditionWake(&threadContext->stateCond); ConditionWake(&threadContext->stateCond);
} }

View File

@ -104,6 +104,7 @@ void GBAThreadEnd(struct GBAThread* threadContext);
void GBAThreadReset(struct GBAThread* threadContext); void GBAThreadReset(struct GBAThread* threadContext);
void GBAThreadJoin(struct GBAThread* threadContext); void GBAThreadJoin(struct GBAThread* threadContext);
bool GBAThreadIsActive(struct GBAThread* threadContext);
void GBAThreadInterrupt(struct GBAThread* threadContext); void GBAThreadInterrupt(struct GBAThread* threadContext);
void GBAThreadContinue(struct GBAThread* threadContext); void GBAThreadContinue(struct GBAThread* threadContext);

View File

@ -52,14 +52,18 @@ void Display::startDrawing(const uint32_t* buffer, GBAThread* thread) {
void Display::stopDrawing() { void Display::stopDrawing() {
if (m_drawThread) { if (m_drawThread) {
if (GBAThreadIsActive(m_context)) {
GBAThreadInterrupt(m_context); GBAThreadInterrupt(m_context);
GBASyncSuspendDrawing(&m_context->sync); GBASyncSuspendDrawing(&m_context->sync);
}
QMetaObject::invokeMethod(m_painter, "stop", Qt::BlockingQueuedConnection); QMetaObject::invokeMethod(m_painter, "stop", Qt::BlockingQueuedConnection);
m_drawThread->exit(); m_drawThread->exit();
m_drawThread = nullptr; m_drawThread = nullptr;
if (GBAThreadIsActive(m_context)) {
GBASyncResumeDrawing(&m_context->sync); GBASyncResumeDrawing(&m_context->sync);
GBAThreadContinue(m_context); GBAThreadContinue(m_context);
} }
}
} }
void Display::forceDraw() { void Display::forceDraw() {

View File

@ -250,13 +250,9 @@ void GameController::setAudioBufferSamples(int samples) {
} }
void GameController::setFPSTarget(float fps) { void GameController::setFPSTarget(float fps) {
if (m_gameOpen) {
GBAThreadInterrupt(&m_threadContext); GBAThreadInterrupt(&m_threadContext);
m_threadContext.fpsTarget = fps; m_threadContext.fpsTarget = fps;
GBAThreadContinue(&m_threadContext); GBAThreadContinue(&m_threadContext);
} else {
m_threadContext.fpsTarget = fps;
}
QMetaObject::invokeMethod(m_audioProcessor, "inputParametersChanged"); QMetaObject::invokeMethod(m_audioProcessor, "inputParametersChanged");
} }
@ -315,23 +311,15 @@ void GameController::setTurbo(bool set, bool forced) {
} }
void GameController::setAVStream(GBAAVStream* stream) { void GameController::setAVStream(GBAAVStream* stream) {
if (m_gameOpen) {
GBAThreadInterrupt(&m_threadContext); GBAThreadInterrupt(&m_threadContext);
m_threadContext.stream = stream; m_threadContext.stream = stream;
GBAThreadContinue(&m_threadContext); GBAThreadContinue(&m_threadContext);
} else {
m_threadContext.stream = stream;
}
} }
void GameController::clearAVStream() { void GameController::clearAVStream() {
if (m_gameOpen) {
GBAThreadInterrupt(&m_threadContext); GBAThreadInterrupt(&m_threadContext);
m_threadContext.stream = nullptr; m_threadContext.stream = nullptr;
GBAThreadContinue(&m_threadContext); GBAThreadContinue(&m_threadContext);
} else {
m_threadContext.stream = nullptr;
}
} }
void GameController::updateKeys() { void GameController::updateKeys() {