fixes#1960
this commit implements one particular approach for exiting emulation
when the RPX being emulated calls `coreinit.exit`. I don't believe
this might be the best way long term, but it seemed to be the best
way given the state (and my knowledge of the codebase). This threads
through 'End Emulation' (normally a debug only feature in the Cemu
menu) into one more spot in the codebase, when `coreinit.exit` is
called. Why did we go this way?
Stopping PPC Emulation _while_ the emulator is actively executing
an instruction (the call to `coreinit.exit`) seemed like a path of
el derado everytime i tried it. calling `Shutdown`, or `ShutdownTitle`
is not ideal because it doesn't do things like update status in
discord or any of the other window actions, and they lock up because
the emulator is already running the coreinit instructions (even if
you launch it in a delayed thread, the PPC emulator is still doing
stuff).
so the only way to get this to somewhat work is _to reach out to the
window system_. So I threaded through an `EndEmulation` request, which
started off just calling `EndEmulation` that already existed. There is
a note on that function about how it memory leaks if called repeatedly,
and it's "not finished". However, this seemed better than looping
forever, or just crashing with a debug assert. At least you still have
a semi-functional window (even if memory is leaking), and a log window
you can investigate?
However, just calling endemulation didn't exit when Cemu was launched
from the command line (my goal), it just returns to the main Cemu
window. To make Cemu usable as a command line app that you can fire
and forget, I threaded a new variable through, that when end emulation
is called and the title was launched with `-g`, or `-t`, it just closes
cemu altogether. this allows my CLI commands to "just work"
This is a first pass for now, more work is needed mostly for UI polish.
Changes in this commit:
- Debugger now exposes a thread-safe API. Previously everything would just access internal debugger state directly without regard for race conditions
- Reworked stepping logic to be more reliable. For example previously Cemu could get forever stuck in the middle of stepping to the next instruction
- Support for debugging while using multi-threaded CPU emulation. Originally the debugger was added when only single core support existed in Cemu. It was possible to debug multi-threaded before but it was very very prone to state corruptions.
- Debugger should now remember breakpoints correctly across sessions