Qt: Create emu thread on bootup, kill it on shutdown.
This commit is contained in:
parent
d5665fea89
commit
28df8dbfeb
|
@ -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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Reference in New Issue