feat(system): handle console exit through runtime shutdown

This commit is contained in:
SamG-Coder 2026-09-25 07:02:37 +10:00
parent 79edb20f17
commit 2920c7f04c
4 changed files with 71 additions and 0 deletions

View File

@ -104,6 +104,18 @@ endforeach()
add_custom_target(libs DEPENDS ${PATCHED_OUTPUTS})
if(BUILD_TESTING)
add_executable(guest_system_exit_tests tests/GuestSystemExit.cpp)
target_include_directories(guest_system_exit_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(guest_system_exit_tests PRIVATE libSceSystemService libc)
configure_windows_unwind(guest_system_exit_tests)
add_test(NAME guest_system_exit_parameters COMMAND guest_system_exit_tests)
add_test(NAME guest_system_exit COMMAND guest_system_exit_tests --exit)
set_tests_properties(guest_system_exit PROPERTIES
PASS_REGULAR_EXPRESSION "Guest shutdown and atexit completed")
if(WIN32)
set_tests_properties(guest_system_exit guest_system_exit_parameters PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
add_executable(guest_character_tests tests/GuestCharacter.cpp)
target_include_directories(guest_character_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(guest_character_tests PRIVATE libc)

View File

@ -1,12 +1,24 @@
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <cstdlib>
#include "prx/libc/include/Shutdown.hpp"
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
#include "prx/libSceSystemService/SystemService.hpp"
extern "C" {
int APS5_VABI sceSystemServiceLoadExec(const char* path, const char* const* arguments) {
if (!path || !*path) return SYSTEM_SERVICE_ERROR_PARAMETER;
if (std::strcmp(path, "exit") != 0) {
NotImplemented_nid_no_patch("sceSystemServiceLoadExec: executable replacement");
}
(void)arguments;
LibcRunShutdown_nid_postfix();
std::exit(0);
}
int APS5_VABI sceSystemServiceDisableNoticeScreenSkipFlagAutoSet(void) {
NotImplemented_nid_no_patch(__func__);
return 0;

View File

@ -0,0 +1,30 @@
#include "prx/libc/include/general/VabiMacros.hpp"
#include "prx/libc/include/Shutdown.hpp"
#include "prx/libSceSystemService/SystemService.hpp"
#include <cstdio>
#include <cstdlib>
#include <stdexcept>
extern "C" int APS5_VABI sceSystemServiceLoadExec(const char*, const char* const*);
namespace {
bool cleaned = false;
void Cleanup() { cleaned = true; }
void VerifyExit() {
if (!cleaned) std::_Exit(1);
std::puts("Guest shutdown and atexit completed");
}
void Require(bool value) { if (!value) std::abort(); }
}
int main(int argc, char**) {
if (argc > 1) {
LibcRegisterShutdown_nid_postfix(Cleanup);
Require(std::atexit(VerifyExit) == 0);
sceSystemServiceLoadExec("exit", nullptr);
return 2;
}
Require(sceSystemServiceLoadExec(nullptr, nullptr) == SYSTEM_SERVICE_ERROR_PARAMETER);
Require(sceSystemServiceLoadExec("", nullptr) == SYSTEM_SERVICE_ERROR_PARAMETER);
bool rejected = false;
try { sceSystemServiceLoadExec("/app0/another.bin", nullptr); }
catch (const std::runtime_error&) { rejected = true; }
Require(rejected);
}

View File

@ -391,3 +391,20 @@ Latest unchanged-game startup resolves ftello and stops at `JoBqSQt1yyA`
shows it requests the console's `exit` operation from its quit path. This is
source evidence only; the guest entry point still has not executed and no frame
has been rendered.
## Follow-up: console exit request
Implemented sceSystemServiceLoadExec for the `exit` operation through the shared
runtime shutdown callbacks followed by normal process exit. Null/empty paths
return the existing system-service parameter error. Replacing the process with
another executable remains explicitly unsupported and raises the runtime's
existing not-implemented diagnostic; it does not report a successful launch.
An isolated CTest process verifies that shutdown callbacks execute before
atexit handlers and that the service does not return after requesting exit.
A separate test checks invalid arguments and executable-replacement rejection.
All twenty-three tests pass and libraries rebuild.
The unchanged game resolves sceSystemServiceLoadExec and now stops at
`gkWgn0p1AfU` (`freopen`). This does not establish that the game has executed
its quit path: guest entry-point execution and rendered output remain unverified.