diff --git a/core/libs/prx/libkernel/Pthread/Posix/Common.hpp b/core/libs/prx/libkernel/Pthread/Posix/Common.hpp index cf95f707e0..2265216482 100644 --- a/core/libs/prx/libkernel/Pthread/Posix/Common.hpp +++ b/core/libs/prx/libkernel/Pthread/Posix/Common.hpp @@ -24,10 +24,18 @@ inline bool RelativeMicroseconds(int clockId, const KernelTimespec* abstime, Ker if (!abstime || abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) return false; KernelTimespec now{}; clock_gettime_nid_postfix(clockId, &now); - const auto deadline = std::chrono::seconds(abstime->tv_sec) + std::chrono::nanoseconds(abstime->tv_nsec); - const auto current = std::chrono::seconds(now.tv_sec) + std::chrono::nanoseconds(now.tv_nsec); - const auto remaining = std::chrono::duration_cast(deadline - current).count(); - *usec = remaining <= 0 ? 0 : remaining >= std::numeric_limits::max() ? std::numeric_limits::max() : static_cast(remaining); + constexpr auto maximum = std::numeric_limits::max(); + if (abstime->tv_sec < now.tv_sec - 1) { + *usec = 0; + return true; + } + const std::int64_t seconds = abstime->tv_sec - now.tv_sec; + if (seconds > static_cast(maximum / 1000000) + 1) { + *usec = maximum; + return true; + } + const std::int64_t remaining = (seconds * 1000000000 + abstime->tv_nsec - now.tv_nsec) / 1000; + *usec = remaining <= 0 ? 0 : remaining >= maximum ? maximum : static_cast(remaining); return true; } diff --git a/core/libs/tests/GuestPthreadRwlock.cpp b/core/libs/tests/GuestPthreadRwlock.cpp index ffae6559ae..223de90306 100644 --- a/core/libs/tests/GuestPthreadRwlock.cpp +++ b/core/libs/tests/GuestPthreadRwlock.cpp @@ -190,8 +190,23 @@ static void CheckFailedLockAttempts() { Require(rwlock == nullptr); } +static void CheckDeadlinesBeyondTheClockRange() { + PthreadRwlock rwlock = nullptr; + Holder reader{&rwlock, false}; + Start(reader); + const KernelTimespec farPast{INT64_MIN, 0}; + Require(pthread_rwlock_timedwrlock_nid_postfix(&rwlock, &farPast) == GUEST_ETIMEDOUT); + reader.release.store(true); + const KernelTimespec farFuture{INT64_MAX, 0}; + Require(pthread_rwlock_timedwrlock_nid_postfix(&rwlock, &farFuture) == 0); + Require(pthread_rwlock_unlock_nid_postfix(&rwlock) == 0); + Require(scePthreadJoin(reader.thread, nullptr) == SCE_OK); + Require(pthread_rwlock_destroy_nid_postfix(&rwlock) == 0); +} + int main() { CheckConcurrentFirstWrlockExcludes(); + CheckDeadlinesBeyondTheClockRange(); const KernelTimespec invalid{0, NANOS_PER_SECOND}; PthreadRwlock fresh[4] = {}; Require(pthread_rwlock_tryrdlock_nid_postfix(&fresh[0]) == 0);