From b044510fa946f1eab7e3b5917eba518b9631835a Mon Sep 17 00:00:00 2001
From: Sacha <xsacha@gmail.com>
Date: Mon, 25 Aug 2014 01:49:34 +1000
Subject: [PATCH] Fix EmuThread loop by ensuring it exits properly. Note: There
 is a pre-existing issue with booting a new game in that it keeps the old
 EmuThread. The GL code now supports this but the Core still doesn't.

---
 src/citra_qt/bootmanager.cpp | 33 +++++++++++++++++++++++++--------
 src/citra_qt/bootmanager.hxx |  5 ++++-
 2 files changed, 29 insertions(+), 9 deletions(-)

diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index 73f25e691..2407f3a3a 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -20,7 +20,8 @@
 
 EmuThread::EmuThread(GRenderWindow* render_window) : 
     exec_cpu_step(false), cpu_running(false), 
-    render_window(render_window), filename("")
+    render_window(render_window), filename(""),
+    stop_run(false)
 {
 }
 
@@ -31,6 +32,7 @@ void EmuThread::SetFilename(std::string filename)
 
 void EmuThread::run()
 {
+    stop_run = false;
     while (true)
     {
         for (int tight_loop = 0; tight_loop < 10000; ++tight_loop)
@@ -41,11 +43,17 @@ void EmuThread::run()
                     exec_cpu_step = false;
 
                 Core::SingleStep();
-                if (!cpu_running)
+                if (!cpu_running) {
                     emit CPUStepped();
+                    yieldCurrentThread();
+                }
             }
         }
+        QMutexLocker lock(&mutex);
+        if (stop_run)
+            break;
     }
+    render_window->moveContext();
 
     Core::Stop();
 }
@@ -58,16 +66,24 @@ void EmuThread::Stop()
         return;
     }
 
+    {
+        QMutexLocker lock(&mutex);
+        stop_run = true;
+    }
+
     //core::g_state = core::SYS_DIE;
 
-    wait(1000);
+    wait(500);
     if (isRunning())
     {
         WARN_LOG(MASTER_LOG, "EmuThread still running, terminating...");
-        terminate();
+        quit();
         wait(1000);
         if (isRunning())
+        {
             WARN_LOG(MASTER_LOG, "EmuThread STILL running, something is wrong here...");
+            terminate();
+        }
     }
     INFO_LOG(MASTER_LOG, "EmuThread stopped");
 }
@@ -116,7 +132,6 @@ GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this
     layout->setMargin(0);
     setLayout(layout);
     QObject::connect(&emu_thread, SIGNAL(started()), this, SLOT(moveContext()));
-    QObject::connect(&emu_thread, SIGNAL(finished()), this, SLOT(moveContext()));
 
     BackupGeometry();
 }
@@ -127,13 +142,14 @@ void GRenderWindow::moveContext()
     // We need to move GL context to the swapping thread in Qt5
 #if QT_VERSION > QT_VERSION_CHECK(5, 0, 0)
     // If the thread started running, move the GL Context to the new thread. Otherwise, move it back.
-    child->context()->moveToThread(emu_thread.isRunning() ? &emu_thread : qApp->thread());
+    child->context()->moveToThread((QThread::currentThread() == qApp->thread()) ? &emu_thread : qApp->thread());
 #endif
 }
 
 GRenderWindow::~GRenderWindow()
 {
-    emu_thread.Stop();
+    if (emu_thread.isRunning())
+        emu_thread.Stop();
 }
 
 void GRenderWindow::SwapBuffers()
@@ -144,7 +160,8 @@ void GRenderWindow::SwapBuffers()
 
 void GRenderWindow::closeEvent(QCloseEvent* event)
 {
-    emu_thread.Stop();
+    if (emu_thread.isRunning())
+        emu_thread.Stop();
     QWidget::closeEvent(event);
 }
 
diff --git a/src/citra_qt/bootmanager.hxx b/src/citra_qt/bootmanager.hxx
index c4a4299b1..4c3e2f0a4 100644
--- a/src/citra_qt/bootmanager.hxx
+++ b/src/citra_qt/bootmanager.hxx
@@ -1,3 +1,4 @@
+#include <QMutex>
 #include <QThread>
 #include <QGLWidget>
 #include "common/common.h"
@@ -66,6 +67,8 @@ private:
 
     bool exec_cpu_step;
     bool cpu_running;
+    bool stop_run;
+    QMutex mutex;
 
     GRenderWindow* render_window;
 
@@ -105,7 +108,7 @@ public:
     void keyPressEvent(QKeyEvent* event);
     void keyReleaseEvent(QKeyEvent* event);
 
-private slots:
+public slots:
     void moveContext();
 
 private: