mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-25 17:40:13 +00:00
citra_qt: Show critical QMessageBox when EmuThread crashes
This commit is contained in:
parent
710b70f555
commit
1bfa44c317
@ -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();
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user