feat(libkernel): add missing pthread attribute accessors

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01QnkpF2oEMofseVz9Z7WEAC
This commit is contained in:
SebastianandClaude Opus 5.5 committed 2026-10-23 06:27:49 +00:00
1 parent fc9d8308a1
commit bb403de88f
10 files changed
+245 -11

No files matched your search

@@ -20,6 +20,10 @@ inline int ToErrno(int sceResult) {
return sceResult == 0 ? 0 : static_cast<int>(static_cast<std::uint32_t>(sceResult) & 0xFFFFu);
}
inline int ToSce(int error) {
return error == 0 ? 0 : static_cast<int>(0x80020000u | static_cast<std::uint32_t>(error));
}
// Converts an absolute deadline on the guest clock into a relative wait, clamped to what the sce layer accepts.
inline bool RelativeMicroseconds(int clockId, const KernelTimespec* abstime, KernelUseconds* usec) {
if (!abstime || abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) return false;
@@ -80,4 +80,16 @@ int APS5_VABI pthread_condattr_getpshared_nid_postfix(const PthreadCondattr* att
return 0;
}
int APS5_VABI pthread_cond_signalto_np_nid_postfix(PthreadCond* cond, Pthread thread) {
return toPosix(scePthreadCondSignalto(cond, thread));
}
int APS5_VABI scePthreadCondattrSetpshared(PthreadCondattr* attr, int pshared) {
return PosixThread::ToSce(pthread_condattr_setpshared_nid_postfix(attr, pshared));
}
int APS5_VABI scePthreadCondattrGetpshared(const PthreadCondattr* attr, int* pshared) {
return PosixThread::ToSce(pthread_condattr_getpshared_nid_postfix(attr, pshared));
}
}
@@ -39,6 +39,7 @@ void _initializeStatic(PthreadMutex* mutex, const char* funcName) {
extern "C" {
int APS5_VABI sched_get_priority_max_nid_postfix(int policy);
int* APS5_VABI __error_nid_postfix();
int APS5_VABI pthread_mutex_destroy_nid_postfix(PthreadMutex* mutex) {
if (!mutex) throw std::runtime_error("pthread_mutex_destroy: null mutex");
@@ -169,4 +170,51 @@ int APS5_VABI pthread_mutexattr_gettype_nid_postfix(const PthreadMutexattr* attr
return 0;
}
int APS5_VABI pthread_mutexattr_setkind_np_nid_postfix(PthreadMutexattr* attr, int kind) {
if (!attr || !*attr) {
*__error_nid_postfix() = POSIX_EINVAL;
return -1;
}
if (kind < static_cast<int>(MutexType::ErrorCheck) || kind > static_cast<int>(MutexType::Adaptive))
throw std::runtime_error("pthread_mutexattr_setkind_np: kind " + std::to_string(kind) + " is not a mutex type, and pthread_mutex_init does not reject it with EINVAL");
(*attr)->type = static_cast<MutexType>(kind);
return 0;
}
int APS5_VABI pthread_mutexattr_getkind_np_nid_postfix(PthreadMutexattr attr) {
if (!attr) {
*__error_nid_postfix() = POSIX_EINVAL;
return -1;
}
return static_cast<int>(attr->type);
}
int APS5_VABI scePthreadMutexattrGettype(const PthreadMutexattr* attr, int* type) {
return PosixThread::ToSce(pthread_mutexattr_gettype_nid_postfix(attr, type));
}
int APS5_VABI scePthreadMutexattrSetprotocol(PthreadMutexattr* attr, int protocol) {
return PosixThread::ToSce(pthread_mutexattr_setprotocol_nid_postfix(attr, protocol));
}
int APS5_VABI scePthreadMutexattrGetprotocol(const PthreadMutexattr* attr, int* protocol) {
return PosixThread::ToSce(pthread_mutexattr_getprotocol_nid_postfix(attr, protocol));
}
int APS5_VABI scePthreadMutexattrSetprioceiling(PthreadMutexattr* attr, int prioceiling) {
return PosixThread::ToSce(pthread_mutexattr_setprioceiling_nid_postfix(attr, prioceiling));
}
int APS5_VABI scePthreadMutexattrGetprioceiling(const PthreadMutexattr* attr, int* prioceiling) {
return PosixThread::ToSce(pthread_mutexattr_getprioceiling_nid_postfix(attr, prioceiling));
}
int APS5_VABI scePthreadMutexattrSetpshared(PthreadMutexattr* attr, int pshared) {
return PosixThread::ToSce(pthread_mutexattr_setpshared_nid_postfix(attr, pshared));
}
int APS5_VABI scePthreadMutexattrGetpshared(const PthreadMutexattr* attr, int* pshared) {
return PosixThread::ToSce(pthread_mutexattr_getpshared_nid_postfix(attr, pshared));
}
}
@@ -70,6 +70,25 @@ int APS5_VABI pthread_rwlockattr_setpshared_nid_postfix(PthreadRwlockattr* attr,
return 0;
}
int APS5_VABI pthread_rwlockattr_gettype_np_nid_postfix(const PthreadRwlockattr* attr, int* type) {
if (!attr || !*attr) throw std::runtime_error("pthread_rwlockattr_gettype_np: null attr");
if (!type) throw std::runtime_error("pthread_rwlockattr_gettype_np: null type");
*type = (*attr)->type;
return 0;
}
int APS5_VABI scePthreadRwlockattrGettype(const PthreadRwlockattr* attr, int* type) {
return PosixThread::ToSce(pthread_rwlockattr_gettype_np_nid_postfix(attr, type));
}
int APS5_VABI scePthreadRwlockattrSetpshared(PthreadRwlockattr* attr, int pshared) {
return PosixThread::ToSce(pthread_rwlockattr_setpshared_nid_postfix(attr, pshared));
}
int APS5_VABI scePthreadRwlockattrGetpshared(const PthreadRwlockattr* attr, int* pshared) {
return PosixThread::ToSce(pthread_rwlockattr_getpshared_nid_postfix(attr, pshared));
}
int APS5_VABI pthread_rwlock_rdlock_nid_postfix(PthreadRwlock* rwlock) {
initializeStatic(rwlock, __func__);
return toPosix(scePthreadRwlockRdlock(rwlock));
@@ -149,16 +149,6 @@ int APS5_VABI scePthreadMutexattrSettype(PthreadMutexattr* attr, int type) {
return 0;
}
int APS5_VABI scePthreadMutexattrSetprotocol(PthreadMutexattr* attr, int protocol) {
if (!attr || !*attr)
return SCE_KERNEL_ERROR_EINVAL;
constexpr int PrioNone = 0;
constexpr int PrioProtect = 2;
if (protocol < PrioNone || protocol > PrioProtect)
return SCE_KERNEL_ERROR_EINVAL;
return 0;
}
int APS5_VABI scePthreadMutexInit(PthreadMutex* mutex, const PthreadMutexattr* attr, const char*) {
if (!mutex)
throw std::invalid_argument("Mutex pointer is null");
+33
View File
@@ -20,6 +20,8 @@ int APS5_VABI pthread_cond_init_nid_postfix(PthreadCond* cond, const PthreadCond
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_cond_reltimedwait_np_nid_postfix(PthreadCond* cond, PthreadMutex* mutex, unsigned int usec);
int APS5_VABI pthread_cond_signalto_np_nid_postfix(PthreadCond* cond, Pthread thread);
Pthread APS5_VABI scePthreadSelf();
int APS5_VABI __cxa_atexit_nid_postfix(void (APS5_VABI *)(void*), void*, void*);
void APS5_VABI __pthread_cxa_finalize_nid_postfix(void*);
unsigned int APS5_VABI sceKernelSleep(unsigned int seconds);
@@ -55,6 +57,7 @@ struct Signalled {
PthreadCond cond = nullptr;
bool ready = false;
int trylock = SCE_OK;
Pthread target = nullptr;
};
static void* APS5_VABI Trylocker(void* arg) {
@@ -72,6 +75,15 @@ static void* APS5_VABI Signaller(void* arg) {
return nullptr;
}
static void* APS5_VABI SignallerTo(void* arg) {
auto& signalled = *static_cast<Signalled*>(arg);
Require(scePthreadMutexLock(&signalled.mutex) == SCE_OK);
signalled.ready = true;
Require(pthread_cond_signalto_np_nid_postfix(&signalled.cond, signalled.target) == 0);
Require(scePthreadMutexUnlock(&signalled.mutex) == SCE_OK);
return nullptr;
}
static void RequireHeldByCaller(Signalled& signalled) {
Pthread thread = nullptr;
Require(scePthreadCreate(&thread, nullptr, Trylocker, &signalled, nullptr) == SCE_OK);
@@ -108,8 +120,29 @@ static void RelativeWait() {
Require(scePthreadMutexDestroy(&signalled.mutex) == SCE_OK);
}
static void SignalTo() {
Signalled signalled;
signalled.target = scePthreadSelf();
Require(scePthreadMutexInit(&signalled.mutex, nullptr, nullptr) == SCE_OK);
Require(scePthreadCondInit(&signalled.cond, nullptr, nullptr) == SCE_OK);
Require(pthread_cond_signalto_np_nid_postfix(&signalled.cond, signalled.target) == 0);
Require(scePthreadMutexLock(&signalled.mutex) == SCE_OK);
Pthread thread = nullptr;
Require(scePthreadCreate(&thread, nullptr, SignallerTo, &signalled, nullptr) == SCE_OK);
const auto waitStart = std::chrono::steady_clock::now();
while (!signalled.ready)
Require(pthread_cond_reltimedwait_np_nid_postfix(&signalled.cond, &signalled.mutex, 10000000) == 0);
Require(std::chrono::steady_clock::now() - waitStart < std::chrono::seconds(5));
Require(scePthreadMutexUnlock(&signalled.mutex) == SCE_OK);
Require(scePthreadJoin(thread, nullptr) == SCE_OK);
Require(scePthreadCondDestroy(&signalled.cond) == SCE_OK);
Require(pthread_cond_signalto_np_nid_postfix(&signalled.cond, signalled.target) == 22);
Require(scePthreadMutexDestroy(&signalled.mutex) == SCE_OK);
}
int main() {
RelativeWait();
SignalTo();
Context context;
PthreadCond cond = nullptr;
+7
View File
@@ -10,6 +10,8 @@ int APS5_VABI scePthreadCondattrSetclock(PthreadCondattr* attr, KernelClockid cl
int APS5_VABI pthread_condattr_setclock_nid_postfix(PthreadCondattr* attr, KernelClockid clockId);
int APS5_VABI pthread_condattr_setpshared_nid_postfix(PthreadCondattr* attr, int pshared);
int APS5_VABI pthread_condattr_getpshared_nid_postfix(const PthreadCondattr* attr, int* pshared);
int APS5_VABI scePthreadCondattrSetpshared(PthreadCondattr* attr, int pshared);
int APS5_VABI scePthreadCondattrGetpshared(const PthreadCondattr* attr, int* pshared);
}
static constexpr int SCE_OK = 0;
@@ -31,6 +33,8 @@ int main() {
Require(pthread_condattr_setpshared_nid_postfix(&unset, 0) == GuestEinval);
Require(pthread_condattr_getpshared_nid_postfix(nullptr, &sharing) == GuestEinval && sharing == -1);
Require(pthread_condattr_getpshared_nid_postfix(&unset, &sharing) == GuestEinval && sharing == -1);
Require(scePthreadCondattrSetpshared(&unset, 0) == SceEinval);
Require(scePthreadCondattrGetpshared(nullptr, &sharing) == SceEinval && sharing == -1);
PthreadCondattr attr = nullptr;
Require(scePthreadCondattrInit(&attr) == SCE_OK);
@@ -38,6 +42,9 @@ int main() {
Require(scePthreadCondattrSetclock(&attr, clock) == SCE_OK);
Require(pthread_condattr_setclock_nid_postfix(&attr, clock) == 0);
}
Require(scePthreadCondattrSetpshared(&attr, 1) == SceEinval);
Require(scePthreadCondattrSetpshared(&attr, 0) == SCE_OK);
Require(scePthreadCondattrGetpshared(&attr, &sharing) == SCE_OK && sharing == 0);
Require(pthread_condattr_getpshared_nid_postfix(&attr, &sharing) == 0 && sharing == 0);
for (const int invalid : {1, 2, -1}) {
Require(pthread_condattr_setpshared_nid_postfix(&attr, invalid) == GuestEinval);
+89
View File
@@ -15,6 +15,19 @@ int APS5_VABI pthread_mutexattr_setprioceiling_nid_postfix(PthreadMutexattr* att
int APS5_VABI pthread_mutexattr_getprioceiling_nid_postfix(const PthreadMutexattr* attr, int* prioceiling);
int APS5_VABI pthread_mutexattr_settype_nid_postfix(PthreadMutexattr* attr, int type);
int APS5_VABI pthread_mutexattr_gettype_nid_postfix(const PthreadMutexattr* attr, int* type);
int APS5_VABI pthread_mutexattr_setkind_np_nid_postfix(PthreadMutexattr* attr, int kind);
int APS5_VABI pthread_mutexattr_getkind_np_nid_postfix(PthreadMutexattr attr);
int APS5_VABI scePthreadMutexattrInit(PthreadMutexattr* attr);
int APS5_VABI scePthreadMutexattrDestroy(PthreadMutexattr* attr);
int APS5_VABI scePthreadMutexattrSettype(PthreadMutexattr* attr, int type);
int APS5_VABI scePthreadMutexattrGettype(const PthreadMutexattr* attr, int* type);
int APS5_VABI scePthreadMutexattrSetprotocol(PthreadMutexattr* attr, int protocol);
int APS5_VABI scePthreadMutexattrGetprotocol(const PthreadMutexattr* attr, int* protocol);
int APS5_VABI scePthreadMutexattrSetprioceiling(PthreadMutexattr* attr, int prioceiling);
int APS5_VABI scePthreadMutexattrGetprioceiling(const PthreadMutexattr* attr, int* prioceiling);
int APS5_VABI scePthreadMutexattrSetpshared(PthreadMutexattr* attr, int pshared);
int APS5_VABI scePthreadMutexattrGetpshared(const PthreadMutexattr* attr, int* pshared);
int* APS5_VABI __error_nid_postfix();
int APS5_VABI pthread_mutex_init_nid_postfix(PthreadMutex* mutex, const PthreadMutexattr* attr);
int APS5_VABI pthread_mutex_lock_nid_postfix(PthreadMutex* mutex);
int APS5_VABI pthread_mutex_unlock_nid_postfix(PthreadMutex* mutex);
@@ -26,6 +39,8 @@ int APS5_VABI sched_get_priority_max_nid_postfix(int policy);
}
static constexpr int GUEST_EINVAL = 22;
static constexpr int SCE_OK = 0;
static constexpr int SCE_KERNEL_ERROR_EINVAL = static_cast<int>(0x80020016u);
static constexpr int PRIO_NONE = 0;
static constexpr int PRIO_INHERIT = 1;
static constexpr int PRIO_PROTECT = 2;
@@ -80,6 +95,78 @@ static void CheckType() {
Require(pthread_mutexattr_gettype_nid_postfix(nullptr, &type) == GUEST_EINVAL && type == -1);
}
static void CheckKind() {
PthreadMutexattr attr = nullptr;
*__error_nid_postfix() = 0;
Require(pthread_mutexattr_getkind_np_nid_postfix(nullptr) == -1 && *__error_nid_postfix() == GUEST_EINVAL);
*__error_nid_postfix() = 0;
Require(pthread_mutexattr_setkind_np_nid_postfix(nullptr, 2) == -1 && *__error_nid_postfix() == GUEST_EINVAL);
*__error_nid_postfix() = 0;
Require(pthread_mutexattr_setkind_np_nid_postfix(&attr, 2) == -1 && *__error_nid_postfix() == GUEST_EINVAL);
Require(pthread_mutexattr_init_nid_postfix(&attr) == 0);
Require(pthread_mutexattr_getkind_np_nid_postfix(attr) == 1);
int type = -1;
for (const int kind : {2, 3, 4, 1}) {
Require(pthread_mutexattr_setkind_np_nid_postfix(&attr, kind) == 0);
Require(pthread_mutexattr_getkind_np_nid_postfix(attr) == kind);
Require(pthread_mutexattr_gettype_nid_postfix(&attr, &type) == 0 && type == kind);
}
Require(pthread_mutexattr_settype_nid_postfix(&attr, 2) == 0);
Require(pthread_mutexattr_getkind_np_nid_postfix(attr) == 2);
for (const int invalid : {0, 5, -1})
Require(Throws([&] { pthread_mutexattr_setkind_np_nid_postfix(&attr, invalid); }));
Require(pthread_mutexattr_getkind_np_nid_postfix(attr) == 2);
PthreadMutex mutex = nullptr;
Require(pthread_mutex_init_nid_postfix(&mutex, &attr) == 0);
Require(pthread_mutex_lock_nid_postfix(&mutex) == 0);
Require(pthread_mutex_lock_nid_postfix(&mutex) == 0);
Require(pthread_mutex_unlock_nid_postfix(&mutex) == 0);
Require(pthread_mutex_unlock_nid_postfix(&mutex) == 0);
Require(pthread_mutex_destroy_nid_postfix(&mutex) == 0);
Require(pthread_mutexattr_destroy_nid_postfix(&attr) == 0);
*__error_nid_postfix() = 0;
Require(pthread_mutexattr_setkind_np_nid_postfix(&attr, 2) == -1 && *__error_nid_postfix() == GUEST_EINVAL);
}
static void CheckSceAccessors() {
PthreadMutexattr attr = nullptr;
int value = -1;
Require(scePthreadMutexattrGettype(nullptr, &value) == SCE_KERNEL_ERROR_EINVAL);
Require(scePthreadMutexattrGettype(&attr, &value) == SCE_KERNEL_ERROR_EINVAL);
Require(scePthreadMutexattrSetprotocol(&attr, PRIO_NONE) == SCE_KERNEL_ERROR_EINVAL);
Require(scePthreadMutexattrGetprotocol(&attr, &value) == SCE_KERNEL_ERROR_EINVAL);
Require(scePthreadMutexattrSetprioceiling(&attr, 300) == SCE_KERNEL_ERROR_EINVAL);
Require(scePthreadMutexattrGetprioceiling(&attr, &value) == SCE_KERNEL_ERROR_EINVAL);
Require(scePthreadMutexattrSetpshared(nullptr, 0) == SCE_KERNEL_ERROR_EINVAL);
Require(scePthreadMutexattrGetpshared(&attr, &value) == SCE_KERNEL_ERROR_EINVAL);
Require(value == -1);
Require(scePthreadMutexattrInit(&attr) == SCE_OK);
Require(scePthreadMutexattrGettype(&attr, &value) == SCE_OK && value == 1);
Require(scePthreadMutexattrSettype(&attr, 3) == SCE_OK);
Require(scePthreadMutexattrGettype(&attr, &value) == SCE_OK && value == 3);
Require(Throws([&] { scePthreadMutexattrGettype(&attr, nullptr); }));
Require(scePthreadMutexattrGetprotocol(&attr, &value) == SCE_OK && value == PRIO_NONE);
for (const int invalid : {-1, 3})
Require(scePthreadMutexattrSetprotocol(&attr, invalid) == SCE_KERNEL_ERROR_EINVAL);
Require(scePthreadMutexattrGetprotocol(&attr, &value) == SCE_OK && value == PRIO_NONE);
Require(scePthreadMutexattrSetprotocol(&attr, PRIO_INHERIT) == SCE_OK);
Require(scePthreadMutexattrGetprotocol(&attr, &value) == SCE_OK && value == PRIO_INHERIT);
Require(scePthreadMutexattrSetprioceiling(&attr, 300) == SCE_KERNEL_ERROR_EINVAL);
Require(scePthreadMutexattrGetprioceiling(&attr, &value) == SCE_KERNEL_ERROR_EINVAL);
Require(scePthreadMutexattrSetprotocol(&attr, PRIO_PROTECT) == SCE_OK);
Require(scePthreadMutexattrGetprioceiling(&attr, &value) == SCE_OK && value == sched_get_priority_max_nid_postfix(SCHED_RR));
Require(scePthreadMutexattrSetprioceiling(&attr, 300) == SCE_OK);
Require(scePthreadMutexattrGetprioceiling(&attr, &value) == SCE_OK && value == 300);
int protocol = -1;
Require(pthread_mutexattr_getprotocol_nid_postfix(&attr, &protocol) == 0 && protocol == PRIO_PROTECT);
Require(scePthreadMutexattrGetpshared(&attr, &value) == SCE_OK && value == 0);
Require(scePthreadMutexattrSetpshared(&attr, 1) == SCE_KERNEL_ERROR_EINVAL);
Require(scePthreadMutexattrSetpshared(&attr, 0) == SCE_OK);
Require(scePthreadMutexattrGetpshared(&attr, &value) == SCE_OK && value == 0);
Require(scePthreadMutexattrDestroy(&attr) == SCE_OK);
Require(scePthreadMutexattrGettype(&attr, &value) == SCE_KERNEL_ERROR_EINVAL);
}
static void CheckProcessSharing() {
PthreadMutexattr attr = nullptr;
int sharing = -1;
@@ -127,6 +214,8 @@ static void CheckInvalidPriorityAttribute(PthreadMutexattr* attr) {
int main() {
CheckType();
CheckKind();
CheckSceAccessors();
CheckProcessSharing();
CheckTimedlockInvalidDeadline();
PthreadMutexattr attr = nullptr;
+29
View File
@@ -16,6 +16,11 @@ int APS5_VABI pthread_rwlockattr_init_nid_postfix(PthreadRwlockattr* attr);
int APS5_VABI pthread_rwlockattr_destroy_nid_postfix(PthreadRwlockattr* attr);
int APS5_VABI pthread_rwlockattr_getpshared_nid_postfix(const PthreadRwlockattr* attr, int* pshared);
int APS5_VABI pthread_rwlockattr_setpshared_nid_postfix(PthreadRwlockattr* attr, int pshared);
int APS5_VABI pthread_rwlockattr_gettype_np_nid_postfix(const PthreadRwlockattr* attr, int* type);
int APS5_VABI scePthreadRwlockattrSettype(PthreadRwlockattr* attr, int type);
int APS5_VABI scePthreadRwlockattrGettype(const PthreadRwlockattr* attr, int* type);
int APS5_VABI scePthreadRwlockattrSetpshared(PthreadRwlockattr* attr, int pshared);
int APS5_VABI scePthreadRwlockattrGetpshared(const PthreadRwlockattr* attr, int* pshared);
int APS5_VABI pthread_rwlock_rdlock_nid_postfix(PthreadRwlock* rwlock);
int APS5_VABI pthread_rwlock_wrlock_nid_postfix(PthreadRwlock* rwlock);
int APS5_VABI pthread_rwlock_unlock_nid_postfix(PthreadRwlock* rwlock);
@@ -397,8 +402,32 @@ static void CheckAttrProcessSharing() {
Require(pthread_rwlockattr_destroy_nid_postfix(&attr) == 0);
}
static void CheckAttrType() {
PthreadRwlockattr attr = nullptr;
Require(pthread_rwlockattr_init_nid_postfix(&attr) == 0);
int type = -1;
Require(pthread_rwlockattr_gettype_np_nid_postfix(&attr, &type) == 0 && type == 0);
Require(scePthreadRwlockattrGettype(&attr, &type) == SCE_OK && type == 0);
for (const int set : {1, 2, 0}) {
Require(scePthreadRwlockattrSettype(&attr, set) == SCE_OK);
Require(pthread_rwlockattr_gettype_np_nid_postfix(&attr, &type) == 0 && type == set);
Require(scePthreadRwlockattrGettype(&attr, &type) == SCE_OK && type == set);
}
Require(Throws([&] { pthread_rwlockattr_gettype_np_nid_postfix(&attr, nullptr); }));
int pshared = -1;
Require(scePthreadRwlockattrGetpshared(&attr, &pshared) == SCE_OK && pshared == PROCESS_PRIVATE);
Require(scePthreadRwlockattrSetpshared(&attr, 1) == SCE_KERNEL_ERROR_EINVAL);
Require(scePthreadRwlockattrSetpshared(&attr, PROCESS_PRIVATE) == SCE_OK);
Require(pthread_rwlockattr_destroy_nid_postfix(&attr) == 0);
PthreadRwlockattr unset = nullptr;
Require(Throws([&] { pthread_rwlockattr_gettype_np_nid_postfix(nullptr, &type); }));
Require(Throws([&] { pthread_rwlockattr_gettype_np_nid_postfix(&unset, &type); }));
Require(Throws([&] { scePthreadRwlockattrGettype(&unset, &type); }));
}
int main() {
CheckAttrProcessSharing();
CheckAttrType();
CheckWaitingWriterHoldsBackNewReaders();
CheckConcurrentFirstWrlockExcludes();
CheckDeadlinesBeyondTheClockRange();
+4 -1
View File
@@ -3,7 +3,7 @@
### Silent stubs
- [sceKernelGetSocPowerConsumption](../../../core/libs/prx/libkernel/System/src/ThermalSensors.cpp) (libkernel) - returns `EINVAL` and writes nothing, as `sceKernelGetSocSensorTemperature` does when the host has no sensor: the host's package power is not read (Linux RAPL `energy_uj` is readable by root only, and Windows has no general source). The prototype is not documented. PS5LM Plus (PPSA99581) passes a zeroed 128-byte buffer and, on success, reads its first 32-bit word as milliwatts, accepting 1000 to 350000; on failure it shows 0 W
- [scePthreadMutexattrSetprotocol](../../../core/libs/prx/libkernel/Pthread/src/Mutex.cpp) (libkernel) - accepts 0 to 2 as a PS5 (firmware 13.60) does and returns `EINVAL` otherwise, but the protocol is not stored or applied: priority inheritance and protection are not modelled. On the console a null or uninitialized mutex attribute returns `EINVAL` from the SCE attribute calls, `scePthreadMutexInit` takes an uninitialized attribute as the default one, and a destroyed mutex returns `EINVAL` from `scePthreadMutexDestroy`; a null mutex pointer crashed the payload and still throws
- [scePthreadMutexattrSetprotocol, scePthreadMutexattrGetprotocol, scePthreadMutexattrSetprioceiling, scePthreadMutexattrGetprioceiling](../../../core/libs/prx/libkernel/Pthread/Posix/Mutex.cpp) (libkernel) - `scePthreadMutexattrSetprotocol` accepts 0 to 2 as a PS5 (firmware 13.60) does and returns `EINVAL` otherwise, but the protocol is not applied: priority inheritance and protection are not modelled. On the console a null or uninitialized mutex attribute returns `EINVAL` from the SCE attribute calls, `scePthreadMutexInit` takes an uninitialized attribute as the default one, and a destroyed mutex returns `EINVAL` from `scePthreadMutexDestroy`; a null mutex pointer crashed the payload and still throws
- [pthread_mutexattr_setprotocol, pthread_mutexattr_getprotocol, pthread_mutexattr_setprioceiling, pthread_mutexattr_getprioceiling](../../../core/libs/prx/libkernel/Pthread/Posix/Mutex.cpp) (libkernel) - the protocol and the priority ceiling are stored and reported as in [FreeBSD 11 libthr](https://github.com/freebsd/freebsd-src/blob/releng/11.0/lib/libthr/thread/thr_mutexattr.c#L192-L245) (the ceiling is set or read only under `PTHREAD_PRIO_PROTECT`, and setting a protocol resets it to the highest `SCHED_RR` priority). A null, uninitialized or destroyed attribute returns `EINVAL` before the other arguments are checked; this error behavior is unverified on the console. Mutexes do not apply the protocol or ceiling: a priority-inherit or priority-protect mutex locks like a normal one and does not change its owner's priority
- [sceCoredumpSetUserDataType](../../../core/libs/prx/libkernel/System/src/Coredump.cpp) (libkernel, NID `Uxqkdta7wEg`) - `(int type)` follows the PS5 12.00 `libkernel.sprx` at 0x138B0: the sign-extended `type` goes to syscall 601 (command 29, third argument 0), and the raw result comes back with no SCE code mapping, so a kernel error is -1 with `errno` set. Which types the kernel accepts is not measured. No dump is produced here, so every type returns 0. Palworld (PPSA23126, #2598) and Hello Neighbor (PPSA35154, discussion #6991) import it; #4144 left it throwing because no signature was known
- [sceKernelGetMainSocId and sceKernelGetCpumode](../../../core/libs/prx/libkernel/System/src/Process.cpp) (libkernel) both return 0, and [sceKernelGetCpuFrequency](../../../core/libs/prx/libkernel/Time/Time.cpp) returns the host TSC frequency measured for `sceKernelGetTscFrequency`, not the console CPU clock. The PS5's SoC id and CPU mode are unknown; shadPS4's PS4 values are [0x710f10/0x740f30 and 0, 2 or 5 from the param.sfo CPU-mode flags](https://github.com/shadps4-emu/shadPS4/blob/e0a466753a1a/src/core/libraries/kernel/process.cpp). PPSA99203 only logs them (`[console] main SoC id: result=%#x out=%#x`, `CPU: %llu Hz, cpumode %d`), passing a pointer that `sceKernelGetMainSocId` leaves untouched
@@ -234,6 +234,9 @@
- [pthread_spin_lock](../../../core/libs/prx/libkernel/Pthread/Posix/Spinlock.cpp) (libkernel) - a lock taken again by the thread that holds it throws here. On a PS5 (firmware 12.70) that call had not returned after 2 s, as FreeBSD 11.4 libthr [`thr_pspinlock.c`](https://github.com/freebsd/freebsd-src/blob/8c639945a44588f6cfdddfb057bb5aad88735da0/lib/libthr/thread/thr_pspinlock.c) spins forever
- [pthread_mutex_getspinloops_np, pthread_mutex_setspinloops_np, pthread_mutex_getyieldloops_np, pthread_mutex_setyieldloops_np and their scePthreadMutex counterparts](../../../core/libs/prx/libkernel/Pthread/src/Mutex.cpp) (libkernel) store and report the counts, but host mutexes do not spin or yield by them. The defaults follow FreeBSD 11.4's [`mutex_init_body`](https://github.com/freebsd/freebsd-src/blob/8c639945a44588f6cfdddfb057bb5aad88735da0/lib/libthr/thread/thr_mutex.c#L236-L272) without `LIBPTHREAD_SPINLOOPS` and `LIBPTHREAD_YIELDLOOPS`: 2000 spins for an adaptive mutex, 0 otherwise; the console's defaults are unverified. Setting the yield count of a destroyed mutex returns 0 as FreeBSD's [`__pthread_mutex_setyieldloops_np`](https://github.com/freebsd/freebsd-src/blob/8c639945a44588f6cfdddfb057bb5aad88735da0/lib/libthr/thread/thr_mutex.c#L1125-L1135) does; the console's result is unverified
- [pthread_rwlockattr_getpshared, pthread_rwlockattr_setpshared](../../../core/libs/prx/libkernel/Pthread/Posix/Rwlock.cpp) (libkernel) - `pthread_rwlockattr_destroy` clears the attribute here, so a later get, or a set of 0, throws. On a PS5 (firmware 12.70) destroy leaves the attribute set; a get afterwards returned 0 with a stale value and a set of 0 returned 0
- [pthread_mutexattr_setkind_np](../../../core/libs/prx/libkernel/Pthread/Posix/Mutex.cpp) (libkernel) throws for a kind outside 1 to 4. FreeBSD 11.4's [`_pthread_mutexattr_setkind_np`](https://github.com/freebsd/freebsd-src/blob/8c639945a44588f6cfdddfb057bb5aad88735da0/lib/libthr/thread/thr_mutexattr.c#L108-L120) stores any kind and [`mutex_check_attr`](https://github.com/freebsd/freebsd-src/blob/8c639945a44588f6cfdddfb057bb5aad88735da0/lib/libthr/thread/thr_mutex.c#L207-L218) then makes `pthread_mutex_init` fail with `EINVAL`, but `pthread_mutex_init` here does not check the type
- [pthread_cond_signalto_np, scePthreadCondSignalto](../../../core/libs/prx/libkernel/Pthread/src/Cond.cpp) (libkernel) wake every waiter of the condition variable, not only the given thread, and do not check the thread; the other waiters see a spurious wakeup. Which waiters the console wakes, and its result for a thread that is not waiting, are unverified
- [pthread_rwlockattr_gettype_np, scePthreadRwlockattrGettype](../../../core/libs/prx/libkernel/Pthread/Posix/Rwlock.cpp) (libkernel) report the type stored by `scePthreadRwlockattrSettype`, which accepts any value and which read-write locks do not apply; the console's valid types and their effect are unverified. A null or uninitialized attribute throws, as for `pthread_rwlockattr_getpshared`
- [sceKernelGetEventError](../../../core/libs/prx/libkernel/Equeue/src/EventAccessors.cpp) (libkernel) throws for `fflags` above 0xFFFF, where OR and addition of 0x80020000 differ and the console was not measured. Otherwise it returns 0 for `fflags` 0 and `0x80020000 | fflags`, whatever `flags` and `data` hold, as [fpPS4](https://github.com/red-prig/fpPS4/blob/04cefd43e6fddd1ab033e7980cd356d14c964905/kernel/ps4_queue.pas#L643) does and a PS5 (firmware 13.40, measured 2026-10-19 in a payload process) answered: `{flags 0x4000, fflags 0, data 22}`, `{0x4000, 0, -1}`, `{0x4000, 0, 0x80020016}` and `{0, 0, 0}` gave 0, `{0x4000, 5, 0}` and `{0x4000, 5, 22}` 0x80020005, `{0, 7, 22}` 0x80020007, `{0x8000, 3, 9}` 0x80020003. Video-out events carry their count in `fflags`, so they get 0x80020001 and up; only events built by the caller were measured. Closes when: `fflags` above 0xFFFF is measured
- [pthread_cond_reltimedwait_np](../../../core/libs/prx/libkernel/Pthread/Posix/Cond.cpp) (libkernel) takes `(cond, mutex, usec)`, a relative timeout in microseconds, and is `scePthreadCondTimedwait` with POSIX error numbers. FreeBSD 11.4 has no such function; the signature comes only from shadPS4, which registers one function for this NID and for `scePthreadCondTimedwait` ([`condvar.cpp`](https://github.com/shadps4-emu/shadPS4/blob/3a9f57265d28975658f1ca941daa5c879c7a74bd/src/core/libraries/kernel/threads/condvar.cpp#L229-L234)). shadPS4 reads a 64-bit count; here it is the 32-bit `SceKernelUseconds` of the SCE twin, as for `sem_reltimedwait_np`. Unverified on the console
- [pthread_mutex_reltimedlock_np](../../../core/libs/prx/libkernel/Pthread/Posix/Mutex.cpp) (libkernel) takes `(mutex, usec)`, a relative timeout in microseconds, and is `scePthreadMutexTimedlock` with POSIX error numbers. FreeBSD 11.4 has no such function; the signature comes only from shadPS4, which registers one function for this NID and for `scePthreadMutexTimedlock` ([`mutex.cpp`](https://github.com/shadps4-emu/shadPS4/blob/7c960eae136b956cf4c1d72aacd2426b650330df/src/core/libraries/kernel/threads/mutex.cpp#L284-L287)). shadPS4 reads a 64-bit count; here it is the 32-bit `SceKernelUseconds` of the SCE twin, as for `pthread_cond_reltimedwait_np`, so a count of 2^32 microseconds or more would be truncated if the console reads 64 bits. Unverified on the console