Core: Rework thread state synchronization
@@ -49,7 +49,6 @@ - All: Improve export headers (fixes mgba.io/i/1738)
- CMake: Fix build with downstream minizip that exports incompatible symbols - Core: Ensure ELF regions can be written before trying - Core: Fix threading improperly setting paused state while interrupted - - Core: Fix thread unsafety issue when dispatching code to a thread - Debugger: Don't skip undefined instructions when debugger attached - Debugger: Close trace log when done tracing - FFmpeg: Fix some small memory leaks@@ -66,6 +65,7 @@ Misc:
- 3DS: Use "wide mode" where applicable for slightly better filtering - Core: Add savedataUpdated callback - Core: Add shutdown callback + - Core: Rework thread state synchronization - GB: Allow pausing event loop while CPU is blocked - GB: Add support for sleep and shutdown callbacks - GBA: Allow pausing event loop while CPU is blocked
@@ -15,7 +15,6 @@
struct mCoreSync { int videoFramePending; bool videoFrameWait; - bool videoFrameOn; Mutex videoFrameMutex; Condition videoFrameAvailableCond; Condition videoFrameRequiredCond;
@@ -48,35 +48,37 @@ #include <mgba/core/sync.h>
#include <mgba-util/threading.h> enum mCoreThreadState { - THREAD_INITIALIZED = -1, - THREAD_RUNNING = 0, - THREAD_REWINDING, - THREAD_MAX_RUNNING = THREAD_REWINDING, + mTHREAD_INITIALIZED = -1, + mTHREAD_RUNNING = 0, + mTHREAD_REQUEST, - THREAD_WAITING, - THREAD_INTERRUPTED, - THREAD_PAUSED, - THREAD_MAX_WAITING = THREAD_PAUSED, + mTHREAD_INTERRUPTED, + mTHREAD_PAUSED, + mTHREAD_MIN_WAITING = mTHREAD_INTERRUPTED, + mTHREAD_MAX_WAITING = mTHREAD_PAUSED, - THREAD_PAUSING, - THREAD_RUN_ON, - THREAD_RESETING, - THREAD_MIN_DEFERRED = THREAD_PAUSING, - THREAD_MAX_DEFERRED = THREAD_RESETING, + mTHREAD_INTERRUPTING, + mTHREAD_EXITING, - THREAD_INTERRUPTING, - THREAD_EXITING, - THREAD_SHUTDOWN, - THREAD_CRASHED + mTHREAD_SHUTDOWN, + mTHREAD_CRASHED +}; + +enum mCoreThreadRequest { + mTHREAD_REQ_PAUSE = 1, // User-set pause + mTHREAD_REQ_WAIT = 2, // Core-set pause + mTHREAD_REQ_RESET = 4, + mTHREAD_REQ_RUN_ON = 8, }; struct mCoreThreadInternal { Thread thread; enum mCoreThreadState state; + bool rewinding; + int requested; Mutex stateMutex; Condition stateCond; - enum mCoreThreadState savedState; int interruptDepth; bool frameWasOn;
@@ -7,11 +7,11 @@ #include <mgba/core/sync.h>
#include <mgba/core/blip_buf.h> -static void _changeVideoSync(struct mCoreSync* sync, bool frameOn) { +static void _changeVideoSync(struct mCoreSync* sync, bool wait) { // Make sure the video thread can process events while the GBA thread is paused MutexLock(&sync->videoFrameMutex); - if (frameOn != sync->videoFrameOn) { - sync->videoFrameOn = frameOn; + if (wait != sync->videoFrameWait) { + sync->videoFrameWait = wait; ConditionWake(&sync->videoFrameAvailableCond); } MutexUnlock(&sync->videoFrameMutex);@@ -50,10 +50,10 @@ }
MutexLock(&sync->videoFrameMutex); ConditionWake(&sync->videoFrameRequiredCond); - if (!sync->videoFrameOn && !sync->videoFramePending) { + if (!sync->videoFrameWait && !sync->videoFramePending) { return false; } - if (sync->videoFrameOn) { + if (sync->videoFrameWait) { if (ConditionWaitTimed(&sync->videoFrameAvailableCond, &sync->videoFrameMutex, 50)) { return false; }
@@ -48,51 +48,79 @@ MutexUnlock(&threadContext->stateMutex);
} static void _waitOnInterrupt(struct mCoreThreadInternal* threadContext) { - while (threadContext->state == THREAD_INTERRUPTED || threadContext->state == THREAD_INTERRUPTING) { + while (threadContext->state == mTHREAD_INTERRUPTED || threadContext->state == mTHREAD_INTERRUPTING) { ConditionWait(&threadContext->stateCond, &threadContext->stateMutex); } } -static void _waitUntilNotState(struct mCoreThreadInternal* threadContext, enum mCoreThreadState oldState) { +void _waitPrologue(struct mCoreThreadInternal* threadContext, bool* videoFrameWait, bool* audioWait) { MutexLock(&threadContext->sync.videoFrameMutex); - bool videoFrameWait = threadContext->sync.videoFrameWait; + *videoFrameWait = threadContext->sync.videoFrameWait; threadContext->sync.videoFrameWait = false; MutexUnlock(&threadContext->sync.videoFrameMutex); - MutexLock(&threadContext->sync.audioBufferMutex); - bool audioWait = threadContext->sync.audioWait; + *audioWait = threadContext->sync.audioWait; threadContext->sync.audioWait = false; MutexUnlock(&threadContext->sync.audioBufferMutex); +} - while (threadContext->state == oldState) { - MutexUnlock(&threadContext->stateMutex); +void _waitEpilogue(struct mCoreThreadInternal* threadContext, bool videoFrameWait, bool audioWait) { + MutexLock(&threadContext->sync.audioBufferMutex); + threadContext->sync.audioWait = audioWait; + MutexUnlock(&threadContext->sync.audioBufferMutex); + MutexLock(&threadContext->sync.videoFrameMutex); + threadContext->sync.videoFrameWait = videoFrameWait; + MutexUnlock(&threadContext->sync.videoFrameMutex); +} - if (!MutexTryLock(&threadContext->sync.videoFrameMutex)) { - ConditionWake(&threadContext->sync.videoFrameRequiredCond); - MutexUnlock(&threadContext->sync.videoFrameMutex); - } +static void _wait(struct mCoreThreadInternal* threadContext) { + MutexUnlock(&threadContext->stateMutex); - if (!MutexTryLock(&threadContext->sync.audioBufferMutex)) { - ConditionWake(&threadContext->sync.audioRequiredCond); - MutexUnlock(&threadContext->sync.audioBufferMutex); - } + if (!MutexTryLock(&threadContext->sync.videoFrameMutex)) { + ConditionWake(&threadContext->sync.videoFrameRequiredCond); + MutexUnlock(&threadContext->sync.videoFrameMutex); + } - MutexLock(&threadContext->stateMutex); - ConditionWake(&threadContext->stateCond); + if (!MutexTryLock(&threadContext->sync.audioBufferMutex)) { + ConditionWake(&threadContext->sync.audioRequiredCond); + MutexUnlock(&threadContext->sync.audioBufferMutex); } - MutexLock(&threadContext->sync.audioBufferMutex); - threadContext->sync.audioWait = audioWait; - MutexUnlock(&threadContext->sync.audioBufferMutex); + MutexLock(&threadContext->stateMutex); + ConditionWake(&threadContext->stateCond); +} - MutexLock(&threadContext->sync.videoFrameMutex); - threadContext->sync.videoFrameWait = videoFrameWait; - MutexUnlock(&threadContext->sync.videoFrameMutex); +static void _waitOnRequest(struct mCoreThreadInternal* threadContext, enum mCoreThreadRequest request) { + bool videoFrameWait, audioWait; + _waitPrologue(threadContext, &videoFrameWait, &audioWait); + while (threadContext->requested & request) { + _wait(threadContext); + } + _waitEpilogue(threadContext, videoFrameWait, audioWait); +} + +static void _waitUntilNotState(struct mCoreThreadInternal* threadContext, enum mCoreThreadState state) { + bool videoFrameWait, audioWait; + _waitPrologue(threadContext, &videoFrameWait, &audioWait); + while (threadContext->state == state) { + _wait(threadContext); + } + _waitEpilogue(threadContext, videoFrameWait, audioWait); } -static void _pauseThread(struct mCoreThreadInternal* threadContext) { - threadContext->state = THREAD_PAUSING; - _waitUntilNotState(threadContext, THREAD_PAUSING); +static void _sendRequest(struct mCoreThreadInternal* threadContext, enum mCoreThreadRequest request) { + threadContext->requested |= request; + if (threadContext->state == mTHREAD_RUNNING) { + threadContext->state = mTHREAD_REQUEST; + } +} + +static void _cancelRequest(struct mCoreThreadInternal* threadContext, enum mCoreThreadRequest request) { + threadContext->requested &= ~request; + if (threadContext->state == mTHREAD_RUNNING || threadContext->state == mTHREAD_PAUSED) { + threadContext->state = mTHREAD_REQUEST; + } + ConditionWake(&threadContext->stateCond); } void _frameStarted(void* context) {@@ -101,12 +129,8 @@ if (!thread) {
return; } if (thread->core->opts.rewindEnable && thread->core->opts.rewindBufferCapacity > 0) { - if (thread->impl->state != THREAD_REWINDING) { + if (!thread->impl->rewinding || !mCoreRewindRestore(&thread->impl->rewind, thread->core)) { mCoreRewindAppend(&thread->impl->rewind, thread->core); - } else if (thread->impl->state == THREAD_REWINDING) { - if (!mCoreRewindRestore(&thread->impl->rewind, thread->core)) { - mCoreRewindAppend(&thread->impl->rewind, thread->core); - } } } }@@ -126,7 +150,7 @@ struct mCoreThread* thread = context;
if (!thread) { return; } - _changeState(thread->impl, THREAD_CRASHED, true); + _changeState(thread->impl, mTHREAD_CRASHED, true); } void _coreSleep(void* context) {@@ -144,7 +168,7 @@ struct mCoreThread* thread = context;
if (!thread) { return; } - _changeState(thread->impl, THREAD_EXITING, true); + _changeState(thread->impl, mTHREAD_EXITING, true); } static THREAD_ENTRY _mCoreThreadRun(void* context) {@@ -189,58 +213,57 @@ threadContext->startCallback(threadContext);
} core->reset(core); - _changeState(threadContext->impl, THREAD_RUNNING, true); + _changeState(threadContext->impl, mTHREAD_RUNNING, true); if (threadContext->resetCallback) { threadContext->resetCallback(threadContext); } struct mCoreThreadInternal* impl = threadContext->impl; - while (impl->state < THREAD_EXITING) { + bool wasPaused = false; + int pendingRequests = 0; + + while (impl->state < mTHREAD_EXITING) { #ifdef USE_DEBUGGERS struct mDebugger* debugger = core->debugger; if (debugger) { mDebuggerRun(debugger); if (debugger->state == DEBUGGER_SHUTDOWN) { - _changeState(impl, THREAD_EXITING, false); + _changeState(impl, mTHREAD_EXITING, false); } } else #endif { - while (impl->state <= THREAD_MAX_RUNNING) { + while (impl->state == mTHREAD_RUNNING) { core->runLoop(core); } } - enum mCoreThreadState deferred = THREAD_RUNNING; MutexLock(&impl->stateMutex); - while (impl->state > THREAD_MAX_RUNNING && impl->state < THREAD_EXITING) { - deferred = impl->state; + impl->requested &= ~pendingRequests | mTHREAD_REQ_PAUSE | mTHREAD_REQ_WAIT; + pendingRequests = impl->requested; - switch (deferred) { - case THREAD_INTERRUPTING: - impl->state = THREAD_INTERRUPTED; - ConditionWake(&impl->stateCond); - break; - case THREAD_PAUSING: - impl->state = THREAD_PAUSED; - break; - case THREAD_RESETING: - impl->state = THREAD_RUNNING; - break; - default: - break; + if (impl->state == mTHREAD_REQUEST) { + if (pendingRequests) { + if (pendingRequests & mTHREAD_REQ_PAUSE) { + impl->state = mTHREAD_PAUSED; + } + if (pendingRequests & mTHREAD_REQ_WAIT) { + impl->state = mTHREAD_PAUSED; + } + } else { + impl->state = mTHREAD_RUNNING; + ConditionWake(&threadContext->impl->stateCond); } + } - if (deferred >= THREAD_MIN_DEFERRED && deferred <= THREAD_MAX_DEFERRED) { - break; + while (impl->state >= mTHREAD_MIN_WAITING && impl->state < mTHREAD_EXITING) { + if (impl->state == mTHREAD_INTERRUPTING) { + impl->state = mTHREAD_INTERRUPTED; + ConditionWake(&impl->stateCond); } - deferred = impl->state; - if (deferred == THREAD_INTERRUPTED) { - deferred = impl->savedState; - } - while (impl->state >= THREAD_WAITING && impl->state <= THREAD_MAX_WAITING) { + while (impl->state >= mTHREAD_MIN_WAITING && impl->state <= mTHREAD_MAX_WAITING) { ConditionWait(&impl->stateCond, &impl->stateMutex); if (impl->sync.audioWait) {@@ -250,41 +273,40 @@ mCoreSyncProduceAudio(&impl->sync, core->getAudioChannel(core, 0), core->getAudioBufferSize(core));
MutexLock(&impl->stateMutex); } } + if (wasPaused && !(impl->requested & mTHREAD_REQ_PAUSE)) { + break; + } } MutexUnlock(&impl->stateMutex); - switch (deferred) { - case THREAD_PAUSING: + + // Deferred callbacks can't be run inside of the critical section + if (!wasPaused && (pendingRequests & mTHREAD_REQ_PAUSE)) { + wasPaused = true; if (threadContext->pauseCallback) { threadContext->pauseCallback(threadContext); } - break; - case THREAD_PAUSED: + } + if (wasPaused && !(pendingRequests & mTHREAD_REQ_PAUSE)) { + wasPaused = false; if (threadContext->unpauseCallback) { threadContext->unpauseCallback(threadContext); } - break; - case THREAD_RUN_ON: - if (threadContext->run) { - threadContext->run(threadContext); - } - MutexLock(&threadContext->impl->stateMutex); - threadContext->impl->state = threadContext->impl->savedState; - ConditionWake(&threadContext->impl->stateCond); - MutexUnlock(&threadContext->impl->stateMutex); - break; - case THREAD_RESETING: + } + if (pendingRequests & mTHREAD_REQ_RESET) { core->reset(core); if (threadContext->resetCallback) { threadContext->resetCallback(threadContext); } - break; - default: - break; + } + if (pendingRequests & mTHREAD_REQ_RUN_ON) { + if (threadContext->run) { + threadContext->run(threadContext); + } } } - while (impl->state < THREAD_SHUTDOWN) { - _changeState(impl, THREAD_SHUTDOWN, false); + while (impl->state < mTHREAD_SHUTDOWN) { + _changeState(impl, mTHREAD_SHUTDOWN, false); } if (core->opts.rewindEnable) {@@ -306,7 +328,8 @@ }
bool mCoreThreadStart(struct mCoreThread* threadContext) { threadContext->impl = calloc(sizeof(*threadContext->impl), 1); - threadContext->impl->state = THREAD_INITIALIZED; + threadContext->impl->state = mTHREAD_INITIALIZED; + threadContext->impl->requested = 0; threadContext->logger.p = threadContext; if (!threadContext->logger.d.log) { threadContext->logger.d.log = _mCoreLog;@@ -342,7 +365,7 @@ threadContext->impl->sync.fpsTarget = threadContext->core->opts.fpsTarget;
MutexLock(&threadContext->impl->stateMutex); ThreadCreate(&threadContext->impl->thread, _mCoreThreadRun, threadContext); - while (threadContext->impl->state < THREAD_RUNNING) { + while (threadContext->impl->state < mTHREAD_RUNNING) { ConditionWait(&threadContext->impl->stateCond, &threadContext->impl->stateMutex); } MutexUnlock(&threadContext->impl->stateMutex);@@ -356,7 +379,7 @@ return false;
} bool hasStarted; MutexLock(&threadContext->impl->stateMutex); - hasStarted = threadContext->impl->state > THREAD_INITIALIZED; + hasStarted = threadContext->impl->state > mTHREAD_INITIALIZED; MutexUnlock(&threadContext->impl->stateMutex); return hasStarted; }@@ -367,7 +390,7 @@ return false;
} bool hasExited; MutexLock(&threadContext->impl->stateMutex); - hasExited = threadContext->impl->state > THREAD_EXITING; + hasExited = threadContext->impl->state > mTHREAD_EXITING; MutexUnlock(&threadContext->impl->stateMutex); return hasExited; }@@ -378,21 +401,21 @@ return false;
} bool hasExited; MutexLock(&threadContext->impl->stateMutex); - hasExited = threadContext->impl->state == THREAD_CRASHED; + hasExited = threadContext->impl->state == mTHREAD_CRASHED; MutexUnlock(&threadContext->impl->stateMutex); return hasExited; } void mCoreThreadMarkCrashed(struct mCoreThread* threadContext) { MutexLock(&threadContext->impl->stateMutex); - threadContext->impl->state = THREAD_CRASHED; + threadContext->impl->state = mTHREAD_CRASHED; MutexUnlock(&threadContext->impl->stateMutex); } void mCoreThreadEnd(struct mCoreThread* threadContext) { MutexLock(&threadContext->impl->stateMutex); _waitOnInterrupt(threadContext->impl); - threadContext->impl->state = THREAD_EXITING; + threadContext->impl->state = mTHREAD_EXITING; ConditionWake(&threadContext->impl->stateCond); MutexUnlock(&threadContext->impl->stateMutex); MutexLock(&threadContext->impl->sync.audioBufferMutex);@@ -402,7 +425,6 @@ MutexUnlock(&threadContext->impl->sync.audioBufferMutex);
MutexLock(&threadContext->impl->sync.videoFrameMutex); threadContext->impl->sync.videoFrameWait = false; - threadContext->impl->sync.videoFrameOn = false; ConditionWake(&threadContext->impl->sync.videoFrameRequiredCond); ConditionWake(&threadContext->impl->sync.videoFrameAvailableCond); MutexUnlock(&threadContext->impl->sync.videoFrameMutex);@@ -410,12 +432,9 @@ }
void mCoreThreadReset(struct mCoreThread* threadContext) { MutexLock(&threadContext->impl->stateMutex); - if (threadContext->impl->state == THREAD_INTERRUPTED || threadContext->impl->state == THREAD_INTERRUPTING) { - threadContext->impl->savedState = THREAD_RESETING; - } else { - threadContext->impl->state = THREAD_RESETING; - } - ConditionWake(&threadContext->impl->stateCond); + _waitOnInterrupt(threadContext->impl); + _sendRequest(threadContext->impl, mTHREAD_REQ_RESET); + _waitOnRequest(threadContext->impl, mTHREAD_REQ_RESET); MutexUnlock(&threadContext->impl->stateMutex); }@@ -446,7 +465,7 @@ bool mCoreThreadIsActive(struct mCoreThread* threadContext) {
if (!threadContext->impl) { return false; } - return threadContext->impl->state >= THREAD_RUNNING && threadContext->impl->state < THREAD_EXITING; + return threadContext->impl->state >= mTHREAD_RUNNING && threadContext->impl->state < mTHREAD_EXITING; } void mCoreThreadInterrupt(struct mCoreThread* threadContext) {@@ -459,11 +478,8 @@ if (threadContext->impl->interruptDepth > 1 || !mCoreThreadIsActive(threadContext)) {
MutexUnlock(&threadContext->impl->stateMutex); return; } - threadContext->impl->savedState = threadContext->impl->state; - _waitOnInterrupt(threadContext->impl); - threadContext->impl->state = THREAD_INTERRUPTING; - ConditionWake(&threadContext->impl->stateCond); - _waitUntilNotState(threadContext->impl, THREAD_INTERRUPTING); + threadContext->impl->state = mTHREAD_INTERRUPTING; + _waitUntilNotState(threadContext->impl, mTHREAD_INTERRUPTING); MutexUnlock(&threadContext->impl->stateMutex); }@@ -474,14 +490,13 @@ }
MutexLock(&threadContext->impl->stateMutex); ++threadContext->impl->interruptDepth; if (threadContext->impl->interruptDepth > 1 || !mCoreThreadIsActive(threadContext)) { - if (threadContext->impl->state == THREAD_INTERRUPTING) { - threadContext->impl->state = THREAD_INTERRUPTED; + if (threadContext->impl->state == mTHREAD_INTERRUPTING) { + threadContext->impl->state = mTHREAD_INTERRUPTED; } MutexUnlock(&threadContext->impl->stateMutex); return; } - threadContext->impl->savedState = threadContext->impl->state; - threadContext->impl->state = THREAD_INTERRUPTING; + threadContext->impl->state = mTHREAD_INTERRUPTING; ConditionWake(&threadContext->impl->stateCond); MutexUnlock(&threadContext->impl->stateMutex); }@@ -493,7 +508,7 @@ }
MutexLock(&threadContext->impl->stateMutex); --threadContext->impl->interruptDepth; if (threadContext->impl->interruptDepth < 1 && mCoreThreadIsActive(threadContext)) { - threadContext->impl->state = threadContext->impl->savedState; + threadContext->impl->state = mTHREAD_REQUEST; ConditionWake(&threadContext->impl->stateCond); } MutexUnlock(&threadContext->impl->stateMutex);@@ -501,105 +516,57 @@ }
void mCoreThreadRunFunction(struct mCoreThread* threadContext, void (*run)(struct mCoreThread*)) { MutexLock(&threadContext->impl->stateMutex); + _waitOnInterrupt(threadContext->impl); threadContext->run = run; - _waitOnInterrupt(threadContext->impl); - threadContext->impl->savedState = threadContext->impl->state; - threadContext->impl->state = THREAD_RUN_ON; - ConditionWake(&threadContext->impl->stateCond); - _waitUntilNotState(threadContext->impl, THREAD_RUN_ON); + _sendRequest(threadContext->impl, mTHREAD_REQ_RUN_ON); + _waitOnRequest(threadContext->impl, mTHREAD_REQ_RUN_ON); MutexUnlock(&threadContext->impl->stateMutex); } void mCoreThreadPause(struct mCoreThread* threadContext) { - bool frameOn = threadContext->impl->sync.videoFrameOn; MutexLock(&threadContext->impl->stateMutex); _waitOnInterrupt(threadContext->impl); - if (threadContext->impl->state == THREAD_RUNNING) { - _pauseThread(threadContext->impl); - threadContext->impl->frameWasOn = frameOn; - frameOn = false; - } + _sendRequest(threadContext->impl, mTHREAD_REQ_PAUSE); + _waitUntilNotState(threadContext->impl, mTHREAD_REQUEST); MutexUnlock(&threadContext->impl->stateMutex); - - mCoreSyncSetVideoSync(&threadContext->impl->sync, frameOn); } void mCoreThreadUnpause(struct mCoreThread* threadContext) { - bool frameOn = threadContext->impl->sync.videoFrameOn; MutexLock(&threadContext->impl->stateMutex); - _waitOnInterrupt(threadContext->impl); - if (threadContext->impl->state == THREAD_PAUSED || threadContext->impl->state == THREAD_PAUSING) { - threadContext->impl->state = THREAD_RUNNING; - ConditionWake(&threadContext->impl->stateCond); - frameOn = threadContext->impl->frameWasOn; - } + _cancelRequest(threadContext->impl, mTHREAD_REQ_PAUSE); + _waitUntilNotState(threadContext->impl, mTHREAD_REQUEST); MutexUnlock(&threadContext->impl->stateMutex); - - mCoreSyncSetVideoSync(&threadContext->impl->sync, frameOn); } bool mCoreThreadIsPaused(struct mCoreThread* threadContext) { bool isPaused; MutexLock(&threadContext->impl->stateMutex); - if (threadContext->impl->interruptDepth) { - isPaused = threadContext->impl->savedState == THREAD_PAUSED; - } else { - isPaused = threadContext->impl->state == THREAD_PAUSED; - } + isPaused = !!(threadContext->impl->requested & mTHREAD_REQ_PAUSE); MutexUnlock(&threadContext->impl->stateMutex); return isPaused; } void mCoreThreadTogglePause(struct mCoreThread* threadContext) { - bool frameOn = threadContext->impl->sync.videoFrameOn; MutexLock(&threadContext->impl->stateMutex); _waitOnInterrupt(threadContext->impl); - if (threadContext->impl->state == THREAD_PAUSED || threadContext->impl->state == THREAD_PAUSING) { - threadContext->impl->state = THREAD_RUNNING; - ConditionWake(&threadContext->impl->stateCond); - frameOn = threadContext->impl->frameWasOn; - } else if (threadContext->impl->state == THREAD_RUNNING) { - _pauseThread(threadContext->impl); - threadContext->impl->frameWasOn = frameOn; - frameOn = false; + if (threadContext->impl->requested & mTHREAD_REQ_PAUSE) { + _cancelRequest(threadContext->impl, mTHREAD_REQ_PAUSE); + } else { + _sendRequest(threadContext->impl, mTHREAD_REQ_PAUSE); } + _waitUntilNotState(threadContext->impl, mTHREAD_REQUEST); MutexUnlock(&threadContext->impl->stateMutex); - - mCoreSyncSetVideoSync(&threadContext->impl->sync, frameOn); } void mCoreThreadPauseFromThread(struct mCoreThread* threadContext) { - bool frameOn = true; MutexLock(&threadContext->impl->stateMutex); - if (threadContext->impl->interruptDepth && threadContext->impl->savedState == THREAD_RUNNING) { - threadContext->impl->savedState = THREAD_PAUSING; - frameOn = false; - } else if (threadContext->impl->state == THREAD_RUNNING) { - threadContext->impl->state = THREAD_PAUSING; - frameOn = false; - } + _sendRequest(threadContext->impl, mTHREAD_REQ_PAUSE); MutexUnlock(&threadContext->impl->stateMutex); - - mCoreSyncSetVideoSync(&threadContext->impl->sync, frameOn); } void mCoreThreadSetRewinding(struct mCoreThread* threadContext, bool rewinding) { MutexLock(&threadContext->impl->stateMutex); - if (rewinding && (threadContext->impl->state == THREAD_REWINDING || (threadContext->impl->interruptDepth && threadContext->impl->savedState == THREAD_REWINDING))) { - MutexUnlock(&threadContext->impl->stateMutex); - return; - } - if (!rewinding && ((!threadContext->impl->interruptDepth && threadContext->impl->state != THREAD_REWINDING) || (threadContext->impl->interruptDepth && threadContext->impl->savedState != THREAD_REWINDING))) { - MutexUnlock(&threadContext->impl->stateMutex); - return; - } - _waitOnInterrupt(threadContext->impl); - if (rewinding && threadContext->impl->state == THREAD_RUNNING) { - threadContext->impl->state = THREAD_REWINDING; - } - if (!rewinding && threadContext->impl->state == THREAD_REWINDING) { - threadContext->impl->state = THREAD_RUNNING; - } + threadContext->impl->rewinding = rewinding; MutexUnlock(&threadContext->impl->stateMutex); }@@ -614,22 +581,13 @@ }
void mCoreThreadWaitFromThread(struct mCoreThread* threadContext) { MutexLock(&threadContext->impl->stateMutex); - if (threadContext->impl->interruptDepth && threadContext->impl->savedState == THREAD_RUNNING) { - threadContext->impl->savedState = THREAD_WAITING; - } else if (threadContext->impl->state == THREAD_RUNNING) { - threadContext->impl->state = THREAD_WAITING; - } + _sendRequest(threadContext->impl, mTHREAD_REQ_WAIT); MutexUnlock(&threadContext->impl->stateMutex); } void mCoreThreadStopWaiting(struct mCoreThread* threadContext) { MutexLock(&threadContext->impl->stateMutex); - if (threadContext->impl->interruptDepth && threadContext->impl->savedState == THREAD_WAITING) { - threadContext->impl->savedState = THREAD_RUNNING; - } else if (threadContext->impl->state == THREAD_WAITING) { - threadContext->impl->state = THREAD_RUNNING; - ConditionWake(&threadContext->impl->stateCond); - } + _cancelRequest(threadContext->impl, mTHREAD_REQ_WAIT); MutexUnlock(&threadContext->impl->stateMutex); }
@@ -402,13 +402,7 @@ mCoreThreadEnd(&m_threadContext);
} void CoreController::reset() { - bool wasPaused = isPaused(); - setPaused(false); - Interrupter interrupter(this); mCoreThreadReset(&m_threadContext); - if (wasPaused) { - setPaused(true); - } } void CoreController::setPaused(bool paused) {