feat(libkernel): implement pthread_attr_getinheritsched, pthread_attr_getscope and pthread_attr_setscope
This commit is contained in:
parent
f6203c150b
commit
91bfd6a18c
|
|
@ -1,5 +1,7 @@
|
|||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
#include "../include/Pthread.hpp"
|
||||
|
|
@ -33,6 +35,7 @@ int APS5_VABI pthread_attr_get_np_nid_postfix(Pthread thread, PthreadAttr* attr)
|
|||
p->_schedpriority = thread->priority.load(std::memory_order_relaxed);
|
||||
p->_affinity = thread->affinity.load(std::memory_order_relaxed);
|
||||
p->_affinityExplicit = true;
|
||||
p->_scope = thread->scope;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -48,6 +51,13 @@ int APS5_VABI pthread_attr_getguardsize_nid_postfix(const PthreadAttr* attr, siz
|
|||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI pthread_attr_getinheritsched_nid_postfix(const PthreadAttr* attr, int* inherit_sched) {
|
||||
if (!Valid(attr)) return PosixThread::GUEST_EINVAL;
|
||||
if (!inherit_sched) throw std::runtime_error(std::string(__func__) + ": null output");
|
||||
*inherit_sched = (*attr)->_inheritsched;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI pthread_attr_getschedparam_nid_postfix(const PthreadAttr* attr, KernelSchedParam* param) {
|
||||
if (!Valid(attr) || !param) return PosixThread::GUEST_EINVAL;
|
||||
param->sched_priority = (*attr)->_schedpriority;
|
||||
|
|
@ -60,6 +70,12 @@ int APS5_VABI pthread_attr_getschedpolicy_nid_postfix(const PthreadAttr* attr, i
|
|||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI pthread_attr_getscope_nid_postfix(const PthreadAttr* attr, int* scope) {
|
||||
if (!Valid(attr) || !scope) return PosixThread::GUEST_EINVAL;
|
||||
*scope = (*attr)->_scope;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI pthread_attr_getstack_nid_postfix(const PthreadAttr* __restrict attr, void** __restrict stack_addr, size_t* __restrict stack_size) {
|
||||
if (!Valid(attr) || !stack_addr || !stack_size) return PosixThread::GUEST_EINVAL;
|
||||
*stack_addr = (*attr)->stackAddress;
|
||||
|
|
@ -92,6 +108,7 @@ int APS5_VABI pthread_attr_setguardsize_nid_postfix(PthreadAttr* attr, size_t gu
|
|||
|
||||
int APS5_VABI pthread_attr_setinheritsched_nid_postfix(PthreadAttr* attr, int inherit_sched) {
|
||||
if (!Valid(attr)) return PosixThread::GUEST_EINVAL;
|
||||
if (inherit_sched != GUEST_INHERIT_SCHED && inherit_sched != GUEST_EXPLICIT_SCHED) return PosixThread::GUEST_ENOTSUP;
|
||||
(*attr)->_inheritsched = inherit_sched;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -108,6 +125,12 @@ int APS5_VABI pthread_attr_setschedpolicy_nid_postfix(PthreadAttr* attr, int pol
|
|||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI pthread_attr_setscope_nid_postfix(PthreadAttr* attr, int scope) {
|
||||
if (!Valid(attr) || (scope != GUEST_SCOPE_PROCESS && scope != GUEST_SCOPE_SYSTEM)) return PosixThread::GUEST_EINVAL;
|
||||
(*attr)->_scope = scope;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI pthread_attr_setstacksize_nid_postfix(PthreadAttr* attr, size_t stack_size) {
|
||||
if (!Valid(attr)) return PosixThread::GUEST_EINVAL;
|
||||
return PosixThread::ToErrno(scePthreadAttrSetstacksize(attr, stack_size));
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ namespace PosixThread {
|
|||
constexpr int GUEST_ESRCH = 3;
|
||||
constexpr int GUEST_EFAULT = 14;
|
||||
constexpr int GUEST_EINVAL = 22;
|
||||
constexpr int GUEST_ENOTSUP = 45;
|
||||
constexpr int GUEST_ETIMEDOUT = 60;
|
||||
|
||||
inline int ToErrno(int sceResult) {
|
||||
|
|
|
|||
|
|
@ -83,6 +83,10 @@ static constexpr int DEFAULT_THREAD_PRIORITY = 700;
|
|||
static constexpr std::uint32_t CPU_CLOCK_BIT = 0x80000000u;
|
||||
static constexpr std::uint32_t CPU_CLOCK_PROCESS_BIT = 0x40000000u;
|
||||
static constexpr std::uint32_t CPU_CLOCK_ID_MASK = ~(CPU_CLOCK_BIT | CPU_CLOCK_PROCESS_BIT);
|
||||
static constexpr int GUEST_EXPLICIT_SCHED = 0;
|
||||
static constexpr int GUEST_INHERIT_SCHED = 4;
|
||||
static constexpr int GUEST_SCOPE_PROCESS = 0;
|
||||
static constexpr int GUEST_SCOPE_SYSTEM = 2;
|
||||
|
||||
inline int GuestCpuFromHost(unsigned hostCpu, KernelCpumask threadAffinity) {
|
||||
KernelCpumask mask = threadAffinity & DEFAULT_THREAD_AFFINITY;
|
||||
|
|
@ -102,6 +106,7 @@ struct PthreadAttrPrivate {
|
|||
bool _affinityExplicit = false;
|
||||
std::size_t _guardsize = 0x1000;
|
||||
int _solosched = 0;
|
||||
int _scope = GUEST_SCOPE_SYSTEM;
|
||||
};
|
||||
|
||||
inline std::atomic<std::int64_t> nextThreadId{100000};
|
||||
|
|
@ -123,6 +128,7 @@ struct PthreadPrivate {
|
|||
std::atomic<int> waitCount{0};
|
||||
std::atomic<KernelCpumask> affinity{DEFAULT_THREAD_AFFINITY};
|
||||
std::atomic<int> priority{DEFAULT_THREAD_PRIORITY};
|
||||
int scope = GUEST_SCOPE_SYSTEM;
|
||||
int cpuClockThread = 0;
|
||||
#ifndef _WIN32
|
||||
clockid_t hostCpuClock{};
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ int APS5_VABI scePthreadAttrGet(Pthread thread, PthreadAttr* attr) {
|
|||
(*attr)->_inheritsched = 4;
|
||||
(*attr)->_affinity = thread->affinity.load(std::memory_order_relaxed);
|
||||
(*attr)->_affinityExplicit = true;
|
||||
(*attr)->_scope = thread->scope;
|
||||
return SCE_OK;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -529,6 +529,12 @@ int APS5_VABI scePthreadCreate(Pthread* thread, const PthreadAttr* attr, Pthread
|
|||
p->stackSize = attr ? (*attr)->_stacksize : DEFAULT_STACK_SIZE;
|
||||
if (attr) {
|
||||
p->priority.store((*attr)->_schedpriority, std::memory_order_relaxed);
|
||||
if ((*attr)->_inheritsched != GUEST_INHERIT_SCHED)
|
||||
p->scope = (*attr)->_scope;
|
||||
else if (CurrentGuestState().current)
|
||||
p->scope = CurrentGuestState().current->scope;
|
||||
} else if (CurrentGuestState().current) {
|
||||
p->scope = CurrentGuestState().current->scope;
|
||||
}
|
||||
if (name) p->name = name;
|
||||
std::promise<bool> start;
|
||||
|
|
|
|||
|
|
@ -22,11 +22,19 @@ int APS5_VABI scePthreadAttrGetdetachstate(const PthreadAttr* attr, int* state);
|
|||
int APS5_VABI scePthreadAttrGetsolosched(const PthreadAttr* attr, int* solosched);
|
||||
int APS5_VABI pthread_attr_setstacksize_nid_postfix(PthreadAttr* attr, std::size_t stackSize);
|
||||
int APS5_VABI pthread_attr_setsolosched_np_nid_postfix(PthreadAttr* attr, int solosched);
|
||||
int APS5_VABI pthread_attr_getinheritsched_nid_postfix(const PthreadAttr* attr, int* inherit_sched);
|
||||
int APS5_VABI pthread_attr_setinheritsched_nid_postfix(PthreadAttr* attr, int inherit_sched);
|
||||
int APS5_VABI pthread_attr_getscope_nid_postfix(const PthreadAttr* attr, int* scope);
|
||||
int APS5_VABI pthread_attr_setscope_nid_postfix(PthreadAttr* attr, int scope);
|
||||
int APS5_VABI pthread_attr_get_np_nid_postfix(Pthread thread, PthreadAttr* attr);
|
||||
}
|
||||
|
||||
static constexpr int SCE_OK = 0;
|
||||
static constexpr int SCE_KERNEL_ERROR_EINVAL = static_cast<int>(0x80020016);
|
||||
static constexpr int EXPLICIT_SCHED = 0;
|
||||
static constexpr int INHERIT_SCHED = 4;
|
||||
static constexpr int SCOPE_PROCESS = 0;
|
||||
static constexpr int SCOPE_SYSTEM = 2;
|
||||
static constexpr int DETACH_JOINABLE = 0;
|
||||
static constexpr int CREATION_PRIORITY = 256;
|
||||
static constexpr int UPDATED_PRIORITY = 767;
|
||||
|
|
@ -35,6 +43,7 @@ static constexpr KernelCpumask UPDATED_AFFINITY = 0x1000;
|
|||
static constexpr std::size_t STACK_SIZE = 2u << 20;
|
||||
static constexpr std::size_t MIN_STACK_SIZE = 16384;
|
||||
static constexpr int GUEST_EINVAL = 22;
|
||||
static constexpr int GUEST_ENOTSUP = 45;
|
||||
|
||||
static void Require(bool value) { if (!value) std::abort(); }
|
||||
|
||||
|
|
@ -98,9 +107,107 @@ static void* APS5_VABI Worker(void* arg) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
static void CheckSchedulingAttributes() {
|
||||
int inherit = -1;
|
||||
int scope = -1;
|
||||
Require(pthread_attr_getinheritsched_nid_postfix(nullptr, &inherit) == GUEST_EINVAL);
|
||||
Require(pthread_attr_setinheritsched_nid_postfix(nullptr, EXPLICIT_SCHED) == GUEST_EINVAL);
|
||||
Require(pthread_attr_getscope_nid_postfix(nullptr, &scope) == GUEST_EINVAL);
|
||||
Require(pthread_attr_setscope_nid_postfix(nullptr, SCOPE_SYSTEM) == GUEST_EINVAL);
|
||||
|
||||
PthreadAttr attr = nullptr;
|
||||
Require(pthread_attr_getinheritsched_nid_postfix(&attr, &inherit) == GUEST_EINVAL);
|
||||
Require(pthread_attr_setinheritsched_nid_postfix(&attr, EXPLICIT_SCHED) == GUEST_EINVAL);
|
||||
Require(pthread_attr_getscope_nid_postfix(&attr, &scope) == GUEST_EINVAL);
|
||||
Require(pthread_attr_setscope_nid_postfix(&attr, SCOPE_SYSTEM) == GUEST_EINVAL);
|
||||
|
||||
Require(scePthreadAttrInit(&attr) == SCE_OK);
|
||||
Require(pthread_attr_getinheritsched_nid_postfix(&attr, &inherit) == 0 && inherit == INHERIT_SCHED);
|
||||
Require(pthread_attr_setinheritsched_nid_postfix(&attr, 1) == GUEST_ENOTSUP);
|
||||
Require(pthread_attr_setinheritsched_nid_postfix(&attr, -1) == GUEST_ENOTSUP);
|
||||
Require(pthread_attr_setinheritsched_nid_postfix(&attr, EXPLICIT_SCHED) == 0);
|
||||
Require(pthread_attr_getinheritsched_nid_postfix(&attr, &inherit) == 0 && inherit == EXPLICIT_SCHED);
|
||||
Require(pthread_attr_setinheritsched_nid_postfix(&attr, INHERIT_SCHED) == 0);
|
||||
Require(pthread_attr_getinheritsched_nid_postfix(&attr, &inherit) == 0 && inherit == INHERIT_SCHED);
|
||||
|
||||
Require(pthread_attr_getscope_nid_postfix(&attr, &scope) == 0 && scope == SCOPE_SYSTEM);
|
||||
Require(pthread_attr_setscope_nid_postfix(&attr, 1) == GUEST_EINVAL);
|
||||
Require(pthread_attr_setscope_nid_postfix(&attr, 3) == GUEST_EINVAL);
|
||||
Require(pthread_attr_setscope_nid_postfix(&attr, -1) == GUEST_EINVAL);
|
||||
Require(pthread_attr_setscope_nid_postfix(&attr, SCOPE_PROCESS) == 0);
|
||||
Require(pthread_attr_getscope_nid_postfix(&attr, &scope) == 0 && scope == SCOPE_PROCESS);
|
||||
Require(pthread_attr_setscope_nid_postfix(&attr, SCOPE_SYSTEM) == 0);
|
||||
Require(pthread_attr_getscope_nid_postfix(&attr, &scope) == 0 && scope == SCOPE_SYSTEM);
|
||||
|
||||
Require(pthread_attr_getscope_nid_postfix(&attr, nullptr) == GUEST_EINVAL);
|
||||
|
||||
bool threw = false;
|
||||
try {
|
||||
pthread_attr_getinheritsched_nid_postfix(&attr, nullptr);
|
||||
} catch (const std::exception&) {
|
||||
threw = true;
|
||||
}
|
||||
Require(threw);
|
||||
|
||||
Require(scePthreadAttrDestroy(&attr) == SCE_OK);
|
||||
Require(pthread_attr_getinheritsched_nid_postfix(&attr, &inherit) == GUEST_EINVAL);
|
||||
Require(pthread_attr_setinheritsched_nid_postfix(&attr, EXPLICIT_SCHED) == GUEST_EINVAL);
|
||||
Require(pthread_attr_getscope_nid_postfix(&attr, &scope) == GUEST_EINVAL);
|
||||
Require(pthread_attr_setscope_nid_postfix(&attr, SCOPE_SYSTEM) == GUEST_EINVAL);
|
||||
}
|
||||
|
||||
static void CheckThreadScope() {
|
||||
PthreadAttr attr = nullptr;
|
||||
Require(scePthreadAttrInit(&attr) == SCE_OK);
|
||||
Require(pthread_attr_setinheritsched_nid_postfix(&attr, EXPLICIT_SCHED) == 0);
|
||||
Require(pthread_attr_setscope_nid_postfix(&attr, SCOPE_PROCESS) == 0);
|
||||
|
||||
std::promise<void> release;
|
||||
auto released = release.get_future();
|
||||
Pthread thread = nullptr;
|
||||
Require(scePthreadCreate(&thread, &attr, Worker, &released, nullptr) == SCE_OK);
|
||||
Require(scePthreadAttrDestroy(&attr) == SCE_OK);
|
||||
|
||||
PthreadAttr queryAttr = nullptr;
|
||||
Require(scePthreadAttrInit(&queryAttr) == SCE_OK);
|
||||
Require(scePthreadAttrGet(thread, &queryAttr) == SCE_OK);
|
||||
int scope = -1;
|
||||
Require(pthread_attr_getscope_nid_postfix(&queryAttr, &scope) == 0 && scope == SCOPE_PROCESS);
|
||||
|
||||
Require(pthread_attr_get_np_nid_postfix(thread, &queryAttr) == 0);
|
||||
Require(pthread_attr_getscope_nid_postfix(&queryAttr, &scope) == 0 && scope == SCOPE_PROCESS);
|
||||
Require(scePthreadAttrDestroy(&queryAttr) == SCE_OK);
|
||||
|
||||
release.set_value();
|
||||
Require(scePthreadJoin(thread, nullptr) == SCE_OK);
|
||||
|
||||
Require(scePthreadAttrInit(&attr) == SCE_OK);
|
||||
Require(pthread_attr_setinheritsched_nid_postfix(&attr, INHERIT_SCHED) == 0);
|
||||
Require(pthread_attr_setscope_nid_postfix(&attr, SCOPE_PROCESS) == 0);
|
||||
|
||||
std::promise<void> releaseInherited;
|
||||
auto releasedInherited = releaseInherited.get_future();
|
||||
Pthread inheritedThread = nullptr;
|
||||
Require(scePthreadCreate(&inheritedThread, &attr, Worker, &releasedInherited, nullptr) == SCE_OK);
|
||||
Require(scePthreadAttrDestroy(&attr) == SCE_OK);
|
||||
|
||||
Require(scePthreadAttrInit(&queryAttr) == SCE_OK);
|
||||
Require(scePthreadAttrGet(inheritedThread, &queryAttr) == SCE_OK);
|
||||
scope = -1;
|
||||
Require(pthread_attr_getscope_nid_postfix(&queryAttr, &scope) == 0 && scope == SCOPE_SYSTEM);
|
||||
Require(pthread_attr_get_np_nid_postfix(inheritedThread, &queryAttr) == 0);
|
||||
Require(pthread_attr_getscope_nid_postfix(&queryAttr, &scope) == 0 && scope == SCOPE_SYSTEM);
|
||||
Require(scePthreadAttrDestroy(&queryAttr) == SCE_OK);
|
||||
|
||||
releaseInherited.set_value();
|
||||
Require(scePthreadJoin(inheritedThread, nullptr) == SCE_OK);
|
||||
}
|
||||
|
||||
int main() {
|
||||
CheckStackSizeLimit();
|
||||
CheckSoloSched();
|
||||
CheckSchedulingAttributes();
|
||||
CheckThreadScope();
|
||||
PthreadAttr attr = nullptr;
|
||||
Require(scePthreadAttrInit(&attr) == SCE_OK);
|
||||
Require(scePthreadAttrSetinheritsched(&attr, EXPLICIT_SCHED) == SCE_OK);
|
||||
|
|
|
|||
|
|
@ -386,6 +386,7 @@ Throughout the project, every function at every stage either **does exactly what
|
|||
- [realpath](../../core/libs/prx/libc/src/RealPath.cpp) (libc) follows FreeBSD 11's [`realpath.c`](https://github.com/freebsd/freebsd-src/blob/stable/11/lib/libc/stdlib/realpath.c) except for symlinks. The console's guest filesystem has none, so a host symlink under the guest root is followed for existence and type but not expanded, and `..` drops the previous component lexically, as `Resolve` does for every guest path. Through a host link `linkdir -> sub/deep`, `linkdir/../x` gives `x` beside the link, not beside its target.
|
||||
- [nan and nanf](../../core/libs/prx/libc/src/Math.cpp) (libc) return fixed quiet NaN values (`0x7fc00000` and `0x7ff8000000000000`), ignoring the tag argument as observed in the console's `libc.prx` (both exports load a global constant via `mov rax,[rip+..]; vmovsd xmm0,[rax]; ret`); VLC (PPSA85300) stops on nanf at start-up after strsep.
|
||||
- [Draw input snapshots](../../core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp) (libSceAgcDriver): `PrepareDrawBindings` caps read-only input buffer snapshots at 64 MiB (overridable via `APS5_DRAW_SNAPSHOT_MAX_MIB`). Larger inputs (streaming heaps, bindless pools) or draws exceeding the cumulative budget skip the per-draw snapshot and bind in place, avoiding multi-gigabyte CPU copy stalls (such as Ratchet & Clank: Rift Apart PPSA01474 stalling at frame ~380 copying 36 GB every 5 s). If the title rewrites those large ranges on the CPU before GPU completion, the in-place binding observes the modification, as verified by `drawSnapshotCapTests`.
|
||||
- [pthread_attr_getinheritsched, pthread_attr_setinheritsched, pthread_attr_getscope, pthread_attr_setscope](../../core/libs/prx/libkernel/Pthread/Posix/Attr.cpp) (libkernel) follow FreeBSD 11 libthr ([thr_attr.c](https://github.com/freebsd/freebsd-src/blob/5ed7eb0d97ba4436218e810f61bd059acba984c2/lib/libthr/thread/thr_attr.c), [thr_create.c](https://github.com/freebsd/freebsd-src/blob/5ed7eb0d97ba4436218e810f61bd059acba984c2/lib/libthr/thread/thr_create.c)), not measured on the console: the scope defaults to `PTHREAD_SCOPE_SYSTEM` (2), only it and `PTHREAD_SCOPE_PROCESS` (0) are accepted and other values return `EINVAL`, and an inherit value other than `PTHREAD_INHERIT_SCHED` (4) or `PTHREAD_EXPLICIT_SCHED` (0) returns `ENOTSUP`. A null output of `pthread_attr_getinheritsched` throws, since libthr writes through it unchecked. A thread keeps the scope it was created with, taken from the creating thread under `PTHREAD_INHERIT_SCHED`, and `pthread_attr_get_np` and `scePthreadAttrGet` report it, but every guest thread is a host thread at system scope, so process scope changes nothing
|
||||
- [SPIRV-Tools optimization](../../core/shader/recompiler/SpirvBackend/src/SpirvOptimizer.cpp) skips CCP and Simplification for modules with storage-only 8- or 16-bit types because the pinned folder produces illegal narrow constants. This also disables unrelated constant folding; the restricted full pipeline mirrors the pinned performance recipe.
|
||||
- [SRT signed comparison](../../core/shader/recompiler/Optimization/src/SrtWalker/SrtEvaluator.cpp) evaluates `SLessThan32` as signed 32-bit less-than, matching the existing SPIR-V backend and [SPIR-V `OpSLessThan`](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpSLessThan). Signed boundary descriptor expressions are tested on the host; native RDNA2/PS5 execution and title behavior remain unverified.
|
||||
- On macOS the [write watch](../../core/libs/prx/libc/src/GuestWriteWatch.cpp) write-protects watched pages and records the first write to each from a SIGBUS/SIGSEGV handler, because macOS has no counterpart to `userfaultfd` write-protect or `MEM_WRITE_WATCH`. The protection is real, so:
|
||||
|
|
|
|||
Loading…
Reference in New Issue