#include "prx/libkernel/include/Api.hpp" #include "prx/libSceLibcInternal/include/Api.hpp" #include "SceTypes.hpp" #include #include #include #include namespace { using Destructor = void (APS5_VABI*)(void*); void Require(bool value) { if (!value) std::abort(); } int dsoHandle = 0; std::vector calls; std::vector callers; void* Object(std::intptr_t value) { return reinterpret_cast(value); } int Register(Destructor destructor, std::intptr_t object) { return _sceLibcInternalThreadAtexit_nid_postfix(destructor, Object(object), &dsoHandle); } void APS5_VABI Record(void* object) { calls.push_back(reinterpret_cast(object)); callers.push_back(scePthreadSelf()); } void APS5_VABI RecordAndRegister(void* object) { Record(object); Require(Register(Record, 9) == 0); } void* APS5_VABI Worker(void*) { Require(Register(Record, 4) == 0); Require(Register(Record, 5) == 0); return nullptr; } bool DestructorsThrow() { try { _sceLibcInternalThreadDtors_nid_postfix(); } catch (const std::runtime_error&) { return true; } return false; } } int main() { const Pthread mainThread = scePthreadSelf(); Require(Register(Record, 1) == 0); Require(Register(RecordAndRegister, 2) == 0); Require(Register(Record, 3) == 0); _sceLibcInternalThreadDtors_nid_postfix(); Require(calls == std::vector{3, 2, 9, 1}); Require(callers == std::vector(4, mainThread)); _sceLibcInternalThreadDtors_nid_postfix(); Require(calls.size() == 4); calls.clear(); callers.clear(); Pthread worker = nullptr; Require(scePthreadCreate(&worker, nullptr, Worker, nullptr, "ThreadAtexit") == 0); Require(scePthreadJoin(worker, nullptr) == 0); Require(calls == std::vector{5, 4}); Require(callers == std::vector(2, worker)); calls.clear(); std::vector heap(64); Require(Register(Record, 6) == 0); Require(Register(nullptr, 7) == 0); Require(Register(reinterpret_cast(heap.data()), 8) == 0); Require(DestructorsThrow()); Require(DestructorsThrow()); Require(calls.empty()); _sceLibcInternalThreadDtors_nid_postfix(); Require(calls == std::vector{6}); }