From 351ca3bb12a86422b5897e1aff6ac07b098fc399 Mon Sep 17 00:00:00 2001 From: Hussein Kadhim Date: Sun, 11 Oct 2026 23:29:08 +0300 Subject: [PATCH] fix(libkernel): return EDEADLK for a thread joining itself and EINVAL for a null thread scePthreadJoin threw when a joinable thread joined itself and scePthreadJoin and scePthreadDetach threw on a null thread, so pthread_join and pthread_detach ended the process where FreeBSD libthr returns EDEADLK and EINVAL. --- core/libs/prx/libkernel/Pthread/src/Thread.cpp | 7 +++---- core/libs/tests/GuestThreadSelf.cpp | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/core/libs/prx/libkernel/Pthread/src/Thread.cpp b/core/libs/prx/libkernel/Pthread/src/Thread.cpp index fada8e72a..d52679aaf 100644 --- a/core/libs/prx/libkernel/Pthread/src/Thread.cpp +++ b/core/libs/prx/libkernel/Pthread/src/Thread.cpp @@ -618,10 +618,9 @@ int APS5_VABI scePthreadCreate(Pthread* thread, const PthreadAttr* attr, Pthread } int APS5_VABI scePthreadJoin(Pthread thread, void** retval) { - if (!thread) throw std::runtime_error("scePthreadJoin: null thread"); + if (!thread) return SCE_KERNEL_ERROR_EINVAL; if (thread->_detached) return SCE_KERNEL_ERROR_EINVAL; - if (thread == CurrentGuestState().current) - throw std::runtime_error("scePthreadJoin: cannot join current thread"); + if (thread == CurrentGuestState().current) return SCE_KERNEL_ERROR_EDEADLK; ThreadCancel::Check(); { std::unique_lock lock(thread->_join_mtx); @@ -642,7 +641,7 @@ int APS5_VABI scePthreadJoin(Pthread thread, void** retval) { } int APS5_VABI scePthreadDetach(Pthread thread) { - if (!thread) throw std::runtime_error("scePthreadDetach: null thread"); + if (!thread) return SCE_KERNEL_ERROR_EINVAL; if (thread->_detached) return SCE_KERNEL_ERROR_EINVAL; thread->_detached = true; #ifdef _WIN32 diff --git a/core/libs/tests/GuestThreadSelf.cpp b/core/libs/tests/GuestThreadSelf.cpp index 57413d0a9..9c59471e9 100644 --- a/core/libs/tests/GuestThreadSelf.cpp +++ b/core/libs/tests/GuestThreadSelf.cpp @@ -7,6 +7,8 @@ extern "C" { int APS5_VABI scePthreadCreate(Pthread* thread, const PthreadAttr* attr, PthreadEntry entry, void* arg, const char* name); int APS5_VABI scePthreadJoin(Pthread thread, void** retval); int APS5_VABI scePthreadDetach(Pthread thread); +int APS5_VABI pthread_join_nid_postfix(Pthread thread, void** value); +int APS5_VABI pthread_detach_nid_postfix(Pthread thread); void APS5_VABI scePthreadExit(void* retval); Pthread APS5_VABI scePthreadSelf(); int APS5_VABI scePthreadGetthreadid(void); @@ -46,6 +48,9 @@ static bool StackContains(Pthread thread, const void* address) { static constexpr int SCE_OK = 0; static constexpr int SCE_KERNEL_ERROR_EINVAL = 0x80020016; static constexpr int SCE_KERNEL_ERROR_EPERM = 0x80020001; +static constexpr int SCE_KERNEL_ERROR_EDEADLK = 0x8002000b; +static constexpr int GUEST_EDEADLK = 11; +static constexpr int GUEST_EINVAL = 22; static constexpr int MUTEX_TYPE_RECURSIVE = 2; static constexpr int PTHREAD_CANCEL_ENABLE = 0; static constexpr int PTHREAD_CANCEL_ASYNCHRONOUS = 2; @@ -69,6 +74,8 @@ struct WorkerContext { PthreadMutex* mutex = nullptr; int unlockResult = 0; bool testcancelReturned = false; + int sceJoinSelf = 0; + int posixJoinSelf = 0; }; static void* APS5_VABI Worker(void* arg) { @@ -80,6 +87,8 @@ static void* APS5_VABI Worker(void* arg) { int local = 0; context.workerStackReported = StackContains(context.selfFromWorker, &local); context.unlockResult = scePthreadMutexUnlock(context.mutex); + context.sceJoinSelf = scePthreadJoin(context.selfFromWorker, nullptr); + context.posixJoinSelf = pthread_join_nid_postfix(context.selfFromWorker, nullptr); int oldState = -1; int oldType = -1; context.testcancelReturned = scePthreadSetcancelstate(PTHREAD_CANCEL_ENABLE, &oldState) == SCE_OK && @@ -103,6 +112,10 @@ int main() { Require(StackContains(mainSelf, &local)); Require(scePthreadJoin(mainSelf, nullptr) == SCE_KERNEL_ERROR_EINVAL); Require(scePthreadDetach(mainSelf) == SCE_KERNEL_ERROR_EINVAL); + Require(scePthreadJoin(nullptr, nullptr) == SCE_KERNEL_ERROR_EINVAL); + Require(scePthreadDetach(nullptr) == SCE_KERNEL_ERROR_EINVAL); + Require(pthread_join_nid_postfix(nullptr, nullptr) == GUEST_EINVAL); + Require(pthread_detach_nid_postfix(nullptr) == GUEST_EINVAL); PthreadMutexattr attr = nullptr; Require(scePthreadMutexattrInit(&attr) == SCE_OK); @@ -129,6 +142,8 @@ int main() { Require(context.workerThreadId == static_cast(context.workerTid)); Require(context.workerPosixThreadId == context.workerThreadId && context.workerPosixThreadId != static_cast(mainTid)); Require(context.unlockResult == SCE_KERNEL_ERROR_EPERM); + Require(context.sceJoinSelf == SCE_KERNEL_ERROR_EDEADLK); + Require(context.posixJoinSelf == GUEST_EDEADLK); Require(context.workerStackReported); Require(context.testcancelReturned);