mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 08:33:12 -05:00
- scePthreadSelf returned null on Linux and for threads not created by scePthreadCreate (including the main thread); such threads now get a lazily adopted, non-joinable handle - scePthreadExit on Linux skipped FinishThread, losing the join value - detached threads on Linux were never freed; use the reference count already used on Windows - unlocking a recursive mutex from a non-owner was undefined behaviour; return SCE_KERNEL_ERROR_EPERM - scePthreadCondTimedwait did not restore the mutex owner after waking, so another thread locking during the wait made the waiter's unlock fail with EPERM and left the mutex locked forever - SCE_KERNEL_ERROR_ETIMEDOUT in Cond.cpp was 0x80020062 instead of 0x8002003C Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
53 lines
2.1 KiB
C++
53 lines
2.1 KiB
C++
#include "SceTypes.hpp"
|
|
#include <atomic>
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
|
|
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 scePthreadMutexInit(PthreadMutex* mutex, const PthreadMutexattr* attr, const char* name);
|
|
int APS5_VABI scePthreadMutexDestroy(PthreadMutex* mutex);
|
|
int APS5_VABI scePthreadMutexLock(PthreadMutex* mutex);
|
|
int APS5_VABI scePthreadMutexUnlock(PthreadMutex* mutex);
|
|
int APS5_VABI scePthreadCondInit(PthreadCond* cond, const PthreadCondattr* attr, const char* name);
|
|
int APS5_VABI scePthreadCondDestroy(PthreadCond* cond);
|
|
int APS5_VABI scePthreadCondTimedwait(PthreadCond* cond, PthreadMutex* mutex, unsigned int usec);
|
|
}
|
|
|
|
static constexpr int SCE_OK = 0;
|
|
static constexpr int SCE_KERNEL_ERROR_ETIMEDOUT = static_cast<int>(0x8002003C);
|
|
|
|
static void Require(bool value) { if (!value) std::abort(); }
|
|
|
|
struct Context {
|
|
PthreadMutex mutex = nullptr;
|
|
std::atomic<bool> acquired{false};
|
|
};
|
|
|
|
static void* APS5_VABI Contender(void* arg) {
|
|
auto& context = *static_cast<Context*>(arg);
|
|
Require(scePthreadMutexLock(&context.mutex) == SCE_OK);
|
|
context.acquired.store(true);
|
|
Require(scePthreadMutexUnlock(&context.mutex) == SCE_OK);
|
|
return nullptr;
|
|
}
|
|
|
|
int main() {
|
|
Context context;
|
|
PthreadCond cond = nullptr;
|
|
Require(scePthreadMutexInit(&context.mutex, nullptr, nullptr) == SCE_OK);
|
|
Require(scePthreadCondInit(&cond, nullptr, nullptr) == SCE_OK);
|
|
|
|
Require(scePthreadMutexLock(&context.mutex) == SCE_OK);
|
|
Pthread thread = nullptr;
|
|
Require(scePthreadCreate(&thread, nullptr, Contender, &context, nullptr) == SCE_OK);
|
|
while (!context.acquired.load())
|
|
Require(scePthreadCondTimedwait(&cond, &context.mutex, 1000) == SCE_KERNEL_ERROR_ETIMEDOUT);
|
|
Require(scePthreadMutexUnlock(&context.mutex) == SCE_OK);
|
|
Require(scePthreadJoin(thread, nullptr) == SCE_OK);
|
|
|
|
Require(scePthreadCondDestroy(&cond) == SCE_OK);
|
|
Require(scePthreadMutexDestroy(&context.mutex) == SCE_OK);
|
|
}
|