#include "prx/libkernel/KernelErrors.hpp" #include "prx/libkernel/include/Api.hpp" #include "prx/libkernel/Semaphore/include/Semaphore.hpp" #include "prx/libkernel/Pthread/include/Mutex.hpp" #include "prx/libkernel/Pthread/include/Rwlock.hpp" #include "prx/libSceSaveData/SaveDataCore.hpp" #include "SceTypes.hpp" #include #include #include #include #include #include #include extern "C" { int APS5_Test_GetEventFlagWaiterCount(KernelEventFlag handle); } static constexpr int SCE_OK = 0; static constexpr std::uint32_t EVF_ATTR_SINGLE = 0x10; static constexpr std::uint32_t EVF_ATTR_MULTI = 0x20; static constexpr std::uint32_t EVF_ATTR_SHARED = 0x100; static constexpr std::uint32_t EVF_WAITMODE_AND = 0x01; static constexpr std::uint32_t EVF_WAITMODE_OR = 0x02; static constexpr std::uint32_t EVF_WAITMODE_CLEAR_ALL = 0x10; static constexpr std::uint32_t EVF_WAITMODE_CLEAR_PAT = 0x20; static constexpr int MUTEX_TYPE_ERRORCHECK = 1; static constexpr int MUTEX_TYPE_NORMAL = 3; static constexpr int PRIO_NONE = 0; static constexpr int PRIO_INHERIT = 1; static constexpr int PRIO_PROTECT = 2; static constexpr int MUTEX_TYPE_ADAPTIVE = 4; static constexpr int POSIX_EDEADLK = 11; static void Require(bool value) { if (!value) std::abort(); } static void WaitForEventFlagWaiters(KernelEventFlag handle, int expected) { const auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(5); while (APS5_Test_GetEventFlagWaiterCount(handle) != expected) { if (std::chrono::steady_clock::now() >= deadline) Require(false); std::this_thread::yield(); } } template static void RequireTimesOut(TLock lock) { const auto start = std::chrono::steady_clock::now(); Require(lock(20000) == SCE_KERNEL_ERROR_ETIMEDOUT); Require(std::chrono::steady_clock::now() - start >= std::chrono::milliseconds(15)); } int main() { constexpr int maximum = std::numeric_limits::max(); KernelSema semaphore = nullptr; Require(sceKernelCreateSema(&semaphore, "overflow", 1, maximum - 1, maximum, nullptr) == SCE_OK); Require(sceKernelSignalSema(semaphore, 2) == SCE_KERNEL_ERROR_EINVAL); Require(sceKernelSignalSema(semaphore, maximum) == SCE_KERNEL_ERROR_EINVAL); Require(sceKernelPollSema(semaphore, maximum - 1) == SCE_OK); Require(sceKernelSignalSema(semaphore, maximum) == SCE_OK); Require(sceKernelSignalSema(semaphore, 1) == SCE_KERNEL_ERROR_EINVAL); Require(sceKernelPollSema(semaphore, maximum) == SCE_OK); Require(sceKernelDeleteSema(semaphore) == SCE_OK); Require(sceKernelCreateSema(&semaphore, "limit", 1, 1, 3, nullptr) == SCE_OK); Require(sceKernelSignalSema(semaphore, 3) == SCE_KERNEL_ERROR_EINVAL); Require(sceKernelSignalSema(semaphore, 2) == SCE_OK); Require(sceKernelSignalSema(semaphore, 0) == SCE_KERNEL_ERROR_EINVAL); Require(sceKernelPollSema(semaphore, 3) == SCE_OK); Require(sceKernelSignalSema(semaphore, 0) == SCE_KERNEL_ERROR_EINVAL); Require(sceKernelPollSema(semaphore, 1) == SCE_KERNEL_ERROR_EBUSY); Require(sceKernelDeleteSema(semaphore) == SCE_OK); KernelEqueue eq = 0; Require(sceKernelCreateEqueue(&eq, "errors") == SCE_OK); KernelEvent event{}; int count = -1; const KernelUseconds timeout = 1000; Require(sceKernelWaitEqueue(eq, &event, 1, &count, &timeout) == SCE_KERNEL_ERROR_ETIMEDOUT); Require(count == 0); Require(sceKernelWaitEqueue(eq, nullptr, 1, &count, &timeout) == SCE_KERNEL_ERROR_EFAULT); Require(sceKernelWaitEqueue(eq, &event, 0, &count, &timeout) == SCE_KERNEL_ERROR_EINVAL); Require(sceKernelDeleteUserEvent(eq, 7) == SCE_KERNEL_ERROR_ENOENT); Require(sceKernelDeleteEqueue(eq) == SCE_OK); Require(sceKernelDeleteEqueue(eq) == SCE_KERNEL_ERROR_EBADF); Require(sceKernelWaitEqueue(eq, &event, 1, &count, &timeout) == SCE_KERNEL_ERROR_EBADF); Require(sceKernelCreateEqueue(nullptr, "errors") == SCE_KERNEL_ERROR_EINVAL); PthreadMutexattr attr = nullptr; Require(scePthreadMutexattrInit(&attr) == SCE_OK); Require(scePthreadMutexattrSettype(&attr, MUTEX_TYPE_ERRORCHECK) == SCE_OK); Require(scePthreadMutexattrSettype(&attr, 0) == SCE_KERNEL_ERROR_EINVAL); Require(scePthreadMutexattrSettype(&attr, 5) == SCE_KERNEL_ERROR_EINVAL); Require(scePthreadMutexattrSetprotocol(&attr, PRIO_NONE) == SCE_OK); Require(scePthreadMutexattrSetprotocol(&attr, PRIO_INHERIT) == SCE_OK); Require(scePthreadMutexattrSetprotocol(&attr, PRIO_PROTECT) == SCE_OK); PthreadMutex mutex = nullptr; Require(scePthreadMutexInit(&mutex, &attr, nullptr) == SCE_OK); Require(scePthreadMutexattrDestroy(&attr) == SCE_OK); Require(scePthreadMutexLock(&mutex) == SCE_OK); Require(scePthreadMutexLock(&mutex) == SCE_KERNEL_ERROR_EDEADLK); RequireTimesOut([&](KernelUseconds usec) { return scePthreadMutexTimedlock(&mutex, usec); }); Require(scePthreadMutexDestroy(&mutex) == SCE_KERNEL_ERROR_EBUSY); Require(scePthreadMutexUnlock(&mutex) == SCE_OK); Require(scePthreadMutexDestroy(&mutex) == SCE_OK); Require(scePthreadMutexattrInit(&attr) == SCE_OK); Require(scePthreadMutexattrSettype(&attr, MUTEX_TYPE_ADAPTIVE) == SCE_OK); PthreadMutex adaptive = nullptr; Require(scePthreadMutexInit(&adaptive, &attr, nullptr) == SCE_OK); Require(scePthreadMutexattrDestroy(&attr) == SCE_OK); Require(scePthreadMutexLock(&adaptive) == SCE_OK); Require(scePthreadMutexLock(&adaptive) == SCE_KERNEL_ERROR_EDEADLK); RequireTimesOut([&](KernelUseconds usec) { return scePthreadMutexTimedlock(&adaptive, usec); }); Require(scePthreadMutexUnlock(&adaptive) == SCE_OK); Require(scePthreadMutexDestroy(&adaptive) == SCE_OK); PthreadMutex timedDefault = nullptr; Require(scePthreadMutexInit(&timedDefault, nullptr, nullptr) == SCE_OK); Require(scePthreadMutexLock(&timedDefault) == SCE_OK); RequireTimesOut([&](KernelUseconds usec) { return scePthreadMutexTimedlock(&timedDefault, usec); }); Require(scePthreadMutexUnlock(&timedDefault) == SCE_OK); Require(scePthreadMutexTimedlock(&timedDefault, 20000) == SCE_OK); Require(scePthreadMutexUnlock(&timedDefault) == SCE_OK); Require(scePthreadMutexDestroy(&timedDefault) == SCE_OK); Require(scePthreadMutexattrInit(&attr) == SCE_OK); Require(scePthreadMutexattrSettype(&attr, MUTEX_TYPE_NORMAL) == SCE_OK); PthreadMutex normal = nullptr; Require(scePthreadMutexInit(&normal, &attr, nullptr) == SCE_OK); Require(scePthreadMutexattrDestroy(&attr) == SCE_OK); Require(scePthreadMutexLock(&normal) == SCE_OK); RequireTimesOut([&](KernelUseconds usec) { return scePthreadMutexTimedlock(&normal, usec); }); Require(scePthreadMutexUnlock(&normal) == SCE_OK); Require(scePthreadMutexDestroy(&normal) == SCE_OK); PthreadRwlock rwlock = nullptr; Require(scePthreadRwlockInit(&rwlock, nullptr, nullptr) == SCE_OK); Require(scePthreadRwlockWrlock(&rwlock) == SCE_OK); Require(scePthreadRwlockTrywrlock(&rwlock) == SCE_KERNEL_ERROR_EBUSY); Require(scePthreadRwlockWrlock(&rwlock) == SCE_KERNEL_ERROR_EDEADLK); RequireTimesOut([&](KernelUseconds usec) { return scePthreadRwlockTimedrdlock(&rwlock, usec); }); RequireTimesOut([&](KernelUseconds usec) { return scePthreadRwlockTimedwrlock(&rwlock, usec); }); Require(scePthreadRwlockUnlock(&rwlock) == SCE_OK); Require(scePthreadRwlockTimedwrlock(&rwlock, 20000) == SCE_OK); Require(scePthreadRwlockUnlock(&rwlock) == SCE_OK); Require(scePthreadRwlockDestroy(&rwlock) == SCE_OK); PthreadMutex adaptiveStatic = reinterpret_cast(std::uintptr_t{1}); Require(scePthreadMutexLock(&adaptiveStatic) == SCE_OK); Require(adaptiveStatic != reinterpret_cast(std::uintptr_t{1})); Require(scePthreadMutexLock(&adaptiveStatic) == SCE_KERNEL_ERROR_EDEADLK); Require(scePthreadMutexTrylock(&adaptiveStatic) == SCE_KERNEL_ERROR_EBUSY); Require(scePthreadMutexUnlock(&adaptiveStatic) == SCE_OK); Require(scePthreadMutexDestroy(&adaptiveStatic) == SCE_OK); adaptiveStatic = reinterpret_cast(std::uintptr_t{1}); Require(scePthreadMutexTrylock(&adaptiveStatic) == SCE_OK); Require(scePthreadMutexTrylock(&adaptiveStatic) == SCE_KERNEL_ERROR_EBUSY); Require(scePthreadMutexUnlock(&adaptiveStatic) == SCE_OK); Require(scePthreadMutexDestroy(&adaptiveStatic) == SCE_OK); adaptiveStatic = reinterpret_cast(std::uintptr_t{1}); Require(scePthreadMutexDestroy(&adaptiveStatic) == SCE_OK); Require(scePthreadMutexattrInit(&attr) == SCE_OK); PthreadMutex defaulted = nullptr; Require(scePthreadMutexInit(&defaulted, &attr, nullptr) == SCE_OK); Require(scePthreadMutexattrDestroy(&attr) == SCE_OK); Require(scePthreadMutexLock(&defaulted) == SCE_OK); Require(scePthreadMutexLock(&defaulted) == SCE_KERNEL_ERROR_EDEADLK); Require(scePthreadMutexUnlock(&defaulted) == SCE_OK); Require(scePthreadMutexDestroy(&defaulted) == SCE_OK); PthreadMutex unattributed = nullptr; Require(scePthreadMutexInit(&unattributed, nullptr, nullptr) == SCE_OK); Require(scePthreadMutexLock(&unattributed) == SCE_OK); Require(scePthreadMutexLock(&unattributed) == SCE_KERNEL_ERROR_EDEADLK); Require(scePthreadMutexUnlock(&unattributed) == SCE_OK); Require(scePthreadMutexDestroy(&unattributed) == SCE_OK); Require(pthread_mutexattr_init_nid_postfix(&attr) == 0); Require(pthread_mutexattr_settype_nid_postfix(&attr, MUTEX_TYPE_ADAPTIVE) == 0); PthreadMutex posixAdaptive = nullptr; Require(pthread_mutex_init_nid_postfix(&posixAdaptive, &attr) == 0); Require(pthread_mutexattr_destroy_nid_postfix(&attr) == 0); Require(pthread_mutex_lock_nid_postfix(&posixAdaptive) == 0); Require(pthread_mutex_lock_nid_postfix(&posixAdaptive) == POSIX_EDEADLK); Require(pthread_mutex_unlock_nid_postfix(&posixAdaptive) == 0); Require(pthread_mutex_destroy_nid_postfix(&posixAdaptive) == 0); auto staticAdaptive = reinterpret_cast(std::uintptr_t{1}); Require(pthread_mutex_lock_nid_postfix(&staticAdaptive) == 0); Require(pthread_mutex_lock_nid_postfix(&staticAdaptive) == POSIX_EDEADLK); Require(pthread_mutex_unlock_nid_postfix(&staticAdaptive) == 0); Require(pthread_mutex_destroy_nid_postfix(&staticAdaptive) == 0); KernelEventFlag ef = nullptr; Require(sceKernelCreateEventFlag(nullptr, "test", EVF_ATTR_MULTI, 0, nullptr) == SCE_KERNEL_ERROR_EINVAL); Require(sceKernelCreateEventFlag(&ef, nullptr, EVF_ATTR_MULTI, 0, nullptr) == SCE_KERNEL_ERROR_EINVAL); Require(sceKernelCreateEventFlag(&ef, "test_zero_attr", 0, 0, nullptr) == SCE_OK); Require(sceKernelDeleteEventFlag(ef) == SCE_OK); Require(sceKernelCreateEventFlag(&ef, "test_fifo", 0x01, 0, nullptr) == SCE_OK); Require(sceKernelDeleteEventFlag(ef) == SCE_OK); Require(sceKernelCreateEventFlag(&ef, "test_single_fifo", EVF_ATTR_SINGLE | 0x01u, 0, nullptr) == SCE_OK); Require(sceKernelDeleteEventFlag(ef) == SCE_OK); Require(sceKernelCreateEventFlag(&ef, "test", EVF_ATTR_SINGLE | EVF_ATTR_MULTI, 0, nullptr) == SCE_KERNEL_ERROR_EINVAL); Require(sceKernelCreateEventFlag(&ef, "test", EVF_ATTR_MULTI | 0x1000u, 0, nullptr) == SCE_KERNEL_ERROR_EINVAL); for (const std::uint32_t attr : {0x03u, 0x13u, 0x23u, 0x103u, 0x130u, 0x04u, 0x08u, 0x40u, 0x80u, 0x200u, 0x80000000u, 0xffffffffu}) { Require(sceKernelCreateEventFlag(&ef, "test_bad_attr", attr, 0, nullptr) == SCE_KERNEL_ERROR_EINVAL); } for (const std::uint32_t attr : {0x02u, 0x11u, 0x12u, 0x21u, 0x22u}) { Require(sceKernelCreateEventFlag(&ef, "test_attr", attr, 0, nullptr) == SCE_OK); Require(sceKernelDeleteEventFlag(ef) == SCE_OK); } Require(sceKernelDeleteEventFlag(nullptr) == SCE_KERNEL_ERROR_ESRCH); Require(sceKernelSetEventFlag(nullptr, 1) == SCE_KERNEL_ERROR_ESRCH); Require(sceKernelClearEventFlag(nullptr, 1) == SCE_KERNEL_ERROR_ESRCH); Require(sceKernelPollEventFlag(nullptr, 1, EVF_WAITMODE_OR, nullptr) == SCE_KERNEL_ERROR_ESRCH); Require(sceKernelWaitEventFlag(nullptr, 1, EVF_WAITMODE_OR, nullptr, nullptr) == SCE_KERNEL_ERROR_ESRCH); Require(sceKernelCancelEventFlag(nullptr, 0, nullptr) == SCE_KERNEL_ERROR_ESRCH); Require(sceKernelCreateEventFlag(&ef, "", EVF_ATTR_MULTI, 0, nullptr) == SCE_OK); Require(sceKernelDeleteEventFlag(ef) == SCE_OK); Require(sceKernelCreateEventFlag(&ef, "nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn", EVF_ATTR_SHARED | EVF_ATTR_MULTI, 0, nullptr) == SCE_OK); Require(sceKernelDeleteEventFlag(ef) == SCE_OK); for (const std::uint32_t attr : {EVF_ATTR_MULTI, EVF_ATTR_SHARED | EVF_ATTR_MULTI}) { Require(sceKernelCreateEventFlag(&ef, "nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn", attr, 0, nullptr) == SCE_KERNEL_ERROR_ENAMETOOLONG); } KernelEventFlag opened = nullptr; Require(sceKernelOpenEventFlag(nullptr, "test") == SCE_KERNEL_ERROR_ESRCH); Require(sceKernelOpenEventFlag(&opened, nullptr) == SCE_KERNEL_ERROR_EFAULT && opened == nullptr); Require(sceKernelOpenEventFlag(&opened, "") == SCE_KERNEL_ERROR_ESRCH && opened == nullptr); Require(sceKernelOpenEventFlag(&opened, "nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn") == SCE_KERNEL_ERROR_ENAMETOOLONG && opened == nullptr); Require(sceKernelOpenEventFlag(&opened, "SceShellCoreUtilAppFocus") == SCE_KERNEL_ERROR_ESRCH && opened == nullptr); Require(sceKernelCloseEventFlag(nullptr) == SCE_KERNEL_ERROR_ESRCH); KernelEventFlag plain = nullptr; Require(sceKernelCreateEventFlag(&plain, "test_open", EVF_ATTR_MULTI, 0x01, nullptr) == SCE_OK); Require(sceKernelOpenEventFlag(&opened, "test_open") == SCE_KERNEL_ERROR_ESRCH && opened == nullptr); Require(sceKernelCloseEventFlag(plain) == SCE_KERNEL_ERROR_EPERM); Require(sceKernelSetEventFlag(plain, 0x02) == SCE_OK); KernelEventFlag plainTwin = nullptr; Require(sceKernelCreateEventFlag(&plainTwin, "test_open", EVF_ATTR_MULTI, 0, nullptr) == SCE_OK); Require(sceKernelDeleteEventFlag(plainTwin) == SCE_OK); Require(sceKernelCreateEventFlag(&ef, "test_open", EVF_ATTR_SHARED | EVF_ATTR_MULTI, 0x05, nullptr) == SCE_OK); KernelEventFlag sharedTwin = nullptr; Require(sceKernelCreateEventFlag(&sharedTwin, "test_open", EVF_ATTR_SHARED | EVF_ATTR_MULTI, 0, nullptr) == SCE_KERNEL_ERROR_EPERM && sharedTwin == nullptr); Require(sceKernelOpenEventFlag(&opened, "test_open") == SCE_OK && opened != nullptr && opened != ef && opened != plain); Require(sceKernelOpenEventFlag(nullptr, "test_open") == SCE_KERNEL_ERROR_EFAULT); KernelEventFlag openedTwice = nullptr; Require(sceKernelOpenEventFlag(&openedTwice, "test_open") == SCE_OK && openedTwice != opened && openedTwice != ef); Require(sceKernelSetEventFlag(opened, 0x08) == SCE_OK); Require(sceKernelClearEventFlag(openedTwice, ~std::uint64_t{0x04}) == SCE_OK); std::uint64_t openedPattern = 0; Require(sceKernelPollEventFlag(ef, 0x08, EVF_WAITMODE_OR, &openedPattern) == SCE_OK && openedPattern == 0x09); Require(sceKernelDeleteEventFlag(opened) == SCE_KERNEL_ERROR_EPERM); Require(sceKernelCloseEventFlag(ef) == SCE_KERNEL_ERROR_EPERM); Require(sceKernelCloseEventFlag(openedTwice) == SCE_OK); Require(sceKernelCloseEventFlag(openedTwice) == SCE_KERNEL_ERROR_ESRCH); Require(sceKernelSetEventFlag(openedTwice, 0x01) == SCE_KERNEL_ERROR_ESRCH); std::atomic orphanWaitRes{-1}; std::uint64_t orphanWaitPat = 0xdeadbeef; std::thread orphanWaiter([&] { orphanWaitRes = sceKernelWaitEventFlag(opened, 0x80, EVF_WAITMODE_OR, &orphanWaitPat, nullptr); }); WaitForEventFlagWaiters(opened, 1); Require(sceKernelDeleteEventFlag(ef) == SCE_OK); orphanWaiter.join(); Require(orphanWaitRes == SCE_KERNEL_ERROR_EACCES && orphanWaitPat == 0); KernelEventFlag reopened = nullptr; Require(sceKernelOpenEventFlag(&reopened, "test_open") == SCE_KERNEL_ERROR_ESRCH && reopened == nullptr); std::uint64_t orphanPattern = 0xdeadbeef; Require(sceKernelPollEventFlag(opened, 0, EVF_WAITMODE_OR, &orphanPattern) == SCE_KERNEL_ERROR_EINVAL && orphanPattern == 0xdeadbeef); Require(sceKernelPollEventFlag(opened, 0x01, EVF_WAITMODE_OR, &orphanPattern) == SCE_KERNEL_ERROR_EACCES && orphanPattern == 0); orphanPattern = 0xdeadbeef; KernelUseconds orphanTimeout = 1000; Require(sceKernelWaitEventFlag(opened, 0x01, EVF_WAITMODE_OR, &orphanPattern, &orphanTimeout) == SCE_KERNEL_ERROR_EACCES && orphanPattern == 0 && orphanTimeout == 1000); Require(sceKernelSetEventFlag(opened, 0x02) == SCE_OK); Require(sceKernelClearEventFlag(opened, 0) == SCE_OK); int orphanCount = -1; Require(sceKernelCancelEventFlag(opened, 0x04, &orphanCount) == SCE_OK && orphanCount == 0); Require(sceKernelDeleteEventFlag(opened) == SCE_KERNEL_ERROR_EPERM); Require(sceKernelCreateEventFlag(&ef, "test_open", EVF_ATTR_SHARED | EVF_ATTR_SINGLE, 0x01, nullptr) == SCE_OK); Require(sceKernelOpenEventFlag(&reopened, "test_open") == SCE_OK && reopened != opened); Require(sceKernelCloseEventFlag(opened) == SCE_OK); Require(sceKernelCloseEventFlag(opened) == SCE_KERNEL_ERROR_ESRCH); std::atomic sharedSingleRes{-1}; std::uint64_t sharedSinglePat = 0; std::thread sharedSingleWaiter([&] { sharedSingleRes = sceKernelWaitEventFlag(ef, 0x80, EVF_WAITMODE_OR, &sharedSinglePat, nullptr); }); WaitForEventFlagWaiters(ef, 1); openedPattern = 0xdeadbeef; Require(sceKernelPollEventFlag(reopened, 0x01, EVF_WAITMODE_OR, &openedPattern) == SCE_KERNEL_ERROR_EPERM && openedPattern == 0); Require(sceKernelSetEventFlag(reopened, 0x80) == SCE_OK); sharedSingleWaiter.join(); Require(sharedSingleRes == SCE_OK && sharedSinglePat == 0x81); Require(sceKernelCloseEventFlag(reopened) == SCE_OK); Require(sceKernelDeleteEventFlag(ef) == SCE_OK); Require(sceKernelDeleteEventFlag(plain) == SCE_OK); Require(sceKernelCreateEventFlag(&ef, "flag", EVF_ATTR_MULTI, 0x15, nullptr) == SCE_OK); std::uint64_t pattern = 0; Require(sceKernelPollEventFlag(ef, 0, EVF_WAITMODE_OR, &pattern) == SCE_KERNEL_ERROR_EINVAL); Require(sceKernelPollEventFlag(ef, 1, 0, &pattern) == SCE_KERNEL_ERROR_EINVAL); Require(sceKernelPollEventFlag(ef, 1, EVF_WAITMODE_AND | EVF_WAITMODE_OR, &pattern) == SCE_KERNEL_ERROR_EINVAL); Require(sceKernelPollEventFlag(ef, 1, EVF_WAITMODE_AND | EVF_WAITMODE_CLEAR_ALL | EVF_WAITMODE_CLEAR_PAT, &pattern) == SCE_KERNEL_ERROR_EINVAL); for (const std::uint32_t mode : {0x04u, 0x40u, 0x100u, 0x80000000u, 0x103u}) { pattern = 0xdeadbeef; Require(sceKernelPollEventFlag(ef, 1, mode, &pattern) == SCE_KERNEL_ERROR_EINVAL && pattern == 0xdeadbeef); } for (const std::uint32_t mode : {EVF_WAITMODE_OR | 0x04u, EVF_WAITMODE_OR | 0x08u, EVF_WAITMODE_AND | 0x40u, EVF_WAITMODE_AND | 0x100u, EVF_WAITMODE_OR | 0x80000000u, EVF_WAITMODE_OR | 0xffffff00u}) { Require(sceKernelPollEventFlag(ef, 0x10, mode, &pattern) == SCE_OK && pattern == 0x15); } Require(sceKernelPollEventFlag(ef, 0x10, EVF_WAITMODE_OR | EVF_WAITMODE_CLEAR_PAT | 0x100u, &pattern) == SCE_OK && pattern == 0x15); Require(sceKernelSetEventFlag(ef, 0x10) == SCE_OK); Require(sceKernelPollEventFlag(ef, 0x20, EVF_WAITMODE_OR, &pattern) == SCE_KERNEL_ERROR_EBUSY); Require(pattern == 0x15); Require(sceKernelPollEventFlag(ef, 0x11, EVF_WAITMODE_AND, &pattern) == SCE_OK); Require(pattern == 0x15); Require(sceKernelClearEventFlag(ef, ~std::uint64_t{0x01}) == SCE_OK); Require(sceKernelPollEventFlag(ef, 0x01, EVF_WAITMODE_OR, &pattern) == SCE_KERNEL_ERROR_EBUSY); Require(pattern == 0x14); Require(sceKernelSetEventFlag(ef, 0x02) == SCE_OK); Require(sceKernelPollEventFlag(ef, 0x06, EVF_WAITMODE_OR | EVF_WAITMODE_CLEAR_PAT, &pattern) == SCE_OK); Require(pattern == 0x16); Require(sceKernelPollEventFlag(ef, 0x02, EVF_WAITMODE_OR, &pattern) == SCE_KERNEL_ERROR_EBUSY); Require(pattern == 0x10); Require(sceKernelPollEventFlag(ef, 0x10, EVF_WAITMODE_OR | EVF_WAITMODE_CLEAR_ALL, &pattern) == SCE_OK); Require(pattern == 0x10); Require(sceKernelPollEventFlag(ef, 0x10, EVF_WAITMODE_OR, &pattern) == SCE_KERNEL_ERROR_EBUSY); Require(pattern == 0); KernelUseconds efTimeout = 1000; Require(sceKernelWaitEventFlag(ef, 0x01, EVF_WAITMODE_OR, &pattern, &efTimeout) == SCE_KERNEL_ERROR_ETIMEDOUT); Require(pattern == 0); int waitThreads = -1; Require(sceKernelCancelEventFlag(ef, 0x42, &waitThreads) == SCE_OK); Require(waitThreads == 0); Require(sceKernelPollEventFlag(ef, 0x42, EVF_WAITMODE_AND, &pattern) == SCE_OK); Require(pattern == 0x42); Require(sceKernelClearEventFlag(ef, 0) == SCE_OK); Require(sceKernelPollEventFlag(ef, 0x42, EVF_WAITMODE_AND, &pattern) == SCE_KERNEL_ERROR_EBUSY); Require(pattern == 0); Require(sceKernelDeleteEventFlag(ef) == SCE_OK); Require(sceKernelCreateEventFlag(&ef, "single", EVF_ATTR_SINGLE | 0x02u, 0x04, nullptr) == SCE_OK); std::atomic singleRes{-1}; std::uint64_t singlePat = 0xdeadbeef; std::thread singleWaiter([&] { singleRes = sceKernelWaitEventFlag(ef, 0x01, EVF_WAITMODE_AND, &singlePat, nullptr); }); WaitForEventFlagWaiters(ef, 1); pattern = 0xdeadbeef; Require(sceKernelPollEventFlag(ef, 0x04, EVF_WAITMODE_AND, &pattern) == SCE_KERNEL_ERROR_EPERM && pattern == 0); pattern = 0xdeadbeef; Require(sceKernelWaitEventFlag(ef, 0x04, EVF_WAITMODE_AND, &pattern, nullptr) == SCE_KERNEL_ERROR_EPERM && pattern == 0); waitThreads = -1; Require(sceKernelCancelEventFlag(ef, 0x08, &waitThreads) == SCE_OK && waitThreads == 1); singleWaiter.join(); Require(singleRes == SCE_KERNEL_ERROR_ECANCELED && singlePat == 0); Require(sceKernelPollEventFlag(ef, 0x08, EVF_WAITMODE_AND, &pattern) == SCE_OK && pattern == 0x08); Require(sceKernelDeleteEventFlag(ef) == SCE_OK); Require(sceKernelCreateEventFlag(&ef, "multi_cancel", EVF_ATTR_MULTI, 0x01, nullptr) == SCE_OK); std::atomic cancelRes1{-1}; std::atomic cancelRes2{-1}; std::uint64_t cancelPat1 = 0xdeadbeef; std::uint64_t cancelPat2 = 0xdeadbeef; std::thread cancelT1([&] { cancelRes1 = sceKernelWaitEventFlag(ef, 0x02, EVF_WAITMODE_AND, &cancelPat1, nullptr); }); std::thread cancelT2([&] { cancelRes2 = sceKernelWaitEventFlag(ef, 0x04, EVF_WAITMODE_OR, &cancelPat2, nullptr); }); WaitForEventFlagWaiters(ef, 2); waitThreads = -1; Require(sceKernelCancelEventFlag(ef, 0x05, &waitThreads) == SCE_OK && waitThreads == 2); cancelT1.join(); cancelT2.join(); Require(cancelRes1 == SCE_KERNEL_ERROR_ECANCELED && cancelPat1 == 0); Require(cancelRes2 == SCE_KERNEL_ERROR_ECANCELED && cancelPat2 == 0); Require(sceKernelPollEventFlag(ef, 0x05, EVF_WAITMODE_AND, &pattern) == SCE_OK && pattern == 0x05); Require(sceKernelDeleteEventFlag(ef) == SCE_OK); Require(sceKernelCreateEventFlag(&ef, "imm_sat", EVF_ATTR_MULTI, 0x05, nullptr) == SCE_OK); pattern = 0; Require(sceKernelWaitEventFlag(ef, 0x01, EVF_WAITMODE_AND | EVF_WAITMODE_CLEAR_PAT, &pattern, nullptr) == SCE_OK); Require(pattern == 0x05); Require(sceKernelPollEventFlag(ef, 0x01, EVF_WAITMODE_AND, &pattern) == SCE_KERNEL_ERROR_EBUSY); Require(sceKernelPollEventFlag(ef, 0x04, EVF_WAITMODE_AND, &pattern) == SCE_OK); Require(sceKernelDeleteEventFlag(ef) == SCE_OK); Require(sceKernelCreateEventFlag(&ef, "multi_order_nonclear_first", EVF_ATTR_MULTI, 0, nullptr) == SCE_OK); std::atomic a1Res{-1}; std::atomic a2Res{-1}; std::uint64_t a1Pat = 0; std::uint64_t a2Pat = 0; std::thread a1([&] { a1Res = sceKernelWaitEventFlag(ef, 0x01, EVF_WAITMODE_AND, &a1Pat, nullptr); }); WaitForEventFlagWaiters(ef, 1); std::thread a2([&] { a2Res = sceKernelWaitEventFlag(ef, 0x01, EVF_WAITMODE_AND | EVF_WAITMODE_CLEAR_PAT, &a2Pat, nullptr); }); WaitForEventFlagWaiters(ef, 2); Require(sceKernelSetEventFlag(ef, 0x01) == SCE_OK); a1.join(); a2.join(); Require(a1Res == SCE_OK); Require(a2Res == SCE_OK); Require(a1Pat == 0x01); Require(a2Pat == 0x01); Require(sceKernelPollEventFlag(ef, 0x01, EVF_WAITMODE_AND, &pattern) == SCE_KERNEL_ERROR_EBUSY); Require(sceKernelDeleteEventFlag(ef) == SCE_OK); Require(sceKernelCreateEventFlag(&ef, "multi_order_clear_first", EVF_ATTR_MULTI, 0, nullptr) == SCE_OK); std::atomic b1Res{-1}; std::atomic b2Res{-1}; std::uint64_t b1Pat = 0; std::uint64_t b2Pat = 0; std::thread b1([&] { b1Res = sceKernelWaitEventFlag(ef, 0x01, EVF_WAITMODE_AND | EVF_WAITMODE_CLEAR_PAT, &b1Pat, nullptr); }); WaitForEventFlagWaiters(ef, 1); std::thread b2([&] { b2Res = sceKernelWaitEventFlag(ef, 0x01, EVF_WAITMODE_AND, &b2Pat, nullptr); }); WaitForEventFlagWaiters(ef, 2); Require(sceKernelSetEventFlag(ef, 0x01) == SCE_OK); b1.join(); Require(b1Res == SCE_OK); Require(b1Pat == 0x01); Require(APS5_Test_GetEventFlagWaiterCount(ef) == 1); Require(b2Res == -1); Require(sceKernelSetEventFlag(ef, 0x01) == SCE_OK); b2.join(); Require(b2Res == SCE_OK); Require(b2Pat == 0x01); Require(sceKernelDeleteEventFlag(ef) == SCE_OK); Require(sceKernelCreateEventFlag(&ef, "del_waiters", EVF_ATTR_MULTI, 0, nullptr) == SCE_OK); std::atomic delRes1{-1}; std::atomic delRes2{-1}; std::uint64_t delPat = 0xdeadbeef; std::thread delT1([&] { delRes1 = sceKernelWaitEventFlag(ef, 0x01, EVF_WAITMODE_AND, &delPat, nullptr); }); std::thread delT2([&] { delRes2 = sceKernelWaitEventFlag(ef, 0x02, EVF_WAITMODE_AND, nullptr, nullptr); }); WaitForEventFlagWaiters(ef, 2); Require(sceKernelDeleteEventFlag(ef) == SCE_OK); delT1.join(); delT2.join(); Require(delRes1 == SCE_KERNEL_ERROR_EACCES && delPat == 0); Require(delRes2 == SCE_KERNEL_ERROR_EACCES); for (int iter = 0; iter < 50; ++iter) { KernelEventFlag raceEf = nullptr; Require(sceKernelCreateEventFlag(&raceEf, "set_del_race", EVF_ATTR_MULTI, 0, nullptr) == SCE_OK); std::atomic setResult{-1}; std::thread concurrentSet([&] { setResult = sceKernelSetEventFlag(raceEf, 0x01); }); Require(sceKernelDeleteEventFlag(raceEf) == SCE_OK); concurrentSet.join(); Require(setResult == SCE_OK || setResult == SCE_KERNEL_ERROR_ESRCH); } for (int iter = 0; iter < 50; ++iter) { KernelEventFlag pollEf = nullptr; Require(sceKernelCreateEventFlag(&pollEf, "poll_del_race", EVF_ATTR_MULTI, 0x01, nullptr) == SCE_OK); std::atomic pollResult{-1}; std::thread concurrentPoll([&] { std::uint64_t observed = 0; pollResult = sceKernelPollEventFlag(pollEf, 0x01, EVF_WAITMODE_AND, &observed); }); Require(sceKernelDeleteEventFlag(pollEf) == SCE_OK); concurrentPoll.join(); Require(pollResult == SCE_OK || pollResult == SCE_KERNEL_ERROR_ESRCH); } }