#include "prx/libkernel/KernelErrors.hpp" #include "prx/libkernel_sys/include/Api.hpp" #include "prx/libkernel/include/Api.hpp" #include "SceTypes.hpp" #include #include #include #include #include static constexpr int PROCESS_PRIVATE = 0; static constexpr int PROCESS_SHARED = 1; static constexpr int BARRIER_SERIAL_THREAD = -1; static constexpr int MS_ASYNC = 0x1; static constexpr int MS_INVALIDATE = 0x2; static constexpr unsigned WAITERS = 4; static void Require(bool value) { if (!value) std::abort(); } struct Context { PthreadBarrierPrivate* barrier = nullptr; std::atomic serial{0}; std::atomic released{0}; }; static void* APS5_VABI Waiter(void* arg) { auto& context = *static_cast(arg); const int result = scePthreadBarrierWait(&context.barrier); if (result == BARRIER_SERIAL_THREAD) ++context.serial; else if (result == 0) ++context.released; else std::abort(); return nullptr; } int main() { PthreadBarrierattrPrivate* attr = nullptr; Require(scePthreadBarrierattrInit(nullptr) == SCE_KERNEL_ERROR_EINVAL); Require(scePthreadBarrierattrInit(&attr) == 0 && attr != nullptr); int pshared = -1; Require(scePthreadBarrierattrGetpshared(&attr, &pshared) == 0 && pshared == PROCESS_PRIVATE); Require(scePthreadBarrierattrSetpshared(&attr, PROCESS_SHARED) == SCE_KERNEL_ERROR_EINVAL); Require(scePthreadBarrierattrSetpshared(&attr, PROCESS_PRIVATE) == 0); Context context; Require(scePthreadBarrierInit(&context.barrier, &attr, 0, "zero") == SCE_KERNEL_ERROR_EINVAL); Require(scePthreadBarrierInit(&context.barrier, &attr, 0x80000000u, "over") == SCE_KERNEL_ERROR_EINVAL && context.barrier == nullptr); Require(scePthreadBarrierInit(nullptr, &attr, WAITERS, "null") == SCE_KERNEL_ERROR_EINVAL); Require(scePthreadBarrierInit(&context.barrier, &attr, WAITERS, "barrier") == 0 && context.barrier != nullptr); Require(scePthreadBarrierattrDestroy(&attr) == 0 && attr == nullptr); Require(scePthreadBarrierattrDestroy(&attr) == SCE_KERNEL_ERROR_EINVAL); for (int round = 0; round < 2; ++round) { context.serial = 0; context.released = 0; std::array threads{}; for (auto& thread : threads) Require(scePthreadCreate(&thread, nullptr, Waiter, &context, nullptr) == 0); for (auto& thread : threads) Require(scePthreadJoin(thread, nullptr) == 0); Require(context.serial == 1 && context.released == static_cast(WAITERS) - 1); } Require(scePthreadBarrierDestroy(&context.barrier) == 0 && context.barrier == nullptr); Require(scePthreadBarrierDestroy(&context.barrier) == SCE_KERNEL_ERROR_EINVAL); Require(scePthreadBarrierWait(nullptr) == SCE_KERNEL_ERROR_EINVAL); PthreadBarrierPrivate* single = nullptr; Require(scePthreadBarrierInit(&single, nullptr, 1, nullptr) == 0); Require(scePthreadBarrierWait(&single) == BARRIER_SERIAL_THREAD); Require(scePthreadBarrierDestroy(&single) == 0); int clock = 0; int posixClock = 0; Require(scePthreadGetcpuclockid(scePthreadSelf(), &clock) == 0); Require(pthread_getcpuclockid_nid_postfix(scePthreadSelf(), &posixClock) == 0 && clock == posixClock); Require(scePthreadGetcpuclockid(scePthreadSelf(), nullptr) == SCE_KERNEL_ERROR_EFAULT); Require(scePthreadGetcpuclockid(nullptr, &clock) == SCE_KERNEL_ERROR_EINVAL); Require(pthread_setconcurrency_nid_postfix(3) == 0 && scePthreadGetconcurrency() == 3); Require(pthread_setconcurrency_nid_postfix(0) == 0 && scePthreadGetconcurrency() == 0); auto* unmapped = reinterpret_cast(static_cast(0x4000)); Require(sceKernelMsync(unmapped, 0x4000, 0) == SCE_KERNEL_ERROR_ENOMEM); Require(sceKernelMsync(unmapped, 0x4000, MS_ASYNC | MS_INVALIDATE) == SCE_KERNEL_ERROR_EINVAL); return 0; }