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

View File

@ -19,6 +19,10 @@ class GGLWidgetInternal;
class GMainWindow;
class GRenderWindow;
namespace Common {
struct CrashInformation;
}
class EmuThread : public QThread {
Q_OBJECT
@ -96,6 +100,14 @@ signals:
* Qt::BlockingQueuedConnection (additionally block source thread until slot returns)
*/
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 {

View File

@ -14,6 +14,12 @@
#include "citra_qt/bootmanager.h"
#include "citra_qt/config.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/disassembler.h"
#include "citra_qt/debugger/graphics.h"
@ -30,6 +36,7 @@
#include "citra_qt/hotkeys.h"
#include "citra_qt/main.h"
#include "citra_qt/ui_settings.h"
#include "common/crash_handler.h"
#include "common/logging/backend.h"
#include "common/logging/filter.h"
#include "common/logging/log.h"
@ -378,6 +385,8 @@ void GMainWindow::BootGame(const std::string& filename) {
Qt::BlockingQueuedConnection);
connect(emu_thread.get(), SIGNAL(DebugModeLeft()), waitTreeWidget, SLOT(OnDebugModeLeft()),
Qt::BlockingQueuedConnection);
connect(emu_thread.get(), SIGNAL(Crashed(Common::CrashInformation)), this,
SLOT(OnCrashed(Common::CrashInformation)), Qt::BlockingQueuedConnection);
// Update the GUI
registersWidget->OnDebugModeEntered();
@ -576,6 +585,16 @@ void GMainWindow::OnCreateGraphicsSurfaceViewer() {
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() {
if (emu_thread == nullptr || !UISettings::values.confirm_before_closing)
return true;

View File

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