#include "SceTypes.hpp" #include "prx/libc/include/general/VabiMacros.hpp" #include #include #include #include #include struct GuestSignalSet { std::uint32_t bits[4]; }; struct GuestTimespec { std::int64_t seconds; std::int64_t nanoseconds; }; struct GuestSiginfo { std::int32_t signo; std::int32_t error; std::int32_t code; std::int32_t pid; std::uint32_t uid; std::int32_t status; std::uintptr_t address; std::int32_t value; std::int32_t valueTail; std::int64_t band; std::int32_t spare[7]; std::int32_t tail; }; using Handler = void (APS5_VABI *)(int); extern "C" { int APS5_VABI sigtimedwait_nid_postfix(const GuestSignalSet*, void*, const GuestTimespec*); int APS5_VABI sigwaitinfo_nid_postfix(const GuestSignalSet*, void*); int APS5_VABI sigwait_nid_postfix(const GuestSignalSet*, int*); int APS5_VABI pause_nid_postfix(void); Handler APS5_VABI signal_nid_postfix(int, Handler); int APS5_VABI raise_nid_postfix(int); int APS5_VABI kill_nid_postfix(int, int); int APS5_VABI _sigprocmask_nid_postfix(int, const GuestSignalSet*, GuestSignalSet*); int APS5_VABI getpid_nid_postfix(void); Pthread APS5_VABI scePthreadSelf(void); int APS5_VABI scePthreadCreate(Pthread* thread, const PthreadAttr* attr, PthreadEntry entry, void* arg, const char* name); int APS5_VABI scePthreadJoin(Pthread thread, void** retval); int APS5_VABI pthread_kill_nid_postfix(Pthread thread, int guest); int* APS5_VABI __error_nid_postfix(); } volatile int received = 0; void APS5_VABI Callback(int value) { received = value; } static void Require(bool value) { if (!value) std::abort(); } static void RequireUntouched(const GuestSiginfo& info) { const GuestSiginfo empty{}; Require(std::memcmp(&info, &empty, sizeof(info)) == 0); } struct Sender { Pthread target = nullptr; int guest = 0; int result = -1; }; static void* APS5_VABI Send(void* arg) { auto& sender = *static_cast(arg); std::this_thread::sleep_for(std::chrono::milliseconds(50)); sender.result = pthread_kill_nid_postfix(sender.target, sender.guest); return nullptr; } static void* APS5_VABI SendWithoutDelay(void* arg) { auto& sender = *static_cast(arg); sender.result = pthread_kill_nid_postfix(sender.target, sender.guest); return nullptr; } static Pthread StartSender(Sender& sender) { Pthread thread = nullptr; Require(scePthreadCreate(&thread, nullptr, Send, &sender, nullptr) == 0); return thread; } static Pthread StartSenderWithoutDelay(Sender& sender) { Pthread thread = nullptr; Require(scePthreadCreate(&thread, nullptr, SendWithoutDelay, &sender, nullptr) == 0); return thread; } static void JoinSender(Pthread thread, const Sender& sender) { Require(scePthreadJoin(thread, nullptr) == 0 && sender.result == 0); } int main() { const GuestSignalSet empty{{0, 0, 0, 0}}; const GuestSignalSet pipe{{1u << 12, 0, 0, 0}}; const GuestSignalSet interrupt{{1u << 1, 0, 0, 0}}; const GuestTimespec poll{0, 0}; const GuestTimespec expired{0, 1000000000}; GuestSiginfo info{}; int taken = -1; *__error_nid_postfix() = 0; Require(sigtimedwait_nid_postfix(nullptr, &info, &poll) == -1 && *__error_nid_postfix() == 22); *__error_nid_postfix() = 0; Require(sigtimedwait_nid_postfix(&empty, &info, &poll) == -1 && *__error_nid_postfix() == 22); *__error_nid_postfix() = 0; Require(sigwaitinfo_nid_postfix(nullptr, &info) == -1 && *__error_nid_postfix() == 22); *__error_nid_postfix() = 0; Require(sigwaitinfo_nid_postfix(&empty, &info) == -1 && *__error_nid_postfix() == 22); *__error_nid_postfix() = 71; Require(sigwait_nid_postfix(nullptr, &taken) == 22 && *__error_nid_postfix() == 71 && taken == -1); *__error_nid_postfix() = 72; Require(sigwait_nid_postfix(&empty, &taken) == 22 && *__error_nid_postfix() == 72 && taken == -1); *__error_nid_postfix() = 73; Require(sigwait_nid_postfix(&interrupt, nullptr) == 22 && *__error_nid_postfix() == 73); RequireUntouched(info); *__error_nid_postfix() = 0; Require(sigtimedwait_nid_postfix(&interrupt, &info, &poll) == -1 && *__error_nid_postfix() == 35); *__error_nid_postfix() = 0; Require(sigtimedwait_nid_postfix(&interrupt, &info, &expired) == -1 && *__error_nid_postfix() == 22); RequireUntouched(info); GuestSignalSet previous{}; Require(signal_nid_postfix(2, Callback) != reinterpret_cast(static_cast(-1))); Require(_sigprocmask_nid_postfix(1, &interrupt, &previous) == 0); received = 0; Require(raise_nid_postfix(2) == 0 && received == 0); Require(sigwait_nid_postfix(&interrupt, &taken) == 0 && taken == 2 && received == 0); Require(raise_nid_postfix(2) == 0 && received == 0); Require(sigtimedwait_nid_postfix(&interrupt, &info, &poll) == 2 && received == 0); Require(info.signo == 2 && info.error == 0 && info.code == 0 && info.pid == getpid_nid_postfix() && info.uid == 0); Require(info.status == 0 && info.address == 0 && info.value == 0 && info.band == 0); Require(raise_nid_postfix(2) == 0 && received == 0); Require(sigwaitinfo_nid_postfix(&interrupt, &info) == 2 && received == 0); Require(info.signo == 2 && info.code == 0 && info.pid == getpid_nid_postfix()); Require(raise_nid_postfix(2) == 0 && received == 0); Require(sigwaitinfo_nid_postfix(&interrupt, nullptr) == 2 && received == 0); Require(raise_nid_postfix(2) == 0 && received == 0); Require(sigtimedwait_nid_postfix(&interrupt, nullptr, nullptr) == 2 && received == 0); GuestSignalSet current{}; Require(_sigprocmask_nid_postfix(1, nullptr, ¤t) == 0 && current.bits[0] == (previous.bits[0] | interrupt.bits[0])); Require(_sigprocmask_nid_postfix(3, &previous, nullptr) == 0); received = 0; Require(raise_nid_postfix(2) == 0 && received == 2); Require(_sigprocmask_nid_postfix(1, &pipe, &previous) == 0); received = 0; Require(raise_nid_postfix(13) == 0 && received == 0); Require(sigwaitinfo_nid_postfix(&pipe, &info) == 13 && info.signo == 13 && info.pid == getpid_nid_postfix()); Require(_sigprocmask_nid_postfix(3, &previous, nullptr) == 0); const Pthread self = scePthreadSelf(); *__error_nid_postfix() = 0; Require(pthread_kill_nid_postfix(nullptr, 13) == 3 && *__error_nid_postfix() == 0); Require(pthread_kill_nid_postfix(self, 129) == 22); Sender sender{self, 13, -1}; Pthread senderThread = StartSender(sender); Require(sigwaitinfo_nid_postfix(&pipe, &info) == 13); JoinSender(senderThread, sender); Require(info.signo == 13 && info.code == 0 && info.pid == getpid_nid_postfix()); senderThread = StartSender(sender); Require(sigtimedwait_nid_postfix(&pipe, nullptr, nullptr) == 13); JoinSender(senderThread, sender); Require(signal_nid_postfix(15, Callback) != reinterpret_cast(static_cast(-1))); senderThread = StartSender(sender = Sender{self, 15, -1}); received = 0; *__error_nid_postfix() = 0; Require(pause_nid_postfix() == -1 && *__error_nid_postfix() == 4 && received == 15); JoinSender(senderThread, sender); Require(signal_nid_postfix(15, nullptr) == Callback); // The senders above sleep 50 ms first, so the signal always arrives while the wait is // already blocked. A raise landing between the check of the pending set and the wait // used to be lost, and the wait then never returned, so raise with no delay instead, // many times. Require(_sigprocmask_nid_postfix(1, &interrupt, &previous) == 0); for (int round = 0; round < 500; ++round) { Sender tight{self, 2, -1}; const Pthread senderThread = StartSenderWithoutDelay(tight); Require(sigwait_nid_postfix(&interrupt, &taken) == 0 && taken == 2); JoinSender(senderThread, tight); } Require(_sigprocmask_nid_postfix(3, &previous, nullptr) == 0); }