mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-30 12:25:49 +00:00
Main's #10706 moves the declarations of exported functions and their types into the libraries' public headers, and gives WaitForPendingInSet a KernelTimespec timeout. The merge keeps this branch's DeliverUnblockedPending and ChangeBlockedMask with main's KernelTimespec. It takes main's side of the declarations in GuestSignalSets.cpp, whose setjmp and longjmp this branch had added and libc's Api.hpp now declares. GuestSignalHandlerMask.cpp includes the libkernel and libc public headers in place of its own declarations and GuestSignalSet and GuestSigaction types, as the public_headers audit requires.
180 lines
5.5 KiB
C++
180 lines
5.5 KiB
C++
#include "prx/libkernel/include/Api.hpp"
|
|
#include "prx/libc/include/Api.hpp"
|
|
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <thread>
|
|
|
|
static constexpr int SigKill = 9;
|
|
static constexpr int SigTerm = 15;
|
|
static constexpr int SigUsr1 = 30;
|
|
static constexpr int SigUsr2 = 31;
|
|
static constexpr int SaRestart = 0x2;
|
|
static constexpr int SaResethand = 0x4;
|
|
static constexpr int SaNodefer = 0x10;
|
|
static constexpr int SigBlock = 1;
|
|
static constexpr int SigUnblock = 2;
|
|
|
|
static std::uint32_t Bit(int signal) { return 1u << (signal - 1); }
|
|
|
|
static void Require(bool value) { if (!value) std::abort(); }
|
|
|
|
static int calls = 0;
|
|
static int callsAfterNestedRaise = 0;
|
|
static std::uint32_t maskInHandler = 0;
|
|
|
|
static std::uint32_t CurrentMask() {
|
|
GuestSignalSet set{};
|
|
Require(sigprocmask_nid_postfix(SigBlock, nullptr, &set) == 0);
|
|
return set.bits[0];
|
|
}
|
|
|
|
static void APS5_VABI RaiseAgain(int signal) {
|
|
if (++calls == 1) {
|
|
maskInHandler = CurrentMask();
|
|
Require(raise_nid_postfix(signal) == 0);
|
|
callsAfterNestedRaise = calls;
|
|
}
|
|
}
|
|
|
|
static void APS5_VABI Count(int) {
|
|
++calls;
|
|
}
|
|
|
|
static std::uint64_t handlerExit[12];
|
|
|
|
static void APS5_VABI LeaveWithLongjmp(int) {
|
|
++calls;
|
|
longjmp_nid_postfix(handlerExit, 1);
|
|
}
|
|
|
|
static void APS5_VABI BlockFromOtherThread(int) {
|
|
++calls;
|
|
std::thread([] {
|
|
const GuestSignalSet set{{Bit(SigTerm), 0, 0, 0}};
|
|
Require(sigprocmask_nid_postfix(SigBlock, &set, nullptr) == 0);
|
|
}).join();
|
|
}
|
|
|
|
static GuestSignalSet setInHandler{};
|
|
|
|
static void APS5_VABI RecordMask(int) {
|
|
++calls;
|
|
Require(sigprocmask_nid_postfix(SigBlock, nullptr, &setInHandler) == 0);
|
|
}
|
|
|
|
static void APS5_VABI UnblockAndRaise(int signal) {
|
|
if (++calls == 1) {
|
|
const GuestSignalSet own{{Bit(signal), 0, 0, 0}};
|
|
Require(sigprocmask_nid_postfix(SigUnblock, &own, nullptr) == 0);
|
|
Require(raise_nid_postfix(signal) == 0);
|
|
callsAfterNestedRaise = calls;
|
|
}
|
|
}
|
|
|
|
static void Install(int signal, void (APS5_VABI* handler)(int), int flags, std::uint32_t mask) {
|
|
GuestSigaction action{reinterpret_cast<std::uintptr_t>(handler), flags, {{mask, 0, 0, 0}}};
|
|
Require(sigaction_nid_postfix(signal, &action, nullptr) == 0);
|
|
}
|
|
|
|
static void CheckDeferred(int signal) {
|
|
calls = 0;
|
|
callsAfterNestedRaise = 0;
|
|
Install(signal, RaiseAgain, SaRestart, Bit(SigUsr1));
|
|
Require(raise_nid_postfix(signal) == 0);
|
|
Require(callsAfterNestedRaise == 1);
|
|
Require(calls == 2);
|
|
Require(maskInHandler == (Bit(signal) | Bit(SigUsr1)));
|
|
Require(CurrentMask() == 0);
|
|
}
|
|
|
|
static void CheckNodefer() {
|
|
calls = 0;
|
|
callsAfterNestedRaise = 0;
|
|
Install(SigUsr2, RaiseAgain, SaRestart | SaNodefer, 0);
|
|
Require(raise_nid_postfix(SigUsr2) == 0);
|
|
Require(callsAfterNestedRaise == 2);
|
|
Require(maskInHandler == 0);
|
|
Require(CurrentMask() == 0);
|
|
}
|
|
|
|
static void CheckResethand() {
|
|
calls = 0;
|
|
Install(SigUsr1, Count, SaResethand, 0);
|
|
Require(raise_nid_postfix(SigUsr1) == 0);
|
|
Require(calls == 1);
|
|
GuestSigaction current{};
|
|
Require(sigaction_nid_postfix(SigUsr1, nullptr, ¤t) == 0);
|
|
Require(current.handler == 0);
|
|
Require((current.flags & SaResethand) != 0);
|
|
}
|
|
|
|
static void CheckOtherThreadKept() {
|
|
calls = 0;
|
|
Install(SigUsr1, BlockFromOtherThread, SaRestart, 0);
|
|
Require(raise_nid_postfix(SigUsr1) == 0);
|
|
Require(calls == 1);
|
|
Require(CurrentMask() == Bit(SigTerm));
|
|
const GuestSignalSet set{{Bit(SigTerm), 0, 0, 0}};
|
|
Require(sigprocmask_nid_postfix(SigUnblock, &set, nullptr) == 0);
|
|
Require(CurrentMask() == 0);
|
|
}
|
|
|
|
static void CheckOtherThreadKeptSameSignal() {
|
|
calls = 0;
|
|
Install(SigUsr1, BlockFromOtherThread, SaRestart, Bit(SigTerm));
|
|
Require(raise_nid_postfix(SigUsr1) == 0);
|
|
Require(calls == 1);
|
|
Require(CurrentMask() == Bit(SigTerm));
|
|
const GuestSignalSet set{{Bit(SigTerm), 0, 0, 0}};
|
|
Require(sigprocmask_nid_postfix(SigUnblock, &set, nullptr) == 0);
|
|
Require(CurrentMask() == 0);
|
|
}
|
|
|
|
static void CheckUnblockInsideHandler() {
|
|
calls = 0;
|
|
callsAfterNestedRaise = 0;
|
|
Install(SigUsr2, UnblockAndRaise, SaRestart, 0);
|
|
Require(raise_nid_postfix(SigUsr2) == 0);
|
|
Require(callsAfterNestedRaise == 2);
|
|
Require(CurrentMask() == 0);
|
|
}
|
|
|
|
static void CheckUpperMaskWords() {
|
|
calls = 0;
|
|
const GuestSigaction action{reinterpret_cast<std::uintptr_t>(RecordMask), SaRestart, {{Bit(SigKill), 1u << 7, 0, 1u << 31}}};
|
|
Require(sigaction_nid_postfix(SigUsr1, &action, nullptr) == 0);
|
|
Require(raise_nid_postfix(SigUsr1) == 0);
|
|
Require(calls == 1);
|
|
Require(setInHandler.bits[0] == Bit(SigUsr1) && setInHandler.bits[1] == 1u << 7 && setInHandler.bits[2] == 0 && setInHandler.bits[3] == 1u << 31);
|
|
GuestSignalSet after{};
|
|
Require(sigprocmask_nid_postfix(SigBlock, nullptr, &after) == 0);
|
|
Require(after.bits[0] == 0 && after.bits[1] == 0 && after.bits[2] == 0 && after.bits[3] == 0);
|
|
}
|
|
|
|
static void CheckLeftWithLongjmp() {
|
|
calls = 0;
|
|
Install(SigUsr1, LeaveWithLongjmp, SaRestart, Bit(SigUsr2));
|
|
for (int round = 1; round <= 2; ++round) {
|
|
if (setjmp_nid_postfix(handlerExit) == 0) {
|
|
raise_nid_postfix(SigUsr1);
|
|
std::abort();
|
|
}
|
|
Require(calls == round);
|
|
Require(CurrentMask() == 0);
|
|
}
|
|
}
|
|
|
|
int main() {
|
|
CheckDeferred(SigUsr2);
|
|
CheckDeferred(SigTerm);
|
|
CheckNodefer();
|
|
CheckResethand();
|
|
CheckOtherThreadKept();
|
|
CheckOtherThreadKeptSameSignal();
|
|
CheckUnblockInsideHandler();
|
|
CheckUpperMaskWords();
|
|
CheckLeftWithLongjmp();
|
|
return 0;
|
|
}
|