diff --git a/core/libs/prx/libkernel/CMakeLists.txt b/core/libs/prx/libkernel/CMakeLists.txt index 3f10d3021..4eeda26c9 100644 --- a/core/libs/prx/libkernel/CMakeLists.txt +++ b/core/libs/prx/libkernel/CMakeLists.txt @@ -303,6 +303,16 @@ if(BUILD_TESTING) set_tests_properties(guest_available_cpumask PROPERTIES ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$") endif() + add_test_executable(guest_getrusage_tests ${LIBS_INCLUDE_DIR}/tests/GuestGetrusage.cpp) + target_include_directories(guest_getrusage_tests PRIVATE ${LIBS_INCLUDE_DIR}) + target_link_libraries(guest_getrusage_tests PRIVATE libkernel libc) + configure_windows_unwind(guest_getrusage_tests) + add_test(NAME guest_getrusage COMMAND guest_getrusage_tests) + set_tests_properties(guest_getrusage PROPERTIES TIMEOUT 20) + if(WIN32) + set_tests_properties(guest_getrusage PROPERTIES ENVIRONMENT_MODIFICATION + "PATH=path_list_prepend:$") + endif() add_test_executable(guest_kernel_error_tests ${LIBS_INCLUDE_DIR}/tests/GuestKernelErrors.cpp) target_include_directories(guest_kernel_error_tests PRIVATE ${LIBS_INCLUDE_DIR}) target_link_libraries(guest_kernel_error_tests PRIVATE libkernel libc) diff --git a/core/libs/prx/libkernel/System/src/Process.cpp b/core/libs/prx/libkernel/System/src/Process.cpp index a3838db51..cc9e1301f 100644 --- a/core/libs/prx/libkernel/System/src/Process.cpp +++ b/core/libs/prx/libkernel/System/src/Process.cpp @@ -290,10 +290,8 @@ int APS5_VABI getrusage_nid_postfix(int who, GuestResourceUsage* usage) { usage->ru_nvcsw = 0; usage->ru_nivcsw = 0; #else - if (who == 1) - throw std::invalid_argument("getrusage: RUSAGE_THREAD is not supported on this platform"); struct rusage native{}; - if (::getrusage(RUSAGE_SELF, &native) != 0) + if (::getrusage(who == 0 ? RUSAGE_SELF : RUSAGE_THREAD, &native) != 0) throw std::system_error(errno, std::generic_category(), "getrusage: getrusage failed"); usage->ru_utime.tv_sec = static_cast(native.ru_utime.tv_sec); usage->ru_utime.tv_usec = static_cast(native.ru_utime.tv_usec); diff --git a/core/libs/tests/GuestGetrusage.cpp b/core/libs/tests/GuestGetrusage.cpp new file mode 100644 index 000000000..a549808cf --- /dev/null +++ b/core/libs/tests/GuestGetrusage.cpp @@ -0,0 +1,42 @@ +#include "prx/libc/include/general/VabiMacros.hpp" +#include +#include +#include +#include +struct Timeval { + std::int64_t tv_sec; + std::int64_t tv_usec; +}; +struct ResourceUsage { + Timeval ru_utime; + Timeval ru_stime; + std::int64_t rest[14]; +}; +extern "C" int APS5_VABI getrusage_nid_postfix(int who, ResourceUsage* usage); +static void Require(bool value) { if (!value) std::abort(); } +static std::int64_t CpuMicros(int who) { + ResourceUsage usage{}; + Require(getrusage_nid_postfix(who, &usage) == 0); + return (usage.ru_utime.tv_sec + usage.ru_stime.tv_sec) * 1000000 + usage.ru_utime.tv_usec + usage.ru_stime.tv_usec; +} +static void SpinUntil(int who, std::int64_t micros) { + const auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(10); + volatile std::uint64_t sink = 0; + while (CpuMicros(who) < micros) { + for (int i = 0; i < 100000; ++i) sink = sink + i; + Require(std::chrono::steady_clock::now() < deadline); + } +} +int main() { + SpinUntil(0, 400000); + const std::int64_t mainThread = CpuMicros(1); + Require(mainThread >= 200000); + std::thread worker([] { + const std::int64_t fresh = CpuMicros(1); + Require(fresh < 100000); + SpinUntil(1, fresh + 100000); + Require(CpuMicros(0) >= CpuMicros(1) + 300000); + }); + worker.join(); + Require(CpuMicros(0) >= 500000); +}