citra_qt: Show critical QMessageBox when EmuThread crashes

This commit is contained in:
MerryMage 2016-12-19 19:25:27 +00:00
parent 710b70f555
commit 1bfa44c317
4 changed files with 66 additions and 26 deletions

View File

@ -9,6 +9,7 @@
#endif #endif
#include "citra_qt/bootmanager.h" #include "citra_qt/bootmanager.h"
#include "common/crash_handler.h"
#include "common/key_map.h" #include "common/key_map.h"
#include "common/microprofile.h" #include "common/microprofile.h"
#include "common/scm_rev.h" #include "common/scm_rev.h"
@ -25,7 +26,10 @@
#define COPYRIGHT "Copyright (C) 2013-2014 Citra Team" #define COPYRIGHT "Copyright (C) 2013-2014 Citra Team"
EmuThread::EmuThread(GRenderWindow* render_window) EmuThread::EmuThread(GRenderWindow* render_window)
: exec_step(false), running(false), stop_run(false), render_window(render_window) {} : exec_step(false), running(false), stop_run(false), render_window(render_window) {
// Custom types must be registered to be used with Qt signals/slots.
qRegisterMetaType<Common::CrashInformation>("Common::CrashInformation");
}
void EmuThread::run() { void EmuThread::run() {
render_window->MakeCurrent(); render_window->MakeCurrent();
@ -34,35 +38,39 @@ void EmuThread::run() {
stop_run = false; stop_run = false;
// holds whether the cpu was running during the last iteration, Common::CrashHandler(
// so that the DebugModeLeft signal can be emitted before the [&]() {
// next execution step // holds whether the cpu was running during the last iteration,
bool was_active = false; // so that the DebugModeLeft signal can be emitted before the
while (!stop_run) { // next execution step
if (running) { bool was_active = false;
if (!was_active) while (!stop_run) {
emit DebugModeLeft(); if (running) {
if (!was_active)
emit DebugModeLeft();
Core::RunLoop(); Core::RunLoop();
was_active = running || exec_step; was_active = running || exec_step;
if (!was_active && !stop_run) if (!was_active && !stop_run)
emit DebugModeEntered(); emit DebugModeEntered();
} else if (exec_step) { } else if (exec_step) {
if (!was_active) if (!was_active)
emit DebugModeLeft(); emit DebugModeLeft();
exec_step = false; exec_step = false;
Core::SingleStep(); Core::SingleStep();
emit DebugModeEntered(); emit DebugModeEntered();
yieldCurrentThread(); yieldCurrentThread();
was_active = false; was_active = false;
} else { } else {
std::unique_lock<std::mutex> lock(running_mutex); std::unique_lock<std::mutex> lock(running_mutex);
running_cv.wait(lock, [this] { return IsRunning() || exec_step || stop_run; }); running_cv.wait(lock, [this] { return IsRunning() || exec_step || stop_run; });
} }
} }
},
[&](const Common::CrashInformation& crash_info) { emit Crashed(crash_info); });
// Shutdown the core emulation // Shutdown the core emulation
System::Shutdown(); System::Shutdown();

View File

@ -19,6 +19,10 @@ class GGLWidgetInternal;
class GMainWindow; class GMainWindow;
class GRenderWindow; class GRenderWindow;
namespace Common {
struct CrashInformation;
}
class EmuThread : public QThread { class EmuThread : public QThread {
Q_OBJECT Q_OBJECT
@ -96,6 +100,14 @@ signals:
* Qt::BlockingQueuedConnection (additionally block source thread until slot returns) * Qt::BlockingQueuedConnection (additionally block source thread until slot returns)
*/ */
void DebugModeLeft(); void DebugModeLeft();
/**
* Emitted when the emulation thread crashes
*
* @warning Terminate the application soon after this signal is emitted. The program may
* not be in a well-defined state.
*/
void Crashed(const Common::CrashInformation&);
}; };
class GRenderWindow : public QWidget, public EmuWindow { class GRenderWindow : public QWidget, public EmuWindow {

View File

@ -14,6 +14,12 @@
#include "citra_qt/bootmanager.h" #include "citra_qt/bootmanager.h"
#include "citra_qt/config.h" #include "citra_qt/config.h"
#include "citra_qt/configure_dialog.h" #include "citra_qt/configure_dialog.h"
#include "citra_qt/game_list.h"
#include "citra_qt/hotkeys.h"
#include "citra_qt/main.h"
#include "citra_qt/ui_settings.h"
// Debugger
#include "citra_qt/debugger/callstack.h" #include "citra_qt/debugger/callstack.h"
#include "citra_qt/debugger/disassembler.h" #include "citra_qt/debugger/disassembler.h"
#include "citra_qt/debugger/graphics.h" #include "citra_qt/debugger/graphics.h"
@ -30,6 +36,7 @@
#include "citra_qt/hotkeys.h" #include "citra_qt/hotkeys.h"
#include "citra_qt/main.h" #include "citra_qt/main.h"
#include "citra_qt/ui_settings.h" #include "citra_qt/ui_settings.h"
#include "common/crash_handler.h"
#include "common/logging/backend.h" #include "common/logging/backend.h"
#include "common/logging/filter.h" #include "common/logging/filter.h"
#include "common/logging/log.h" #include "common/logging/log.h"
@ -378,6 +385,8 @@ void GMainWindow::BootGame(const std::string& filename) {
Qt::BlockingQueuedConnection); Qt::BlockingQueuedConnection);
connect(emu_thread.get(), SIGNAL(DebugModeLeft()), waitTreeWidget, SLOT(OnDebugModeLeft()), connect(emu_thread.get(), SIGNAL(DebugModeLeft()), waitTreeWidget, SLOT(OnDebugModeLeft()),
Qt::BlockingQueuedConnection); Qt::BlockingQueuedConnection);
connect(emu_thread.get(), SIGNAL(Crashed(Common::CrashInformation)), this,
SLOT(OnCrashed(Common::CrashInformation)), Qt::BlockingQueuedConnection);
// Update the GUI // Update the GUI
registersWidget->OnDebugModeEntered(); registersWidget->OnDebugModeEntered();
@ -576,6 +585,16 @@ void GMainWindow::OnCreateGraphicsSurfaceViewer() {
graphicsSurfaceViewerWidget->show(); graphicsSurfaceViewerWidget->show();
} }
void GMainWindow::OnCrashed(const Common::CrashInformation& crash_info) {
QString message = tr("Citra has crashed. Crash information follows:\n");
for (const auto& line : crash_info.stack_trace) {
message += QString::fromStdString(line);
message += '\n';
}
QMessageBox::critical(this, tr("Citra"), message);
QCoreApplication::exit(EXIT_FAILURE);
}
bool GMainWindow::ConfirmClose() { bool GMainWindow::ConfirmClose() {
if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) if (emu_thread == nullptr || !UISettings::values.confirm_before_closing)
return true; return true;

View File

@ -115,6 +115,7 @@ private slots:
void OnDisplayTitleBars(bool); void OnDisplayTitleBars(bool);
void ToggleWindowMode(); void ToggleWindowMode();
void OnCreateGraphicsSurfaceViewer(); void OnCreateGraphicsSurfaceViewer();
void OnCrashed(const Common::CrashInformation&);
private: private:
Ui::MainWindow ui; Ui::MainWindow ui;