#include "prx/libc/include/general/VabiMacros.hpp" #include #include #include #include #include #include #include #include struct Xtime { std::int64_t sec; std::int64_t nsec; }; extern "C" { float APS5_VABI nearbyintf_nid_postfix(float x); int APS5_VABI _Mtx_init_nid_postfix(void** handle, int type); void APS5_VABI _Mtx_destroy_nid_postfix(void** handle); int APS5_VABI _Mtx_lock_nid_postfix(void** handle); int APS5_VABI _Mtx_unlock_nid_postfix(void** handle); int APS5_VABI _Mtx_trylock_nid_postfix(void** handle); int APS5_VABI _Thrd_sleep_nid_postfix(const Xtime* target, Xtime* remaining); } namespace { void Require(bool value) { if (!value) std::abort(); } template void RequireThrows(TCall call) { try { call(); } catch (const TException&) { return; } std::abort(); } constexpr int threadSuccess = 0; constexpr int threadBusy = 3; constexpr int mutexTryable = 0x02; constexpr int mutexRecursive = 0x100; constexpr std::int64_t nanosPerSecond = 1000000000LL; void TestNearbyintf() { const float half = nearbyintf_nid_postfix(0.5f); Require(half == 0.0f); Require(!std::signbit(half)); const float negHalf = nearbyintf_nid_postfix(-0.5f); Require(negHalf == 0.0f); Require(std::signbit(negHalf)); Require(nearbyintf_nid_postfix(1.5f) == 2.0f); Require(nearbyintf_nid_postfix(-1.5f) == -2.0f); Require(nearbyintf_nid_postfix(2.5f) == 2.0f); Require(nearbyintf_nid_postfix(-2.5f) == -2.0f); const float negZero = nearbyintf_nid_postfix(-0.0f); Require(negZero == 0.0f); Require(std::signbit(negZero)); const float inf = std::numeric_limits::infinity(); const float posInf = nearbyintf_nid_postfix(inf); Require(std::isinf(posInf) && posInf > 0.0f); const float negInf = nearbyintf_nid_postfix(-inf); Require(std::isinf(negInf) && negInf < 0.0f); const float nan = std::numeric_limits::quiet_NaN(); Require(std::isnan(nearbyintf_nid_postfix(nan))); } void TestMtxTrylock() { void* mutex = nullptr; Require(_Mtx_init_nid_postfix(&mutex, mutexTryable) == threadSuccess && mutex != nullptr); Require(_Mtx_trylock_nid_postfix(&mutex) == threadSuccess); Require(_Mtx_trylock_nid_postfix(&mutex) == threadBusy); Require(_Mtx_unlock_nid_postfix(&mutex) == threadSuccess); std::atomic held{false}; std::atomic release{false}; std::thread other([&] { Require(_Mtx_lock_nid_postfix(&mutex) == threadSuccess); held.store(true, std::memory_order_release); while (!release.load(std::memory_order_acquire)) std::this_thread::yield(); Require(_Mtx_unlock_nid_postfix(&mutex) == threadSuccess); }); while (!held.load(std::memory_order_acquire)) std::this_thread::yield(); Require(_Mtx_trylock_nid_postfix(&mutex) == threadBusy); release.store(true, std::memory_order_release); other.join(); Require(_Mtx_trylock_nid_postfix(&mutex) == threadSuccess); Require(_Mtx_unlock_nid_postfix(&mutex) == threadSuccess); _Mtx_destroy_nid_postfix(&mutex); void* recMutex = nullptr; Require(_Mtx_init_nid_postfix(&recMutex, mutexTryable | mutexRecursive) == threadSuccess && recMutex != nullptr); Require(_Mtx_trylock_nid_postfix(&recMutex) == threadSuccess); Require(_Mtx_trylock_nid_postfix(&recMutex) == threadSuccess); Require(_Mtx_trylock_nid_postfix(&recMutex) == threadSuccess); std::thread([&] { Require(_Mtx_trylock_nid_postfix(&recMutex) == threadBusy); }).join(); Require(_Mtx_unlock_nid_postfix(&recMutex) == threadSuccess); std::thread([&] { Require(_Mtx_trylock_nid_postfix(&recMutex) == threadBusy); }).join(); Require(_Mtx_unlock_nid_postfix(&recMutex) == threadSuccess); std::thread([&] { Require(_Mtx_trylock_nid_postfix(&recMutex) == threadBusy); }).join(); Require(_Mtx_unlock_nid_postfix(&recMutex) == threadSuccess); std::thread([&] { Require(_Mtx_trylock_nid_postfix(&recMutex) == threadSuccess); Require(_Mtx_unlock_nid_postfix(&recMutex) == threadSuccess); }).join(); _Mtx_destroy_nid_postfix(&recMutex); } void TestThrdSleep() { timespec before{}; Require(clock_gettime(CLOCK_REALTIME, &before) == 0); const std::int64_t sleepNanos = 20000000LL; const std::int64_t targetTotal = static_cast(before.tv_sec) * nanosPerSecond + before.tv_nsec + sleepNanos; const Xtime target{targetTotal / nanosPerSecond, targetTotal % nanosPerSecond}; Require(_Thrd_sleep_nid_postfix(&target, nullptr) == 0); timespec after{}; Require(clock_gettime(CLOCK_REALTIME, &after) == 0); const std::int64_t afterTotal = static_cast(after.tv_sec) * nanosPerSecond + after.tv_nsec; Require(afterTotal >= targetTotal); const Xtime past{before.tv_sec - 1, before.tv_nsec}; Require(_Thrd_sleep_nid_postfix(&past, nullptr) == 0); RequireThrows([] { _Thrd_sleep_nid_postfix(nullptr, nullptr); }); } } int main() { TestNearbyintf(); TestMtxTrylock(); TestThrdSleep(); return 0; }