Merge pull request #5284 from MarcZX100/codex/nested-exit-5277
fix(libc): finish exit handlers after nested exit
This commit is contained in:
commit
0a56aaaf47
|
|
@ -24,14 +24,17 @@ if(BUILD_TESTING)
|
|||
add_test(NAME guest_immediate_exit COMMAND guest_system_exit_tests --immediate)
|
||||
add_test(NAME guest_return_from_main COMMAND guest_system_exit_tests --return-from-main)
|
||||
add_test(NAME guest_system_relaunch COMMAND guest_system_exit_tests --relaunch-driver)
|
||||
add_test(NAME guest_nested_exit COMMAND guest_system_exit_tests --nested-exit-driver)
|
||||
set_tests_properties(guest_system_exit PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "Guest shutdown and atexit completed")
|
||||
set_tests_properties(guest_quick_exit PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "Guest quick_exit handlers completed")
|
||||
set_tests_properties(guest_system_relaunch PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "Guest relaunch completed" TIMEOUT 30)
|
||||
set_tests_properties(guest_nested_exit PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "Guest nested exit completed" TIMEOUT 30)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_system_exit guest_system_exit_parameters guest_immediate_exit guest_return_from_main guest_quick_exit guest_system_relaunch PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
set_tests_properties(guest_system_exit guest_system_exit_parameters guest_immediate_exit guest_return_from_main guest_quick_exit guest_system_relaunch guest_nested_exit PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
add_test_executable(guest_system_service_tests ${LIBS_INCLUDE_DIR}/tests/GuestSystemService.cpp)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ std::stop_source shutdownSource;
|
|||
std::atomic<bool> exitRequested{false};
|
||||
std::atomic<bool> exitStarted{false};
|
||||
using GuestExitCallback = void (APS5_VABI*)();
|
||||
thread_local bool runningExit = false;
|
||||
|
||||
void APS5_VABI RunGuestExitCallback(void* callback) {
|
||||
reinterpret_cast<GuestExitCallback>(callback)();
|
||||
|
|
@ -115,8 +116,12 @@ extern "C" {
|
|||
|
||||
[[noreturn]] void LibcExit_nid_no_patch(int code) {
|
||||
exitRequested.store(true);
|
||||
if (exitStarted.exchange(true)) LibcAwaitExit_nid_postfix();
|
||||
LibcRunShutdown_nid_postfix();
|
||||
if (exitStarted.exchange(true)) {
|
||||
if (!runningExit) LibcAwaitExit_nid_postfix();
|
||||
} else {
|
||||
runningExit = true;
|
||||
LibcRunShutdown_nid_postfix();
|
||||
}
|
||||
CxaFinalize_nid_no_patch(nullptr);
|
||||
std::exit(code);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
extern "C" int APS5_VABI sceSystemServiceLoadExec(const char*, const char* const*);
|
||||
extern "C" int APS5_VABI __cxa_atexit_nid_postfix(void (APS5_VABI *func)(void*), void* arg, void* dsoHandle);
|
||||
extern "C" void APS5_VABI _Exit_nid_postfix(int);
|
||||
extern "C" void APS5_VABI exit_nid_postfix(int);
|
||||
extern "C" void APS5_VABI catchReturnFromMain_nid_postfix(int);
|
||||
using GuestQuickExitCallback = void (APS5_VABI*)();
|
||||
extern "C" int APS5_VABI at_quick_exit_nid_postfix(GuestQuickExitCallback);
|
||||
|
|
@ -71,9 +72,11 @@ void AppendMarker(const std::string& line) {
|
|||
}
|
||||
void MainShutdown() { AppendMarker("shutdown"); }
|
||||
void SecondaryShutdown() { AppendMarker("secondary shutdown"); }
|
||||
int RunRelaunchingChild(const std::filesystem::path& self) {
|
||||
void APS5_VABI RemainingHandler(void*) { AppendMarker("remaining handler"); }
|
||||
void APS5_VABI ExitingHandler(void*) { exit_nid_postfix(7); }
|
||||
int RunChild(const std::filesystem::path& self, const char* mode) {
|
||||
#ifdef _WIN32
|
||||
std::wstring commandLine = L"\"" + self.wstring() + L"\" --relaunch";
|
||||
std::wstring commandLine = L"\"" + self.wstring() + L"\" " + std::wstring(mode, mode + std::strlen(mode));
|
||||
STARTUPINFOW startup{};
|
||||
startup.cb = sizeof(startup);
|
||||
PROCESS_INFORMATION process{};
|
||||
|
|
@ -88,7 +91,7 @@ int RunRelaunchingChild(const std::filesystem::path& self) {
|
|||
const pid_t child = fork();
|
||||
Require(child >= 0);
|
||||
if (child == 0) {
|
||||
execl(self.c_str(), self.c_str(), "--relaunch", static_cast<char*>(nullptr));
|
||||
execl(self.c_str(), self.c_str(), mode, static_cast<char*>(nullptr));
|
||||
std::_Exit(127);
|
||||
}
|
||||
int status = 0;
|
||||
|
|
@ -96,6 +99,23 @@ int RunRelaunchingChild(const std::filesystem::path& self) {
|
|||
return WIFEXITED(status) ? WEXITSTATUS(status) : 1;
|
||||
#endif
|
||||
}
|
||||
int DriveNestedExit() {
|
||||
const auto self = OwnExecutable();
|
||||
const auto marker = std::filesystem::temp_directory_path() / ("anyps5-nested-exit-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()) + ".txt");
|
||||
SetVariable(RelaunchMarker, marker.string().c_str());
|
||||
const int code = RunChild(self, "--nested-exit");
|
||||
std::string text;
|
||||
{
|
||||
std::ifstream file(marker);
|
||||
text.assign(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
|
||||
}
|
||||
std::error_code ignored;
|
||||
std::filesystem::remove(marker, ignored);
|
||||
Require(code == 7);
|
||||
Require(text == "remaining handler\n");
|
||||
std::puts("Guest nested exit completed");
|
||||
return 0;
|
||||
}
|
||||
int DriveRelaunch() {
|
||||
const auto self = OwnExecutable();
|
||||
const auto secondary = self.parent_path() / ("picker.picker.bin" + self.extension().string());
|
||||
|
|
@ -103,7 +123,7 @@ int DriveRelaunch() {
|
|||
const auto marker = std::filesystem::temp_directory_path() / ("anyps5-relaunch-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()) + ".txt");
|
||||
SetVariable(RelaunchMarker, marker.string().c_str());
|
||||
SetVariable(MainExecutable, self.string().c_str());
|
||||
Require(RunRelaunchingChild(self) == 0);
|
||||
Require(RunChild(self, "--relaunch") == 0);
|
||||
std::string text;
|
||||
for (int attempt = 0; attempt < 200 && text.find("relaunched") == std::string::npos; ++attempt) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
|
|
@ -140,6 +160,15 @@ int main(int argc, char** argv) {
|
|||
quick_exit_nid_postfix(0);
|
||||
return 2;
|
||||
}
|
||||
if (argc > 1 && std::strcmp(argv[1], "--nested-exit-driver") == 0) {
|
||||
return DriveNestedExit();
|
||||
}
|
||||
if (argc > 1 && std::strcmp(argv[1], "--nested-exit") == 0) {
|
||||
Require(__cxa_atexit_nid_postfix(RemainingHandler, nullptr, nullptr) == 0);
|
||||
Require(__cxa_atexit_nid_postfix(ExitingHandler, nullptr, nullptr) == 0);
|
||||
exit_nid_postfix(0);
|
||||
return 2;
|
||||
}
|
||||
if (argc > 1 && std::strcmp(argv[1], "--relaunch-driver") == 0) {
|
||||
return DriveRelaunch();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue