diff --git a/core/libs/prx/libkernel/CMakeLists.txt b/core/libs/prx/libkernel/CMakeLists.txt index 2520ab4772f..e898d2146d2 100644 --- a/core/libs/prx/libkernel/CMakeLists.txt +++ b/core/libs/prx/libkernel/CMakeLists.txt @@ -210,6 +210,16 @@ if(BUILD_TESTING) set_tests_properties(guest_cond_timedwait PROPERTIES ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$") endif() + add_test_executable(guest_condattr_setclock_tests ${LIBS_INCLUDE_DIR}/tests/GuestCondattrSetclock.cpp) + target_include_directories(guest_condattr_setclock_tests PRIVATE ${LIBS_INCLUDE_DIR}) + target_link_libraries(guest_condattr_setclock_tests PRIVATE libkernel libc) + configure_windows_unwind(guest_condattr_setclock_tests) + add_test(NAME guest_condattr_setclock COMMAND guest_condattr_setclock_tests) + set_tests_properties(guest_condattr_setclock PROPERTIES TIMEOUT 20) + if(WIN32) + set_tests_properties(guest_condattr_setclock PROPERTIES ENVIRONMENT_MODIFICATION + "PATH=path_list_prepend:$") + endif() add_test_executable(guest_cpu_time_clocks_tests ${LIBS_INCLUDE_DIR}/tests/GuestCpuTimeClocks.cpp) target_include_directories(guest_cpu_time_clocks_tests PRIVATE ${LIBS_INCLUDE_DIR}) target_link_libraries(guest_cpu_time_clocks_tests PRIVATE libkernel libc) diff --git a/core/libs/prx/libkernel/Pthread/Posix/Cond.cpp b/core/libs/prx/libkernel/Pthread/Posix/Cond.cpp index b9a7b211cc5..a31fe550208 100644 --- a/core/libs/prx/libkernel/Pthread/Posix/Cond.cpp +++ b/core/libs/prx/libkernel/Pthread/Posix/Cond.cpp @@ -57,6 +57,7 @@ int APS5_VABI pthread_condattr_init_nid_postfix(PthreadCondattr* attr) { int APS5_VABI pthread_condattr_setclock_nid_postfix(PthreadCondattr* attr, KernelClockid clock_id) { if (!attr || !*attr) return PosixThread::GUEST_EINVAL; + if (clock_id != 0 && clock_id != 1 && clock_id != 2 && clock_id != 4) return PosixThread::GUEST_EINVAL; return toPosix(scePthreadCondattrSetclock(attr, clock_id)); } diff --git a/core/libs/tests/GuestCondattrSetclock.cpp b/core/libs/tests/GuestCondattrSetclock.cpp new file mode 100644 index 00000000000..6abbc3f190c --- /dev/null +++ b/core/libs/tests/GuestCondattrSetclock.cpp @@ -0,0 +1,75 @@ +#include "SceTypes.hpp" +#include +#include +#include +#include + +extern "C" { +int APS5_VABI pthread_condattr_init_nid_postfix(PthreadCondattr* attr); +int APS5_VABI pthread_condattr_destroy_nid_postfix(PthreadCondattr* attr); +int APS5_VABI pthread_condattr_setclock_nid_postfix(PthreadCondattr* attr, KernelClockid clockId); +int APS5_VABI pthread_cond_init_nid_postfix(PthreadCond* cond, const PthreadCondattr* attr); +int APS5_VABI pthread_cond_destroy_nid_postfix(PthreadCond* cond); +int APS5_VABI pthread_cond_timedwait_nid_postfix(PthreadCond* cond, PthreadMutex* mutex, const KernelTimespec* abstime); +int APS5_VABI pthread_mutex_init_nid_postfix(PthreadMutex* mutex, const PthreadMutexattr* attr); +int APS5_VABI pthread_mutex_destroy_nid_postfix(PthreadMutex* mutex); +int APS5_VABI pthread_mutex_lock_nid_postfix(PthreadMutex* mutex); +int APS5_VABI pthread_mutex_unlock_nid_postfix(PthreadMutex* mutex); +int APS5_VABI clock_gettime_nid_postfix(KernelClockid clockId, KernelTimespec* tp); +int* APS5_VABI __error_nid_postfix(); +} + +static constexpr int GUEST_EINVAL = 22; +static constexpr int GUEST_ETIMEDOUT = 60; +static constexpr int GUEST_EINTR = 4; + +static void RequireResult(const char* operation, int actual, int expected) { + if (actual != expected) { + std::fprintf(stderr, "%s: expected %d, got %d\n", operation, expected, actual); + std::abort(); + } +} + +static void RequireGuestErrno(const char* operation, int expected) { + const int actual = *__error_nid_postfix(); + if (actual != expected) { + std::fprintf(stderr, "%s changed guest errno: expected %d, got %d\n", operation, expected, actual); + std::abort(); + } +} + +int main() { + PthreadCondattr attr = nullptr; + RequireResult("pthread_condattr_setclock null pointer", pthread_condattr_setclock_nid_postfix(nullptr, 4), GUEST_EINVAL); + RequireResult("pthread_condattr_setclock null attribute", pthread_condattr_setclock_nid_postfix(&attr, 4), GUEST_EINVAL); + RequireResult("pthread_condattr_init", pthread_condattr_init_nid_postfix(&attr), 0); + + for (const KernelClockid clockId : {0, 1, 2, 4}) { + *__error_nid_postfix() = GUEST_EINTR; + RequireResult("pthread_condattr_setclock valid clock", pthread_condattr_setclock_nid_postfix(&attr, clockId), 0); + RequireGuestErrno("pthread_condattr_setclock valid clock", GUEST_EINTR); + } + + const KernelClockid invalidClockIds[] = {3, 5, -1, INT_MAX}; + for (const KernelClockid clockId : invalidClockIds) { + *__error_nid_postfix() = GUEST_EINTR; + RequireResult("pthread_condattr_setclock invalid clock", pthread_condattr_setclock_nid_postfix(&attr, clockId), GUEST_EINVAL); + RequireGuestErrno("pthread_condattr_setclock invalid clock", GUEST_EINTR); + } + + PthreadCond cond = nullptr; + PthreadMutex mutex = nullptr; + RequireResult("pthread_cond_init", pthread_cond_init_nid_postfix(&cond, &attr), 0); + RequireResult("pthread_mutex_init", pthread_mutex_init_nid_postfix(&mutex, nullptr), 0); + RequireResult("pthread_mutex_lock", pthread_mutex_lock_nid_postfix(&mutex), 0); + + KernelTimespec deadline{}; + RequireResult("clock_gettime monotonic", clock_gettime_nid_postfix(4, &deadline), 0); + RequireResult("pthread_cond_timedwait expired monotonic deadline", pthread_cond_timedwait_nid_postfix(&cond, &mutex, &deadline), GUEST_ETIMEDOUT); + + RequireResult("pthread_mutex_unlock", pthread_mutex_unlock_nid_postfix(&mutex), 0); + RequireResult("pthread_cond_destroy", pthread_cond_destroy_nid_postfix(&cond), 0); + RequireResult("pthread_mutex_destroy", pthread_mutex_destroy_nid_postfix(&mutex), 0); + RequireResult("pthread_condattr_destroy", pthread_condattr_destroy_nid_postfix(&attr), 0); + RequireResult("pthread_condattr_setclock destroyed attribute", pthread_condattr_setclock_nid_postfix(&attr, 4), GUEST_EINVAL); +}