Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions core/libs/prx/libc/src/Threads.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#include "prx/libc/include/general/VabiMacros.hpp"
#include "prx/libc/include/General.hpp"
#ifdef _WIN32
#include "prx/libc/include/PreciseWait.hpp"
#endif
#include <algorithm>
#include <atomic>
#include <cerrno>
Expand Down Expand Up @@ -291,11 +294,16 @@ int APS5_VABI _Thrd_sleep_nid_postfix(const Xtime* target, Xtime*) {
--remaining.tv_sec;
}
remaining.tv_sec = std::min<time_t>(remaining.tv_sec, longestSleepSeconds);
#ifdef _WIN32
PreciseSleepHundredNanos(static_cast<unsigned long long>(remaining.tv_sec) * 10000000ULL +
(static_cast<unsigned long long>(remaining.tv_nsec) + 99ULL) / 100ULL);
#else
if (nanosleep(&remaining, nullptr) != 0) {
if (errno == EINTR)
continue;
throw std::runtime_error("_Thrd_sleep: nanosleep failed");
}
#endif
}
}

Expand Down
18 changes: 18 additions & 0 deletions core/libs/tests/GuestAmprThreads.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "SceTypes.hpp"
#include "prx/libc/include/exceptions/Runtime.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"
#include <algorithm>
#include <array>
#include <atomic>
#include <chrono>
Expand Down Expand Up @@ -188,6 +189,23 @@ static void TestThreadSleep() {
Require(_Thrd_sleep_nid_postfix(&negative, nullptr) == 0);
Require(RealtimeNanos() >= borrowed.sec * NanosPerSecond + borrowed.nsec);

#ifdef _WIN32
for (const auto duration : {100000LL, 2000000LL}) {
std::array<std::chrono::nanoseconds, 31> samples{};
for (auto& sample : samples) {
const auto start = std::chrono::steady_clock::now();
const auto shortTarget = XtimeAfter(duration);
Require(_Thrd_sleep_nid_postfix(&shortTarget, nullptr) == ThrdSuccess);
sample = std::chrono::steady_clock::now() - start;
Require(RealtimeNanos() >= shortTarget.sec * NanosPerSecond + shortTarget.nsec);
}
std::sort(samples.begin(), samples.end());
const auto median = samples[samples.size() / 2];
std::fprintf(stderr, "_Thrd_sleep(%lld ns) median: %lld ns\n", duration, static_cast<long long>(median.count()));
Require(median < std::chrono::milliseconds(12));
}
#endif

bool rejected = false;
try {
_Thrd_sleep_nid_postfix(nullptr, nullptr);
Expand Down
2 changes: 1 addition & 1 deletion docs/dev/debt/libc.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
- [_Mtx_trylock](../../../core/libs/prx/libc/src/Threads.cpp) (libc, NID `k6pGNMwJB08`) - returns busy for a non-recursive mutex already owned by the caller, assumed to match `_Mtx_lock`'s ownership handling; exact console behavior is unverified.
- [nearbyintf](../../../core/libs/prx/libc/src/Math.cpp) (libc, NID `c+4r-T-tEIc`) uses the host rounding mode, not the console's; console rounding mode state remains unverified.
- [__std_find_trivial_unsized_N](../../../core/libs/prx/libc/src/VectorAlgorithms.cpp) (libc) - matches the `libc.prx` bundled with PPSA08427 (disassembly, and that binary run side by side on random inputs): when nothing matches between `first` and the end of its 32-byte-aligned block, the console rescans that whole block without masking and so can return a match up to 31 bytes before `first`
- [_Thrd_sleep](../../../core/libs/prx/libc/src/Threads.cpp) (libc, NID `jfRI3snge3o`) follows the Dinkumware threads library shipped with [Visual C++ 2013](https://github.com/adityaramesh/concurrency_runtime/tree/master/VS2013_SP2/crt/src/thr) (`xtime.c`) and C11 Annex K, without console verification. It reads a 16-byte xtime (64-bit seconds and nanoseconds) on the guest `CLOCK_REALTIME`, normalizes the nanoseconds and sleeps through `nanosleep`, retrying on `EINTR`, so it is a cancellation point; a null xtime or one whose normalization overflows throws. The console's `_Thrd_sleep` (disassembled from a title's `libc.prx`) also takes an optional `xtime*` of remaining time and returns `int`; here the sleep is never cut short, so it returns 0 and leaves the remaining time untouched.
- [_Thrd_sleep](../../../core/libs/prx/libc/src/Threads.cpp) (libc, NID `jfRI3snge3o`) follows the Dinkumware threads library shipped with [Visual C++ 2013](https://github.com/adityaramesh/concurrency_runtime/tree/master/VS2013_SP2/crt/src/thr) (`xtime.c`) and C11 Annex K, without console verification. It reads a 16-byte xtime (64-bit seconds and nanoseconds) on the guest `CLOCK_REALTIME`, normalizes the nanoseconds and sleeps through `nanosleep` on POSIX, retrying on `EINTR`, or high-resolution waitable timers on Windows; a null xtime or one whose normalization overflows throws. Guest thread cancellation is not integrated with this wait. The console's `_Thrd_sleep` (disassembled from a title's `libc.prx`) also takes an optional `xtime*` of remaining time and returns `int`; here the sleep is never cut short, so it returns 0 and leaves the remaining time untouched.
- [_Mtx_init_with_name](../../../core/libs/prx/libc/src/Threads.cpp) (libc, NID `tgioGpKtmbE`) forwards to `_Mtx_init` and ignores the mutex name parameter.
- [_Cnd_timedwait](../../../core/libs/prx/libc/src/Threads.cpp) (libc, NID `McaImWKXong`) follows the console's `_Cnd_timedwait` (disassembled from a title's `libc.prx`), where xtime is an absolute deadline converted against the current time: it returns `_Thrd_timedout` (2) on expiration and `_Thrd_success` (0) on notification. The console returns 4 for other internal pthread errors while this implementation throws.
- [fegetround, fesetround, fetestexcept, feclearexcept, fegetexceptflag and fesetexceptflag](../../../core/libs/prx/libc/src/FloatingPoint.cpp) (libSceLibcInternal, implemented in libc) follow FreeBSD 11.4 amd64 [fenv.h](https://github.com/freebsd/freebsd-src/blob/4554bee35405b36ea19e9e60d6abe6ea534e36e0/lib/msun/x86/fenv.h): rounding modes use x87 control bits 10-11, exception flags include denormals (`0x3f`), and `fexcept_t` is 16 bits. They access the current host thread's x87 and MXCSR state. This console ABI is assumed, as for `fegetenv`, not measured on hardware. Null flag pointers throw instead of faulting.
Expand Down
Loading