mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-26 11:24:15 +01:00
Sleep-loop rather than abort during termination
We don't want to actually exit the process as it'll automatically be restarted gracefully due to a timeout after being unable to exit within a fixed duration so we just want to infinite sleep during termination. This should fix issues where exiting any game would cause the app to force close after some time as exception signal handling would fail in the background, the app should stay open now and automatically restart itself when another game is loaded in.
This commit is contained in:
parent
ea00f1bb82
commit
164d4852fa
@ -14,7 +14,12 @@ namespace skyline::signal {
|
|||||||
std::rethrow_exception(SignalExceptionPtr);
|
std::rethrow_exception(SignalExceptionPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::terminate_handler terminateHandler{};
|
void SleepTillExit() {
|
||||||
|
// We don't want to actually exit the process ourselves as it'll automatically be restarted gracefully due to a timeout after being unable to exit within a fixed duration
|
||||||
|
Logger::EmulationContext.TryFlush(); // We want to attempt to flush logs before exiting
|
||||||
|
while (true)
|
||||||
|
sleep(std::numeric_limits<int>::max()); // We just trigger the timeout wait by sleeping forever
|
||||||
|
}
|
||||||
|
|
||||||
inline StackFrame *SafeFrameRecurse(size_t depth, StackFrame *frame) {
|
inline StackFrame *SafeFrameRecurse(size_t depth, StackFrame *frame) {
|
||||||
if (frame) {
|
if (frame) {
|
||||||
@ -22,17 +27,17 @@ namespace skyline::signal {
|
|||||||
if (frame->lr && frame->next)
|
if (frame->lr && frame->next)
|
||||||
frame = frame->next;
|
frame = frame->next;
|
||||||
else
|
else
|
||||||
terminateHandler();
|
SleepTillExit();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
terminateHandler();
|
SleepTillExit();
|
||||||
}
|
}
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerminateHandler() {
|
void TerminateHandler() {
|
||||||
auto exception{std::current_exception()};
|
auto exception{std::current_exception()};
|
||||||
if (terminateHandler && exception && exception == SignalExceptionPtr) {
|
if (exception && exception == SignalExceptionPtr) {
|
||||||
StackFrame *frame;
|
StackFrame *frame;
|
||||||
asm("MOV %0, FP" : "=r"(frame));
|
asm("MOV %0, FP" : "=r"(frame));
|
||||||
frame = SafeFrameRecurse(2, frame); // We unroll past 'std::terminate'
|
frame = SafeFrameRecurse(2, frame); // We unroll past 'std::terminate'
|
||||||
@ -56,17 +61,14 @@ namespace skyline::signal {
|
|||||||
frame = SafeFrameRecurse(2, lookupFrame);
|
frame = SafeFrameRecurse(2, lookupFrame);
|
||||||
hasAdvanced = true;
|
hasAdvanced = true;
|
||||||
} else {
|
} else {
|
||||||
Logger::EmulationContext.TryFlush();
|
SleepTillExit(); // We presumably have no exception handlers left on the stack to consume the exception, it's time to quit
|
||||||
terminateHandler(); // We presumably have no exception handlers left on the stack to consume the exception, it's time to quit
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lookupFrame = lookupFrame->next;
|
lookupFrame = lookupFrame->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!frame->next) {
|
if (!frame->next)
|
||||||
Logger::EmulationContext.TryFlush(); // We want to attempt to flush all logs before quitting
|
SleepTillExit(); // We don't know the frame's stack boundaries, the only option is to quit
|
||||||
terminateHandler(); // We don't know the frame's stack boundaries, the only option is to quit
|
|
||||||
}
|
|
||||||
|
|
||||||
asm("MOV SP, %x0\n\t" // Stack frame is the first item on a function's stack, it's used to calculate calling function's stack pointer
|
asm("MOV SP, %x0\n\t" // Stack frame is the first item on a function's stack, it's used to calculate calling function's stack pointer
|
||||||
"MOV LR, %x1\n\t"
|
"MOV LR, %x1\n\t"
|
||||||
@ -76,7 +78,7 @@ namespace skyline::signal {
|
|||||||
|
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
} else {
|
} else {
|
||||||
terminateHandler();
|
SleepTillExit(); // We don't want to delegate to the older terminate handler as it might cause an exit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,11 +99,7 @@ namespace skyline::signal {
|
|||||||
SignalExceptionPtr = std::make_exception_ptr(signalException);
|
SignalExceptionPtr = std::make_exception_ptr(signalException);
|
||||||
context->uc_mcontext.pc = reinterpret_cast<u64>(&ExceptionThrow);
|
context->uc_mcontext.pc = reinterpret_cast<u64>(&ExceptionThrow);
|
||||||
|
|
||||||
auto handler{std::get_terminate()};
|
|
||||||
if (handler != TerminateHandler) {
|
|
||||||
terminateHandler = handler;
|
|
||||||
std::set_terminate(TerminateHandler);
|
std::set_terminate(TerminateHandler);
|
||||||
}
|
|
||||||
|
|
||||||
Logger::EmulationContext.TryFlush(); // We want to attempt to flush all logs in case exception handling fails and infloops
|
Logger::EmulationContext.TryFlush(); // We want to attempt to flush all logs in case exception handling fails and infloops
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user