Qt: Create emu thread on bootup, kill it on shutdown.

This commit is contained in:
bunnei 2015-04-16 23:31:14 -04:00
parent d5665fea89
commit 28df8dbfeb
3 changed files with 44 additions and 31 deletions

View File

@ -30,21 +30,19 @@
EmuThread::EmuThread(GRenderWindow* render_window) : EmuThread::EmuThread(GRenderWindow* render_window) :
exec_cpu_step(false), cpu_running(false), stop_run(false), render_window(render_window) { exec_cpu_step(false), cpu_running(false), stop_run(false), render_window(render_window) {
shutdown_event.Reset();
connect(this, SIGNAL(started()), render_window, SLOT(moveContext())); connect(this, SIGNAL(started()), render_window, SLOT(moveContext()));
} }
void EmuThread::run() void EmuThread::run() {
{
stop_run = false; stop_run = false;
// holds whether the cpu was running during the last iteration, // holds whether the cpu was running during the last iteration,
// so that the DebugModeLeft signal can be emitted before the // so that the DebugModeLeft signal can be emitted before the
// next execution step // next execution step
bool was_active = false; bool was_active = false;
while (!stop_run) while (!stop_run) {
{ if (cpu_running) {
if (cpu_running)
{
if (!was_active) if (!was_active)
emit DebugModeLeft(); emit DebugModeLeft();
@ -53,9 +51,7 @@ void EmuThread::run()
was_active = cpu_running || exec_cpu_step; was_active = cpu_running || exec_cpu_step;
if (!was_active) if (!was_active)
emit DebugModeEntered(); emit DebugModeEntered();
} } else if (exec_cpu_step) {
else if (exec_cpu_step)
{
if (!was_active) if (!was_active)
emit DebugModeLeft(); emit DebugModeLeft();
@ -67,15 +63,14 @@ void EmuThread::run()
was_active = false; was_active = false;
} }
} }
render_window->moveContext(); render_window->moveContext();
Core::Stop(); shutdown_event.Set();
} }
void EmuThread::Stop() void EmuThread::Stop() {
{ if (!isRunning()) {
if (!isRunning())
{
LOG_WARNING(Frontend, "EmuThread::Stop called while emu thread wasn't running, returning..."); LOG_WARNING(Frontend, "EmuThread::Stop called while emu thread wasn't running, returning...");
return; return;
} }
@ -88,23 +83,19 @@ void EmuThread::Stop()
// TODO: Waiting here is just a bad workaround for retarded shutdown logic. // TODO: Waiting here is just a bad workaround for retarded shutdown logic.
wait(1000); wait(1000);
if (isRunning()) if (isRunning()) {
{
LOG_WARNING(Frontend, "EmuThread still running, terminating..."); LOG_WARNING(Frontend, "EmuThread still running, terminating...");
quit(); quit();
// TODO: Waiting 50 seconds can be necessary if the logging subsystem has a lot of spam // TODO: Waiting 50 seconds can be necessary if the logging subsystem has a lot of spam
// queued... This should be fixed. // queued... This should be fixed.
wait(50000); wait(50000);
if (isRunning()) if (isRunning()) {
{
LOG_CRITICAL(Frontend, "EmuThread STILL running, something is wrong here..."); LOG_CRITICAL(Frontend, "EmuThread STILL running, something is wrong here...");
terminate(); terminate();
} }
} }
LOG_INFO(Frontend, "EmuThread stopped"); LOG_INFO(Frontend, "EmuThread stopped");
System::Shutdown();
} }

View File

@ -9,6 +9,7 @@
#include "common/common.h" #include "common/common.h"
#include "common/emu_window.h" #include "common/emu_window.h"
#include "common/thread.h"
class QScreen; class QScreen;
class QKeyEvent; class QKeyEvent;
@ -37,20 +38,31 @@ public:
void ExecStep() { exec_cpu_step = true; } void ExecStep() { exec_cpu_step = true; }
/** /**
* Allow the CPU to continue processing instructions without interruption * Sets whether the CPU is running
* *
* @note This function is thread-safe * @note This function is thread-safe
*/ */
void SetCpuRunning(bool running) { cpu_running = running; } void SetCpuRunning(bool running) { cpu_running = running; }
/** /**
* Allow the CPU to continue processing instructions without interruption * Allow the CPU to continue processing instructions without interruption
* *
* @note This function is thread-safe * @note This function is thread-safe
*/ */
bool IsCpuRunning() { return cpu_running; } bool IsCpuRunning() { return cpu_running; }
/**
* Shutdown (permantently stops) the CPU
*/
void ShutdownCpu() { stop_run = true; };
/**
* Waits for the CPU shutdown to complete
*/
void WaitForCpuShutdown() { shutdown_event.Wait(); }
public slots: public slots:
/** /**
* Stop emulation and wait for the thread to finish. * Stop emulation and wait for the thread to finish.
@ -71,6 +83,8 @@ private:
GRenderWindow* render_window; GRenderWindow* render_window;
Common::Event shutdown_event;
signals: signals:
/** /**
* Emitted when the CPU has halted execution * Emitted when the CPU has halted execution

View File

@ -57,7 +57,6 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
render_window = new GRenderWindow(this, *this); render_window = new GRenderWindow(this, *this);
render_window->hide(); render_window->hide();
emu_thread = new EmuThread(render_window);
profilerWidget = new ProfilerWidget(this); profilerWidget = new ProfilerWidget(this);
addDockWidget(Qt::BottomDockWidgetArea, profilerWidget); addDockWidget(Qt::BottomDockWidgetArea, profilerWidget);
@ -197,9 +196,9 @@ void GMainWindow::OnDisplayTitleBars(bool show)
} }
} }
void GMainWindow::BootGame(std::string filename) void GMainWindow::BootGame(std::string filename) {
{
LOG_INFO(Frontend, "Citra starting...\n"); LOG_INFO(Frontend, "Citra starting...\n");
System::Init(render_window); System::Init(render_window);
// Load a game or die... // Load a game or die...
@ -211,6 +210,7 @@ void GMainWindow::BootGame(std::string filename)
registersWidget->OnDebugModeEntered(); registersWidget->OnDebugModeEntered();
callstackWidget->OnDebugModeEntered(); callstackWidget->OnDebugModeEntered();
emu_thread = new EmuThread(render_window);
emu_thread->start(); emu_thread->start();
render_window->show(); render_window->show();
@ -248,14 +248,22 @@ void GMainWindow::OnPauseGame()
ui.action_Stop->setEnabled(true); ui.action_Stop->setEnabled(true);
} }
void GMainWindow::OnStopGame() void GMainWindow::OnStopGame() {
{
emu_thread->SetCpuRunning(false); emu_thread->SetCpuRunning(false);
// TODO: Shutdown core
emu_thread->ShutdownCpu();
emu_thread->WaitForCpuShutdown();
emu_thread->Stop();
delete emu_thread;
System::Shutdown();
ui.action_Start->setEnabled(true); ui.action_Start->setEnabled(true);
ui.action_Pause->setEnabled(false); ui.action_Pause->setEnabled(false);
ui.action_Stop->setEnabled(false); ui.action_Stop->setEnabled(false);
render_window->hide();
} }
void GMainWindow::OnOpenHotkeysDialog() void GMainWindow::OnOpenHotkeysDialog()