#include "prx/libkernel/KernelErrors.hpp" #include "prx/libkernel/include/Api.hpp" #include "prx/libkernel/Semaphore/include/Semaphore.hpp" #include "SceTypes.hpp" #include #include #include static constexpr int SCE_OK = 0; static void Require(bool value) { if (!value) std::abort(); } struct Waiter { KernelSema sem = nullptr; bool timed = false; int result = SCE_OK; }; static void* APS5_VABI Wait(void* arg) { auto& waiter = *static_cast(arg); KernelUseconds timeout = 5000000; waiter.result = sceKernelWaitSema(waiter.sem, 1, waiter.timed ? &timeout : nullptr); return nullptr; } static void RequireInvalidArguments() { KernelSema rejected = nullptr; Require(sceKernelCreateSema(&rejected, "rejected", 0, 5, 3, nullptr) == SCE_KERNEL_ERROR_EINVAL); Require(sceKernelCreateSema(&rejected, "rejected", 0, 0, 0, nullptr) == SCE_KERNEL_ERROR_EINVAL); Require(sceKernelCreateSema(&rejected, "rejected", 0, -1, 3, nullptr) == SCE_KERNEL_ERROR_EINVAL); Require(sceKernelCreateSema(&rejected, nullptr, 0, 0, 1, nullptr) == SCE_KERNEL_ERROR_EINVAL); Require(rejected == nullptr); KernelSema sem = nullptr; Require(sceKernelCreateSema(&sem, "limits", 0, 2, 3, nullptr) == SCE_OK); Require(sceKernelPollSema(sem, 0) == SCE_KERNEL_ERROR_EINVAL); Require(sceKernelPollSema(sem, -1) == SCE_KERNEL_ERROR_EINVAL); Require(sceKernelPollSema(sem, 4) == SCE_KERNEL_ERROR_EINVAL); Require(sceKernelPollSema(sem, 100) == SCE_KERNEL_ERROR_EINVAL); Require(sceKernelPollSema(sem, 3) == SCE_KERNEL_ERROR_EBUSY); Require(sceKernelSignalSema(sem, 0) == SCE_KERNEL_ERROR_EINVAL); Require(sceKernelPollSema(sem, 2) == SCE_OK); Require(sceKernelSignalSema(sem, 3) == SCE_OK); Require(sceKernelPollSema(sem, 3) == SCE_OK); Require(sceKernelDeleteSema(sem) == SCE_OK); } int main() { KernelUseconds nullTimeout = 1000; int nullWaiters = -1; Require(sceKernelWaitSema(nullptr, 1, nullptr) == SCE_KERNEL_ERROR_ESRCH); Require(sceKernelWaitSema(nullptr, 1, &nullTimeout) == SCE_KERNEL_ERROR_ESRCH && nullTimeout == 1000); Require(sceKernelPollSema(nullptr, 1) == SCE_KERNEL_ERROR_ESRCH); Require(sceKernelSignalSema(nullptr, 1) == SCE_KERNEL_ERROR_ESRCH); Require(sceKernelCancelSema(nullptr, 0, &nullWaiters) == SCE_KERNEL_ERROR_ESRCH && nullWaiters == -1); Require(sceKernelDeleteSema(nullptr) == SCE_KERNEL_ERROR_ESRCH); KernelSema sem = nullptr; Require(sceKernelCreateSema(&sem, "cancel", 0, 1, 3, nullptr) == SCE_OK); int waiters = -1; Require(sceKernelCancelSema(sem, 4, &waiters) == SCE_KERNEL_ERROR_EINVAL); Require(waiters == -1); Require(sceKernelPollSema(sem, 1) == SCE_OK); Require(sceKernelPollSema(sem, 1) == SCE_KERNEL_ERROR_EBUSY); Require(sceKernelCancelSema(sem, 2, &waiters) == SCE_OK && waiters == 0); Require(sceKernelPollSema(sem, 2) == SCE_OK); Require(sceKernelPollSema(sem, 1) == SCE_KERNEL_ERROR_EBUSY); Require(sceKernelCancelSema(sem, -1, nullptr) == SCE_OK); Require(sceKernelPollSema(sem, 1) == SCE_OK); Require(sceKernelPollSema(sem, 1) == SCE_KERNEL_ERROR_EBUSY); Waiter blocked{sem, false}; Waiter timed{sem, true}; Pthread blockedThread = nullptr; Pthread timedThread = nullptr; Require(scePthreadCreate(&blockedThread, nullptr, Wait, &blocked, nullptr) == SCE_OK); Require(scePthreadCreate(&timedThread, nullptr, Wait, &timed, nullptr) == SCE_OK); int canceled = 0; const auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(4); while (canceled < 2 && std::chrono::steady_clock::now() < deadline) { waiters = -1; Require(sceKernelCancelSema(sem, 0, &waiters) == SCE_OK); Require(waiters >= 0); canceled += waiters; } Require(scePthreadJoin(blockedThread, nullptr) == SCE_OK); Require(scePthreadJoin(timedThread, nullptr) == SCE_OK); Require(canceled == 2); Require(blocked.result == SCE_KERNEL_ERROR_ECANCELED); Require(timed.result == SCE_KERNEL_ERROR_ECANCELED); Require(sceKernelCancelSema(sem, 0, &waiters) == SCE_OK && waiters == 0); Require(sceKernelPollSema(sem, 1) == SCE_KERNEL_ERROR_EBUSY); KernelUseconds remaining = 1000; Require(sceKernelWaitSema(sem, 1, &remaining) == SCE_KERNEL_ERROR_ETIMEDOUT && remaining == 0); Require(sceKernelSignalSema(sem, 1) == SCE_OK); remaining = 5000000; Require(sceKernelWaitSema(sem, 1, &remaining) == SCE_OK && remaining > 0 && remaining <= 5000000); Require(sceKernelSignalSema(sem, 1) == SCE_OK); Require(sceKernelWaitSema(sem, 1, nullptr) == SCE_OK); Require(sceKernelDeleteSema(sem) == SCE_OK); RequireInvalidArguments(); }