all repos — mgba @ bf611e01f238b3366dcde7a5f176a0a9d198c520

mGBA Game Boy Advance Emulator

Core: Fix ordering of thread state request processing
Vicki Pfau vi@endrift.com
Thu, 19 Nov 2020 23:27:52 -0800
commit

bf611e01f238b3366dcde7a5f176a0a9d198c520

parent

d20b2e1e2302460dea1b17996a85cbd8f253fcbb

1 files changed, 28 insertions(+), 25 deletions(-)

jump to
M src/core/thread.csrc/core/thread.c

@@ -53,7 +53,13 @@ ConditionWait(&threadContext->stateCond, &threadContext->stateMutex);

} } -void _waitPrologue(struct mCoreThreadInternal* threadContext, bool* videoFrameWait, bool* audioWait) { +static void _pokeRequest(struct mCoreThreadInternal* threadContext) { + if (threadContext->state == mTHREAD_RUNNING || threadContext->state == mTHREAD_PAUSED) { + threadContext->state = mTHREAD_REQUEST; + } +} + +static void _waitPrologue(struct mCoreThreadInternal* threadContext, bool* videoFrameWait, bool* audioWait) { MutexLock(&threadContext->sync.videoFrameMutex); *videoFrameWait = threadContext->sync.videoFrameWait; threadContext->sync.videoFrameWait = false;

@@ -64,7 +70,7 @@ threadContext->sync.audioWait = false;

MutexUnlock(&threadContext->sync.audioBufferMutex); } -void _waitEpilogue(struct mCoreThreadInternal* threadContext, bool videoFrameWait, bool audioWait) { +static void _waitEpilogue(struct mCoreThreadInternal* threadContext, bool videoFrameWait, bool audioWait) { MutexLock(&threadContext->sync.audioBufferMutex); threadContext->sync.audioWait = audioWait; MutexUnlock(&threadContext->sync.audioBufferMutex);

@@ -94,6 +100,7 @@ static void _waitOnRequest(struct mCoreThreadInternal* threadContext, enum mCoreThreadRequest request) {

bool videoFrameWait, audioWait; _waitPrologue(threadContext, &videoFrameWait, &audioWait); while (threadContext->requested & request) { + _pokeRequest(threadContext); _wait(threadContext); } _waitEpilogue(threadContext, videoFrameWait, audioWait);

@@ -110,16 +117,12 @@ }

static void _sendRequest(struct mCoreThreadInternal* threadContext, enum mCoreThreadRequest request) { threadContext->requested |= request; - if (threadContext->state == mTHREAD_RUNNING) { - threadContext->state = mTHREAD_REQUEST; - } + _pokeRequest(threadContext); } 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; - } + _pokeRequest(threadContext); ConditionWake(&threadContext->stateCond); }

@@ -240,23 +243,6 @@ }

} MutexLock(&impl->stateMutex); - impl->requested &= ~pendingRequests | mTHREAD_REQ_PAUSE | mTHREAD_REQ_WAIT; - pendingRequests = impl->requested; - - 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); - } - } - while (impl->state >= mTHREAD_MIN_WAITING && impl->state < mTHREAD_EXITING) { if (impl->state == mTHREAD_INTERRUPTING) { impl->state = mTHREAD_INTERRUPTED;

@@ -275,6 +261,23 @@ }

} if (wasPaused && !(impl->requested & mTHREAD_REQ_PAUSE)) { break; + } + } + + impl->requested &= ~pendingRequests | mTHREAD_REQ_PAUSE | mTHREAD_REQ_WAIT; + pendingRequests = impl->requested; + + 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); } } MutexUnlock(&impl->stateMutex);