Skip to content

Commit 2b66690

Browse files
authored
Merge pull request #1876 from malucard/quitting
Fix quitting issue again
2 parents 17a8883 + 047f0c2 commit 2b66690

File tree

4 files changed

+38
-18
lines changed

4 files changed

+38
-18
lines changed

src/core/DynaRec_aa64/recompiler.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,6 @@ void DynaRecCPU::emitDispatcher() {
169169
gen.Str(contextPointer,
170170
MemOperand(sp, -16, PreIndex)); // Save contextPointer register in stack (also align stack pointer)
171171

172-
gen.Mov(runningPointer, (uintptr_t)PCSX::g_system->runningPtr()); // Move runningPtr to runningPointer register
173172
gen.Mov(contextPointer, (uintptr_t)this); // Load context pointer
174173

175174
// Back up all our allocateable volatile regs
@@ -188,8 +187,12 @@ void DynaRecCPU::emitDispatcher() {
188187

189188
loadThisPointer(arg1.X()); // Poll events
190189
call(recBranchTestWrapper);
190+
gen.Mov(runningPointer, (uintptr_t)PCSX::g_system->runningPtr()); // Move runningPtr to runningPointer register
191191
gen.Ldrb(w0, MemOperand(runningPointer)); // Check if PCSX::g_system->running is true
192192
gen.Cbz(w0, &done); // If it's not, return
193+
gen.Mov(runningPointer, (uintptr_t)PCSX::g_system->quittingPtr()); // Load pointer to "quitting" variable
194+
gen.Ldrb(w0, MemOperand(runningPointer)); // Check if PCSX::g_system->quitting is true
195+
gen.Cbnz(w0, &done); // If it is, return
193196
emitBlockLookup(); // Otherwise, look up next block
194197

195198
gen.align();

src/core/DynaRec_x64/recompiler.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,6 @@ void DynaRecCPU::emitDispatcher() {
186186
gen.push(reg.cvt64());
187187
}
188188
gen.mov(qword[contextPointer + HOST_REG_CACHE_OFFSET(0)], runningPointer); // Backup running pointer
189-
gen.mov(runningPointer, (uintptr_t)PCSX::g_system->runningPtr()); // Load pointer to "running" variable
190189

191190
// Allocate shadow stack space on Windows
192191
if constexpr (isWindows()) {
@@ -202,8 +201,12 @@ void DynaRecCPU::emitDispatcher() {
202201

203202
// Poll events
204203
emitMemberFunctionCall(&PCSX::R3000Acpu::branchTest, this);
204+
gen.mov(runningPointer, (uintptr_t)PCSX::g_system->runningPtr()); // Load pointer to "running" variable
205205
gen.test(Xbyak::util::byte[runningPointer], 1); // Check if PCSX::g_system->running is true
206206
gen.jz(done); // If it's not, return
207+
gen.mov(runningPointer, (uintptr_t)PCSX::g_system->quittingPtr()); // Load pointer to "quitting" variable
208+
gen.test(Xbyak::util::byte[runningPointer], 1); // Check if PCSX::g_system->running is true
209+
gen.jnz(done); // If it is, return
207210
emitBlockLookup(); // Otherwise, look up next block
208211

209212
gen.align(16);

src/core/system.h

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,12 @@ class System {
163163
// Close mem and plugins
164164
virtual void close() = 0;
165165
virtual void purgeAllEvents() = 0;
166-
bool running() { return m_running; }
166+
bool running() {
167+
std::atomic_signal_fence(std::memory_order_relaxed);
168+
return m_running && !m_quitting;
169+
}
167170
const bool *runningPtr() { return &m_running; }
171+
const bool *quittingPtr() { return &m_quitting; }
168172
bool quitting() { return m_quitting; }
169173
int exitCode() { return m_exitCode; }
170174
bool emergencyExit() { return m_emergencyExit; }
@@ -179,12 +183,10 @@ class System {
179183
m_eventBus->signal(Events::ExecutionFlow::Run{});
180184
}
181185
virtual void testQuit(int code) = 0;
186+
// This needs to only mutate variables, as it requires to be signal-safe.
182187
[[gnu::cold]] void quit(int code = 0) {
183188
m_quitting = true;
184-
pause();
185189
m_exitCode = code;
186-
m_eventBus->signal(Events::Quitting{});
187-
purgeAllEvents();
188190
}
189191

190192
std::shared_ptr<EventBus::EventBus> m_eventBus = std::make_shared<EventBus::EventBus>();
@@ -257,7 +259,17 @@ class System {
257259
std::map<uint64_t, std::string> m_i18n;
258260
std::map<std::string, decltype(m_i18n)> m_locales;
259261
std::string m_currentLocale;
262+
// If true, indicates that the emulator is currently capturing the main loop
263+
// and actively emulates the PSX hardware. If false, the emulator is paused,
264+
// waiting for user input or other events inside the UI. The way the UI
265+
// is refreshed is by calling update() periodically, so this boolean affects
266+
// the moment when and how update() is called.
260267
bool m_running = false;
268+
// If true, indicates that the emulator is quitting. This can be set by a
269+
// number of events, including the user pressing the quit button or the
270+
// emulator itself requesting a quit due to testing for instance. This will
271+
// cause the two main loop to exit: the inner one being the emulator itself,
272+
// and the outer one being the main.cc loop.
261273
bool m_quitting = false;
262274
int m_exitCode = 0;
263275
struct LocaleInfo {

src/main/main.cc

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,6 @@ class SystemImpl final : public PCSX::System {
116116
// emulator is requesting a shutdown of the emulation
117117
}
118118

119-
virtual void purgeAllEvents() final override { uv_run(getLoop(), UV_RUN_DEFAULT); }
120-
121119
virtual void testQuit(int code) final override {
122120
if (m_args.isTestModeEnabled()) {
123121
quit(code);
@@ -134,6 +132,8 @@ class SystemImpl final : public PCSX::System {
134132
const PCSX::Arguments m_args;
135133

136134
public:
135+
virtual void purgeAllEvents() final override { uv_run(getLoop(), UV_RUN_DEFAULT); }
136+
137137
void setBinDir(std::filesystem::path path) {
138138
m_binDir = path;
139139
m_version.loadFromFile(new PCSX::PosixFile(path / "version.json"));
@@ -166,6 +166,10 @@ struct Cleaner {
166166
std::function<void()> f;
167167
};
168168

169+
void handleSignal(int signal) {
170+
PCSX::g_system->quit(-1);
171+
}
172+
169173
int pcsxMain(int argc, char **argv) {
170174
ZoneScoped;
171175
// Command line arguments are parsed after this point.
@@ -193,11 +197,10 @@ int pcsxMain(int argc, char **argv) {
193197
// enabled as much as possible.
194198
SystemImpl *system = new SystemImpl(args);
195199
PCSX::g_system = system;
196-
static std::atomic_bool scheduledQuit = false;
197-
auto sigint = std::signal(SIGINT, [](auto signal) { scheduledQuit = true; });
198-
auto sigterm = std::signal(SIGTERM, [](auto signal) { scheduledQuit = true; });
200+
auto sigint = std::signal(SIGINT, handleSignal);
201+
auto sigterm = std::signal(SIGTERM, handleSignal);
199202
#ifndef _WIN32
200-
signal(SIGPIPE, SIG_IGN);
203+
std::signal(SIGPIPE, SIG_IGN);
201204
#endif
202205
const auto &logfileArgOpt = args.get<std::string>("logfile");
203206
const PCSX::u8string logfileArg = MAKEU8(logfileArgOpt.has_value() ? logfileArgOpt->c_str() : "");
@@ -451,15 +454,14 @@ runner.init({
451454
emulator->m_cpu->Execute();
452455
} else {
453456
// The "update" method will be called periodically by the emulator while
454-
// meaning if we want our UI to work, we have to manually call "update"
455-
// when the emulator is paused.
457+
// it's running, meaning if we want our UI to work, we have to manually
458+
// call "update" when the emulator is paused.
456459
s_ui->update();
457460
}
458-
if (scheduledQuit) {
459-
PCSX::g_system->quit(-1);
460-
return exitCode;
461-
}
462461
}
462+
system->pause();
463+
system->m_eventBus->signal(PCSX::Events::Quitting{});
464+
system->purgeAllEvents();
463465
} catch (...) {
464466
// This will ensure we don't do certain cleanups that are awaiting other tasks,
465467
// which could result in deadlocks on exit in case we encountered a serious problem.

0 commit comments

Comments
 (0)