diff --git a/include/mgba/core/thread.h b/include/mgba/core/thread.h index 420533762..9e609bfe7 100644 --- a/include/mgba/core/thread.h +++ b/include/mgba/core/thread.h @@ -34,6 +34,8 @@ struct mCoreThread { ThreadCallback cleanCallback; ThreadCallback frameCallback; ThreadCallback sleepCallback; + ThreadCallback pauseCallback; + ThreadCallback unpauseCallback; void* userData; void (*run)(struct mCoreThread*); @@ -50,13 +52,19 @@ enum mCoreThreadState { 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 diff --git a/src/core/thread.c b/src/core/thread.c index 782b573df..f17b5e30a 100644 --- a/src/core/thread.c +++ b/src/core/thread.c @@ -195,38 +195,58 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) { } } - 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; } } diff --git a/src/platform/qt/CoreController.cpp b/src/platform/qt/CoreController.cpp index 00c40e1a9..108fafed9 100644 --- a/src/platform/qt/CoreController.cpp +++ b/src/platform/qt/CoreController.cpp @@ -109,6 +109,18 @@ CoreController::CoreController(mCore* core, QObject* parent) QMetaObject::invokeMethod(controller, "stopping"); }; + m_threadContext.pauseCallback = [](mCoreThread* context) { + CoreController* controller = static_cast(context->userData); + + QMetaObject::invokeMethod(controller, "paused"); + }; + + m_threadContext.unpauseCallback = [](mCoreThread* context) { + CoreController* controller = static_cast(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(logger); mCoreThread* context = logContext->p; @@ -344,11 +356,9 @@ void CoreController::setPaused(bool paused) { QMutexLocker locker(&m_mutex); m_frameActions.append([this]() { mCoreThreadPauseFromThread(&m_threadContext); - QMetaObject::invokeMethod(this, "paused"); }); } else { mCoreThreadUnpause(&m_threadContext); - emit unpaused(); } }