Merge pull request #4063 from MarcZX100/codex/carry-pthread-join-self-4052

fix(libkernel): return EDEADLK for self-join and EINVAL for null threads
This commit is contained in:
Dean 2026-10-13 01:25:36 +13:00 committed by GitHub
commit fb23e85f66
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 17 additions and 2 deletions

View File

@ -624,7 +624,7 @@ 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) return SCE_KERNEL_ERROR_EDEADLK;
ThreadCancel::Check();
@ -647,7 +647,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

View File

@ -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<int>(context.workerTid));
Require(context.workerPosixThreadId == context.workerThreadId && context.workerPosixThreadId != static_cast<int>(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);