all repos — mgba @ 1a749240239d58eab801825eb5d43be19290b90d

mGBA Game Boy Advance Emulator

Core: Add pause/unpause callbacks to mCoreThread
Vicki Pfau vi@endrift.com
Thu, 03 Aug 2017 23:56:44 -0700
commit

1a749240239d58eab801825eb5d43be19290b90d

parent

1733c6456125b0a49c7f7fcac28ffe4328ce4701

3 files changed, 56 insertions(+), 18 deletions(-)

jump to
M include/mgba/core/thread.hinclude/mgba/core/thread.h

@@ -34,6 +34,8 @@ ThreadCallback resetCallback;

ThreadCallback cleanCallback; ThreadCallback frameCallback; ThreadCallback sleepCallback; + ThreadCallback pauseCallback; + ThreadCallback unpauseCallback; void* userData; void (*run)(struct mCoreThread*);

@@ -50,13 +52,19 @@ THREAD_INITIALIZED = -1,

THREAD_RUNNING = 0, THREAD_REWINDING, THREAD_MAX_RUNNING = THREAD_REWINDING, + + THREAD_WAITING, THREAD_INTERRUPTED, - THREAD_INTERRUPTING, THREAD_PAUSED, + THREAD_MAX_WAITING = THREAD_PAUSED, + THREAD_PAUSING, THREAD_RUN_ON, - THREAD_WAITING, THREAD_RESETING, + THREAD_MIN_DEFERRED = THREAD_PAUSING, + THREAD_MAX_DEFERRED = THREAD_RESETING, + + THREAD_INTERRUPTING, THREAD_EXITING, THREAD_SHUTDOWN, THREAD_CRASHED
M src/core/thread.csrc/core/thread.c

@@ -195,38 +195,58 @@ core->runLoop(core);

} } - int resetScheduled = 0; + enum mCoreThreadState deferred = THREAD_RUNNING; MutexLock(&impl->stateMutex); while (impl->state > THREAD_MAX_RUNNING && impl->state < THREAD_EXITING) { - if (impl->state == THREAD_PAUSING) { - impl->state = THREAD_PAUSED; - ConditionWake(&impl->stateCond); - } + deferred = impl->state; + if (impl->state == THREAD_INTERRUPTING) { impl->state = THREAD_INTERRUPTED; ConditionWake(&impl->stateCond); } - if (impl->state == THREAD_RUN_ON) { - if (threadContext->run) { - threadContext->run(threadContext); - } - impl->state = impl->savedState; - ConditionWake(&impl->stateCond); + + if (impl->state == THREAD_PAUSING) { + impl->state = THREAD_PAUSED; } if (impl->state == THREAD_RESETING) { impl->state = THREAD_RUNNING; - resetScheduled = 1; } - while (impl->state == THREAD_PAUSED || impl->state == THREAD_INTERRUPTED || impl->state == THREAD_WAITING) { + + if (deferred >= THREAD_MIN_DEFERRED && deferred <= THREAD_MAX_DEFERRED) { + break; + } + + deferred = impl->state; + while (impl->state >= THREAD_WAITING && impl->state <= THREAD_MAX_WAITING) { ConditionWait(&impl->stateCond, &impl->stateMutex); } } MutexUnlock(&impl->stateMutex); - if (resetScheduled) { + switch (deferred) { + case THREAD_PAUSING: + if (threadContext->pauseCallback) { + threadContext->pauseCallback(threadContext); + } + break; + case THREAD_PAUSED: + if (threadContext->unpauseCallback) { + threadContext->unpauseCallback(threadContext); + } + break; + case THREAD_RUN_ON: + if (threadContext->run) { + threadContext->run(threadContext); + } + threadContext->impl->state = threadContext->impl->savedState; + break; + case THREAD_RESETING: core->reset(core); if (threadContext->resetCallback) { threadContext->resetCallback(threadContext); } + break; + default: + break; } }
M src/platform/qt/CoreController.cppsrc/platform/qt/CoreController.cpp

@@ -109,6 +109,18 @@ controller->clearMultiplayerController();

QMetaObject::invokeMethod(controller, "stopping"); }; + m_threadContext.pauseCallback = [](mCoreThread* context) { + CoreController* controller = static_cast<CoreController*>(context->userData); + + QMetaObject::invokeMethod(controller, "paused"); + }; + + m_threadContext.unpauseCallback = [](mCoreThread* context) { + CoreController* controller = static_cast<CoreController*>(context->userData); + + QMetaObject::invokeMethod(controller, "unpaused"); + }; + m_threadContext.logger.d.log = [](mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) { mThreadLogger* logContext = reinterpret_cast<mThreadLogger*>(logger); mCoreThread* context = logContext->p;

@@ -344,11 +356,9 @@ if (paused) {

QMutexLocker locker(&m_mutex); m_frameActions.append([this]() { mCoreThreadPauseFromThread(&m_threadContext); - QMetaObject::invokeMethod(this, "paused"); }); } else { mCoreThreadUnpause(&m_threadContext); - emit unpaused(); } }