From 45eb4923357b85e7ce9547568d689b8abbe0f072 Mon Sep 17 00:00:00 2001 From: Ramzi Date: Fri, 9 Oct 2026 01:05:15 +0100 Subject: [PATCH] feat(libkernel): implement pthread_getaffinity_np Report the thread's affinity mask as a 32-byte FreeBSD cpuset_t, with FreeBSD 11's errors: ERANGE for any other set size, ESRCH for a null thread and EFAULT for a null set. EVO-PLAYER (PPSA99039 v0.11.0) imports it (Jb2uGFMr688) and calls it once with a 32-byte set on pthread_self(). --- .../prx/libkernel/Pthread/Posix/Thread.cpp | 15 ++++++++++ core/libs/tests/GuestAvailableCpumask.cpp | 28 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/core/libs/prx/libkernel/Pthread/Posix/Thread.cpp b/core/libs/prx/libkernel/Pthread/Posix/Thread.cpp index 73111721c..13a72d1b8 100644 --- a/core/libs/prx/libkernel/Pthread/Posix/Thread.cpp +++ b/core/libs/prx/libkernel/Pthread/Posix/Thread.cpp @@ -9,6 +9,7 @@ #include "Common.hpp" #include "prx/libkernel/KernelErrors.hpp" #include +#include #include extern "C" { @@ -28,6 +29,8 @@ int APS5_VABI scePthreadGetprio(Pthread thread, int* prio); } static constexpr int GUEST_SCHED_FIFO = 1; +static constexpr std::size_t GUEST_CPUSET_BYTES = 32; +static constexpr int GUEST_ERANGE = 34; extern "C" { int* APS5_VABI __error_nid_postfix(); @@ -116,6 +119,18 @@ int APS5_VABI pthread_getschedparam_nid_postfix(Pthread thread, int* policy, Ker return PosixThread::ToErrno(scePthreadGetprio(thread, ¶m->sched_priority)); } +int APS5_VABI pthread_getaffinity_np_nid_postfix(Pthread thread, std::size_t cpusetSize, void* cpuset) { + if (!thread) return PosixThread::GUEST_EINVAL; + if (cpusetSize != GUEST_CPUSET_BYTES) return GUEST_ERANGE; + if (!cpuset) return PosixThread::GUEST_EFAULT; + KernelCpumask mask = 0; + const int result = scePthreadGetaffinity(thread, &mask); + if (result != 0) return PosixThread::ToErrno(result); + std::memset(cpuset, 0, GUEST_CPUSET_BYTES); + std::memcpy(cpuset, &mask, sizeof(mask)); + return 0; +} + int APS5_VABI pthread_join_nid_postfix(Pthread thread, void** value) { return PosixThread::ToErrno(scePthreadJoin(thread, value)); } diff --git a/core/libs/tests/GuestAvailableCpumask.cpp b/core/libs/tests/GuestAvailableCpumask.cpp index 3e5d6b343..4a1076604 100644 --- a/core/libs/tests/GuestAvailableCpumask.cpp +++ b/core/libs/tests/GuestAvailableCpumask.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include extern "C" { @@ -18,6 +19,8 @@ int APS5_VABI cpuset_getaffinity_nid_postfix(int level, int which, std::int64_t int APS5_VABI cpuset_setaffinity_nid_postfix(int level, int which, std::int64_t id, std::size_t size, const void* mask); int APS5_VABI getpid_nid_postfix(void); int* APS5_VABI __error_nid_postfix(); +Pthread APS5_VABI pthread_self_nid_postfix(void); +int APS5_VABI pthread_getaffinity_np_nid_postfix(Pthread thread, std::size_t cpusetSize, void* cpuset); } static constexpr int SCE_OK = 0; @@ -25,6 +28,22 @@ static constexpr int PS5_LOGICAL_CPUS = 16; static void Require(bool value) { if (!value) std::abort(); } +static constexpr std::size_t GUEST_CPUSET_BYTES = 32; +static constexpr int GUEST_EINVAL = 22; +static constexpr int GUEST_EFAULT = 14; +static constexpr int GUEST_ERANGE = 34; + +static KernelCpumask ReadCpuset(Pthread thread) { + std::uint8_t cpuset[GUEST_CPUSET_BYTES + 8]; + std::memset(cpuset, 0xAB, sizeof(cpuset)); + Require(pthread_getaffinity_np_nid_postfix(thread, GUEST_CPUSET_BYTES, cpuset) == 0); + for (std::size_t i = sizeof(KernelCpumask); i < GUEST_CPUSET_BYTES; ++i) Require(cpuset[i] == 0); + for (std::size_t i = GUEST_CPUSET_BYTES; i < sizeof(cpuset); ++i) Require(cpuset[i] == 0xAB); + KernelCpumask mask = 0; + std::memcpy(&mask, cpuset, sizeof(mask)); + return mask; +} + static void* APS5_VABI Worker(void* arg) { static_cast*>(arg)->get(); return nullptr; @@ -102,6 +121,7 @@ int main() { Require(scePthreadSetaffinity(thread, cpu) == SCE_OK); Require(scePthreadGetaffinity(thread, &threadAffinity) == SCE_OK); Require(threadAffinity == cpu); + Require(ReadCpuset(thread) == cpu); } release.set_value(); Require(scePthreadJoin(thread, nullptr) == SCE_OK); @@ -143,4 +163,12 @@ int main() { hold.set_value(); Require(scePthreadJoin(bystander, nullptr) == SCE_OK); Require(scePthreadAttrDestroy(&attr) == SCE_OK); + + Require(ReadCpuset(pthread_self_nid_postfix()) == available); + std::uint8_t rawSet[GUEST_CPUSET_BYTES]{}; + for (const std::size_t size : {std::size_t{0}, std::size_t{8}, std::size_t{31}, std::size_t{33}, std::size_t{64}}) + Require(pthread_getaffinity_np_nid_postfix(pthread_self_nid_postfix(), size, rawSet) == GUEST_ERANGE); + Require(pthread_getaffinity_np_nid_postfix(nullptr, GUEST_CPUSET_BYTES, rawSet) == GUEST_EINVAL); + Require(pthread_getaffinity_np_nid_postfix(nullptr, 0, rawSet) == GUEST_EINVAL); + Require(pthread_getaffinity_np_nid_postfix(pthread_self_nid_postfix(), GUEST_CPUSET_BYTES, nullptr) == GUEST_EFAULT); }