mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-28 00:35:47 +00:00
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:
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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user