Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions core/libs/prx/libkernel/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ add_library(libkernel SHARED EXCLUDE_FROM_ALL
${CMAKE_CURRENT_SOURCE_DIR}/System/src/Process.cpp
${CMAKE_CURRENT_SOURCE_DIR}/System/src/SystemConfiguration.cpp
${CMAKE_CURRENT_SOURCE_DIR}/System/src/Signals.cpp
${CMAKE_CURRENT_SOURCE_DIR}/System/src/SignalSets.cpp
${CMAKE_CURRENT_SOURCE_DIR}/System/src/Notification.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Time/Time.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Time/TimedWait.cpp
Expand Down Expand Up @@ -289,6 +290,16 @@ if(BUILD_TESTING)
set_tests_properties(guest_signals PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel>")
endif()
add_test_executable(guest_signal_set_tests ${LIBS_INCLUDE_DIR}/tests/GuestSignalSets.cpp)
target_include_directories(guest_signal_set_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_signal_set_tests PRIVATE libkernel libc)
configure_windows_unwind(guest_signal_set_tests)
add_test(NAME guest_signal_sets COMMAND guest_signal_set_tests)
set_tests_properties(guest_signal_sets PROPERTIES TIMEOUT 20)
if(WIN32)
set_tests_properties(guest_signal_sets PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel>")
endif()
add_test_executable(guest_exception_handler_tests ${LIBS_INCLUDE_DIR}/tests/GuestExceptionHandler.cpp)
target_include_directories(guest_exception_handler_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_exception_handler_tests PRIVATE libkernel libc)
Expand Down
62 changes: 62 additions & 0 deletions core/libs/prx/libkernel/System/src/SignalSets.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#include "prx/libc/include/general/VabiMacros.hpp"
#include <cstddef>
#include <cstdint>
#include <stdexcept>
#include <string>

extern "C" int* APS5_VABI __error_nid_postfix();

struct GuestSignalSet {
std::uint32_t bits[4];
};
static_assert(sizeof(GuestSignalSet) == 16);

namespace {
constexpr int MaximumSignal = 128;
constexpr int InvalidArgument = 22;

bool ValidSignal(int signal) { return signal > 0 && signal <= MaximumSignal; }
std::size_t WordIndex(int signal) { return static_cast<std::size_t>(signal - 1) >> 5; }
std::uint32_t Bit(int signal) { return 1u << ((signal - 1) & 31); }
int RejectSignal() {
*__error_nid_postfix() = InvalidArgument;
return -1;
}
void RequireSet(const GuestSignalSet* set, const char* function) {
if (set == nullptr) throw std::invalid_argument(std::string(function) + ": set is null");
}
}

extern "C" {
int APS5_VABI sigemptyset_nid_postfix(GuestSignalSet* set) {
RequireSet(set, "sigemptyset");
for (auto& word : set->bits) word = 0;
return 0;
}

int APS5_VABI sigfillset_nid_postfix(GuestSignalSet* set) {
RequireSet(set, "sigfillset");
for (auto& word : set->bits) word = ~0u;
return 0;
}

int APS5_VABI sigaddset_nid_postfix(GuestSignalSet* set, int signal) {
RequireSet(set, "sigaddset");
if (!ValidSignal(signal)) return RejectSignal();
set->bits[WordIndex(signal)] |= Bit(signal);
return 0;
}

int APS5_VABI sigdelset_nid_postfix(GuestSignalSet* set, int signal) {
RequireSet(set, "sigdelset");
if (!ValidSignal(signal)) return RejectSignal();
set->bits[WordIndex(signal)] &= ~Bit(signal);
return 0;
}

int APS5_VABI sigismember_nid_postfix(const GuestSignalSet* set, int signal) {
RequireSet(set, "sigismember");
if (!ValidSignal(signal)) return RejectSignal();
return (set->bits[WordIndex(signal)] & Bit(signal)) != 0 ? 1 : 0;
}
}
104 changes: 104 additions & 0 deletions core/libs/tests/GuestSignalSets.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#include "prx/libc/include/general/VabiMacros.hpp"
#include <climits>
#include <cstdint>
#include <cstdlib>
#include <initializer_list>

struct GuestSignalSet {
std::uint32_t bits[4];
};

extern "C" {
int APS5_VABI sigemptyset_nid_postfix(GuestSignalSet*);
int APS5_VABI sigfillset_nid_postfix(GuestSignalSet*);
int APS5_VABI sigaddset_nid_postfix(GuestSignalSet*, int);
int APS5_VABI sigdelset_nid_postfix(GuestSignalSet*, int);
int APS5_VABI sigismember_nid_postfix(const GuestSignalSet*, int);
int* APS5_VABI __error_nid_postfix();
}

static void Require(bool value) { if (!value) std::abort(); }

static bool Equals(const GuestSignalSet& set, std::uint32_t w0, std::uint32_t w1, std::uint32_t w2, std::uint32_t w3) {
return set.bits[0] == w0 && set.bits[1] == w1 && set.bits[2] == w2 && set.bits[3] == w3;
}

int main() {
static constexpr int Untouched = 5;
GuestSignalSet set{{0x12345678u, 0x9abcdef0u, 0xffffffffu, 1u}};
*__error_nid_postfix() = Untouched;
Require(sigemptyset_nid_postfix(&set) == 0);
Require(Equals(set, 0, 0, 0, 0));
Require(*__error_nid_postfix() == Untouched);

Require(sigfillset_nid_postfix(&set) == 0);
Require(Equals(set, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu));
for (int signal = 1; signal <= 128; ++signal) Require(sigismember_nid_postfix(&set, signal) == 1);
Require(*__error_nid_postfix() == Untouched);

Require(sigemptyset_nid_postfix(&set) == 0);
Require(sigaddset_nid_postfix(&set, 1) == 0);
Require(Equals(set, 1u, 0, 0, 0));
Require(sigaddset_nid_postfix(&set, 32) == 0);
Require(Equals(set, 0x80000001u, 0, 0, 0));
Require(sigaddset_nid_postfix(&set, 33) == 0);
Require(Equals(set, 0x80000001u, 1u, 0, 0));
Require(sigaddset_nid_postfix(&set, 65) == 0);
Require(Equals(set, 0x80000001u, 1u, 1u, 0));
Require(sigaddset_nid_postfix(&set, 96) == 0);
Require(Equals(set, 0x80000001u, 1u, 0x80000001u, 0));
Require(sigaddset_nid_postfix(&set, 128) == 0);
Require(Equals(set, 0x80000001u, 1u, 0x80000001u, 0x80000000u));
Require(sigaddset_nid_postfix(&set, 33) == 0);
Require(Equals(set, 0x80000001u, 1u, 0x80000001u, 0x80000000u));
Require(*__error_nid_postfix() == Untouched);

Require(sigismember_nid_postfix(&set, 1) == 1);
Require(sigismember_nid_postfix(&set, 2) == 0);
Require(sigismember_nid_postfix(&set, 32) == 1);
Require(sigismember_nid_postfix(&set, 33) == 1);
Require(sigismember_nid_postfix(&set, 64) == 0);
Require(sigismember_nid_postfix(&set, 65) == 1);
Require(sigismember_nid_postfix(&set, 96) == 1);
Require(sigismember_nid_postfix(&set, 97) == 0);
Require(sigismember_nid_postfix(&set, 128) == 1);
Require(*__error_nid_postfix() == Untouched);

Require(sigdelset_nid_postfix(&set, 1) == 0);
Require(Equals(set, 0x80000000u, 1u, 0x80000001u, 0x80000000u));
Require(sigdelset_nid_postfix(&set, 32) == 0);
Require(Equals(set, 0, 1u, 0x80000001u, 0x80000000u));
Require(sigdelset_nid_postfix(&set, 33) == 0);
Require(Equals(set, 0, 0, 0x80000001u, 0x80000000u));
Require(sigdelset_nid_postfix(&set, 96) == 0);
Require(Equals(set, 0, 0, 1u, 0x80000000u));
Require(sigdelset_nid_postfix(&set, 128) == 0);
Require(Equals(set, 0, 0, 1u, 0));
Require(sigdelset_nid_postfix(&set, 2) == 0);
Require(Equals(set, 0, 0, 1u, 0));
Require(sigismember_nid_postfix(&set, 128) == 0);
Require(*__error_nid_postfix() == Untouched);

for (const int invalid : {0, -1, 129, 1000, INT_MIN, INT_MAX}) {
*__error_nid_postfix() = 0;
Require(sigaddset_nid_postfix(&set, invalid) == -1 && *__error_nid_postfix() == 22);
*__error_nid_postfix() = 0;
Require(sigdelset_nid_postfix(&set, invalid) == -1 && *__error_nid_postfix() == 22);
*__error_nid_postfix() = 0;
Require(sigismember_nid_postfix(&set, invalid) == -1 && *__error_nid_postfix() == 22);
Require(Equals(set, 0, 0, 1u, 0));
}

Require(sigfillset_nid_postfix(&set) == 0);
for (const int invalid : {0, -1, 129, 1000, INT_MIN, INT_MAX}) {
Require(sigaddset_nid_postfix(&set, invalid) == -1 && *__error_nid_postfix() == 22);
Require(sigdelset_nid_postfix(&set, invalid) == -1 && *__error_nid_postfix() == 22);
Require(sigismember_nid_postfix(&set, invalid) == -1 && *__error_nid_postfix() == 22);
Require(Equals(set, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu));
}

const GuestSignalSet empty{{0, 0, 0, 0}};
Require(sigismember_nid_postfix(&empty, 1) == 0);
Require(sigismember_nid_postfix(&empty, 128) == 0);
return 0;
}
Loading