diff --git a/core/libs/prx/libc/CMakeLists.txt b/core/libs/prx/libc/CMakeLists.txt index dfbe462ee1..233ff92c44 100644 --- a/core/libs/prx/libc/CMakeLists.txt +++ b/core/libs/prx/libc/CMakeLists.txt @@ -451,6 +451,16 @@ if(BUILD_TESTING) set_tests_properties(guest_libc_threads PROPERTIES ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$") endif() + add_test_executable(guest_std_thread_hardware_concurrency_tests ${LIBS_INCLUDE_DIR}/tests/GuestStdThreadHardwareConcurrency.cpp) + target_include_directories(guest_std_thread_hardware_concurrency_tests PRIVATE ${LIBS_INCLUDE_DIR}) + target_link_libraries(guest_std_thread_hardware_concurrency_tests PRIVATE libc) + configure_windows_unwind(guest_std_thread_hardware_concurrency_tests) + add_test(NAME guest_std_thread_hardware_concurrency COMMAND guest_std_thread_hardware_concurrency_tests) + set_tests_properties(guest_std_thread_hardware_concurrency PROPERTIES TIMEOUT 20) + if(WIN32) + set_tests_properties(guest_std_thread_hardware_concurrency PROPERTIES ENVIRONMENT_MODIFICATION + "PATH=path_list_prepend:$") + endif() add_test_executable(guest_libc_static_imports_tests ${LIBS_INCLUDE_DIR}/tests/GuestLibcStaticImports.cpp) target_include_directories(guest_libc_static_imports_tests PRIVATE ${LIBS_INCLUDE_DIR}) target_link_libraries(guest_libc_static_imports_tests PRIVATE libc) diff --git a/core/libs/prx/libc/src/Threads.cpp b/core/libs/prx/libc/src/Threads.cpp index 1e7ea35688..4933672426 100644 --- a/core/libs/prx/libc/src/Threads.cpp +++ b/core/libs/prx/libc/src/Threads.cpp @@ -350,6 +350,10 @@ int SignalCondition_nid_no_patch(void** handle) { return threadSuccess; } +unsigned APS5_VABI _ZNSt6thread20hardware_concurrencyEv_nid_postfix() { + return std::thread::hardware_concurrency(); +} + int APS5_VABI _Thrd_sleep_nid_postfix(const Xtime* target, Xtime*) { if (!target) APS5_INVALID_ARG_EX; diff --git a/core/libs/tests/GuestStdThreadHardwareConcurrency.cpp b/core/libs/tests/GuestStdThreadHardwareConcurrency.cpp new file mode 100644 index 0000000000..6b53d172cf --- /dev/null +++ b/core/libs/tests/GuestStdThreadHardwareConcurrency.cpp @@ -0,0 +1,15 @@ +#include "prx/libc/include/general/VabiMacros.hpp" +#include +#include + +extern "C" unsigned APS5_VABI _ZNSt6thread20hardware_concurrencyEv_nid_postfix(); + +int main() { + const unsigned result = _ZNSt6thread20hardware_concurrencyEv_nid_postfix(); + if (result != std::thread::hardware_concurrency()) { + std::fprintf(stderr, "guest processor hint %u differs from std::thread::hardware_concurrency %u\n", + result, std::thread::hardware_concurrency()); + return 1; + } + return 0; +} diff --git a/docs/dev/debt/libc.md b/docs/dev/debt/libc.md index 3fc92fea9e..abcc20d6f1 100644 --- a/docs/dev/debt/libc.md +++ b/docs/dev/debt/libc.md @@ -61,6 +61,7 @@ ### Functional - [_Cosh](../../../core/libs/prx/libc/src/Math.cpp) (libc) follows the two-argument Dinkumware CRT helper used by `std::complex`, including a scaled large-finite-input path; the signature, exact result and floating-point exception behavior are not verified against the console. +- [std::thread::hardware_concurrency](../../../core/libs/prx/libc/src/Threads.cpp) (libc, NID `CHrhwd8QSBs`) returns the host's `std::thread::hardware_concurrency()` (which may be 0 when unknown) instead of the console's processor count; no reference implements it and the value a title expects (PPSA34015 imports it) is unverified. - [fmodf](../../../core/libs/prx/libc/src/Math.cpp) (libc) - console `errno`, exception flags and NaN payloads remain unverified. The wrapper preserves `errno` like the existing double `fmod`, following FreeBSD 11.4 [`e_fmodf.c`](https://github.com/freebsd/freebsd-src/blob/release/11.4.0/lib/msun/src/e_fmodf.c); host `std::fmod` still supplies the result and exception flags. - [_FSinh and _FCosh](../../../core/libs/prx/libc/src/Math.cpp) (libc) finite results are not verified bit for bit against the console: the scaled product uses the host's binary64 hyperbolic function before rounding to binary32, rather than the float rational and `_FExp` sequence in PRAGMATA's bundled `libc.prx`. NaN preference and payloads, signed zeros, infinite operands and the range-error thresholds follow that binary's instructions; the system `libSceLibcInternal` implementation and nondefault flush-to-zero modes are unverified.