#include "Pthread.hpp" #include "prx/libc/include/General.hpp" #include #include #include #include #include #include #include #include #include #ifdef _WIN32 #include #else #include #endif static constexpr int SCE_OK = 0; static constexpr int SCE_KERNEL_ERROR_EINVAL = 0x80020016; static constexpr int SCE_KERNEL_ERROR_ENOMEM = 0x8002000C; static constexpr int SCE_KERNEL_ERROR_EBUSY = 0x80020010; static constexpr int SCE_KERNEL_ERROR_EDEADLK = 0x80020023; static constexpr int SCE_KERNEL_ERROR_EPERM = 0x80020001; static constexpr int SCE_KERNEL_ERROR_ETIMEDOUT = 0x80020062; static constexpr int SCE_KERNEL_ERROR_EAGAIN = 0x80020023; static constexpr int SCE_KERNEL_ERROR_ESRCH = 0x80020003; static constexpr int SCE_KERNEL_ERROR_ENOTSUP = 0x80020086; static constexpr std::size_t DEFAULT_STACK_SIZE = 1u << 20; static constexpr int DETACH_JOINABLE = 0; static constexpr int DETACH_DETACHED = 1; static constexpr int SCHED_FIFO_PS5 = 1; struct ThreadArgs { void* (*entry)(void*); void* arg; PthreadPrivate* self; }; static void RunThread(std::unique_ptr args) { fprintf(stderr, "RunThread started\n"); fprintf(stdout, "RunThread started stdout\n"); void* retval = args->entry(args->arg); PthreadPrivate* self = args->self; args.reset(); { std::unique_lock lk(self->_join_mtx); self->_retval = retval; self->_finished.store(true, std::memory_order_release); } self->_join_cv.notify_all(); } extern "C" { int APS5_VABI scePthreadMutexattrInit(PthreadMutexattr* attr) { if (!attr) throw std::runtime_error("scePthreadMutexattrInit: null attr"); auto* p = new (std::nothrow) PthreadMutexattrPrivate{MutexType::Normal}; if (!p) return SCE_KERNEL_ERROR_ENOMEM; *attr = p; return SCE_OK; } int APS5_VABI scePthreadMutexattrDestroy(PthreadMutexattr* attr) { if (!attr || !*attr) throw std::runtime_error("scePthreadMutexattrDestroy: null attr"); delete *attr; *attr = nullptr; return SCE_OK; } int APS5_VABI scePthreadMutexattrSettype(PthreadMutexattr* attr, int type) { if (!attr || !*attr) throw std::runtime_error("scePthreadMutexattrSettype: null attr"); switch (type) { case 1: (*attr)->type = MutexType::ErrorCheck; break; case 2: (*attr)->type = MutexType::Recursive; break; case 3: (*attr)->type = MutexType::Normal; break; default: throw std::runtime_error("scePthreadMutexattrSettype: invalid type"); } return SCE_OK; } int APS5_VABI scePthreadMutexInit(PthreadMutex* mutex, const PthreadMutexattr* attr, const char*) { if (!mutex) throw std::runtime_error("scePthreadMutexInit: null mutex"); MutexType t = MutexType::Normal; if (attr && *attr) t = (*attr)->type; auto* p = new (std::nothrow) PthreadMutexPrivate(); if (!p) return SCE_KERNEL_ERROR_ENOMEM; p->_type = t; *mutex = p; return SCE_OK; } int APS5_VABI scePthreadMutexDestroy(PthreadMutex* mutex) { if (!mutex || !*mutex) throw std::runtime_error("scePthreadMutexDestroy: null mutex"); delete *mutex; *mutex = nullptr; return SCE_OK; } int APS5_VABI scePthreadMutexLock(PthreadMutex* mutex) { if (!mutex || !*mutex) throw std::runtime_error("scePthreadMutexLock: null mutex"); auto* m = *mutex; const auto tid = std::this_thread::get_id(); if (m->_type == MutexType::Recursive) { m->_rmtx.lock(); m->_owner.store(tid, std::memory_order_relaxed); ++m->_count; return SCE_OK; } if (m->_type == MutexType::ErrorCheck) { if (m->_owner.load(std::memory_order_acquire) == tid) return SCE_KERNEL_ERROR_EDEADLK; } m->_mtx.lock(); m->_owner.store(tid, std::memory_order_relaxed); return SCE_OK; } int APS5_VABI scePthreadMutexUnlock(PthreadMutex* mutex) { if (!mutex || !*mutex) throw std::runtime_error("scePthreadMutexUnlock: null mutex"); auto* m = *mutex; if (m->_type == MutexType::ErrorCheck || m->_type == MutexType::Normal) { if (m->_owner.load(std::memory_order_acquire) != std::this_thread::get_id()) return SCE_KERNEL_ERROR_EPERM; } if (m->_type == MutexType::Recursive) { if (--m->_count == 0) m->_owner.store(std::thread::id{}, std::memory_order_relaxed); m->_rmtx.unlock(); return SCE_OK; } m->_owner.store(std::thread::id{}, std::memory_order_relaxed); m->_mtx.unlock(); return SCE_OK; } int APS5_VABI scePthreadCondattrInit(PthreadCondattr* attr) { if (!attr) throw std::runtime_error("scePthreadCondattrInit: null attr"); auto* p = new (std::nothrow) PthreadCondattrPrivate{0}; if (!p) return SCE_KERNEL_ERROR_ENOMEM; *attr = p; return SCE_OK; } int APS5_VABI scePthreadCondattrDestroy(PthreadCondattr* attr) { if (!attr || !*attr) throw std::runtime_error("scePthreadCondattrDestroy: null attr"); delete *attr; *attr = nullptr; return SCE_OK; } int APS5_VABI scePthreadCondInit(PthreadCond* cond, const PthreadCondattr*, const char*) { if (!cond) throw std::runtime_error("scePthreadCondInit: null cond"); auto* p = new (std::nothrow) PthreadCondPrivate{}; if (!p) return SCE_KERNEL_ERROR_ENOMEM; *cond = p; return SCE_OK; } int APS5_VABI scePthreadCondDestroy(PthreadCond* cond) { if (!cond || !*cond) throw std::runtime_error("scePthreadCondDestroy: null cond"); delete *cond; *cond = nullptr; return SCE_OK; } int APS5_VABI scePthreadCondSignal(PthreadCond* cond) { if (!cond || !*cond) throw std::runtime_error("scePthreadCondSignal: null cond"); (*cond)->_cv.notify_one(); return SCE_OK; } int APS5_VABI scePthreadCondBroadcast(PthreadCond* cond) { if (!cond || !*cond) throw std::runtime_error("scePthreadCondBroadcast: null cond"); (*cond)->_cv.notify_all(); return SCE_OK; } int APS5_VABI scePthreadCondTimedwait(PthreadCond* cond, PthreadMutex* mutex, unsigned int usec) { if (!cond || !*cond || !mutex || !*mutex) throw std::runtime_error("scePthreadCondTimedwait: null arg"); auto* m = *mutex; auto* c = *cond; if (m->_type == MutexType::Recursive) { std::unique_lock lk(m->_rmtx, std::adopt_lock); auto res = c->_cv.wait_for(lk, std::chrono::microseconds(usec)); lk.release(); return res == std::cv_status::timeout ? SCE_KERNEL_ERROR_ETIMEDOUT : SCE_OK; } std::unique_lock lk(m->_mtx, std::adopt_lock); auto res = c->_cv.wait_for(lk, std::chrono::microseconds(usec)); lk.release(); return res == std::cv_status::timeout ? SCE_KERNEL_ERROR_ETIMEDOUT : SCE_OK; } int APS5_VABI scePthreadAttrInit(PthreadAttr* attr) { if (!attr) throw std::runtime_error("scePthreadAttrInit: null attr"); auto* p = new (std::nothrow) PthreadAttrPrivate{}; if (!p) return SCE_KERNEL_ERROR_ENOMEM; p->_stacksize = DEFAULT_STACK_SIZE; p->_detachstate = DETACH_JOINABLE; p->_schedpriority = 700; p->_schedpolicy = SCHED_FIFO_PS5; p->_inheritsched = 4; *attr = p; return SCE_OK; } int APS5_VABI scePthreadAttrDestroy(PthreadAttr* attr) { if (!attr || !*attr) throw std::runtime_error("scePthreadAttrDestroy: null attr"); delete *attr; *attr = nullptr; return SCE_OK; } int APS5_VABI scePthreadAttrSetdetachstate(PthreadAttr* attr, int detachstate) { if (!attr || !*attr) throw std::runtime_error("scePthreadAttrSetdetachstate: null attr"); if (detachstate != DETACH_JOINABLE && detachstate != DETACH_DETACHED) throw std::runtime_error("scePthreadAttrSetdetachstate: invalid state"); (*attr)->_detachstate = detachstate; return SCE_OK; } int APS5_VABI scePthreadAttrSetschedparam(PthreadAttr* attr, const KernelSchedParam* param) { if (!attr || !*attr || !param) throw std::runtime_error("scePthreadAttrSetschedparam: null arg"); (*attr)->_schedpriority = param->sched_priority; return SCE_OK; } int APS5_VABI scePthreadAttrSetstacksize(PthreadAttr* attr, std::size_t stacksize) { if (!attr || !*attr) throw std::runtime_error("scePthreadAttrSetstacksize: null attr"); if (stacksize < 16384) throw std::runtime_error("scePthreadAttrSetstacksize: too small"); (*attr)->_stacksize = stacksize; return SCE_OK; } int APS5_VABI scePthreadAttrGetstack(const PthreadAttr* attr, void** stackaddr, std::size_t* stacksize) { if (!attr || !*attr || !stackaddr || !stacksize) throw std::runtime_error("scePthreadAttrGetstack: null arg"); *stackaddr = nullptr; *stacksize = (*attr)->_stacksize; return SCE_OK; } int APS5_VABI scePthreadAttrGet(Pthread thread, PthreadAttr* attr) { if (!thread || !attr || !*attr) throw std::runtime_error("scePthreadAttrGet: null arg"); (*attr)->_stacksize = DEFAULT_STACK_SIZE; (*attr)->_detachstate = thread->_detached ? DETACH_DETACHED : DETACH_JOINABLE; (*attr)->_schedpriority = 700; (*attr)->_schedpolicy = SCHED_FIFO_PS5; (*attr)->_inheritsched = 4; return SCE_OK; } int APS5_VABI scePthreadCreate(Pthread* thread, const PthreadAttr* attr, void* (*entry)(void*), void* arg, const char*) { if (!thread || !entry) throw std::runtime_error("scePthreadCreate: null arg"); auto p = std::make_unique(); bool detached = false; if (attr && *attr) detached = ((*attr)->_detachstate == DETACH_DETACHED); p->_detached = detached; std::promise start; auto args = std::make_unique(ThreadArgs{entry, arg, p.get()}); p->_thr = std::thread([args = std::move(args), ready = start.get_future()]() mutable { if (ready.get()) RunThread(std::move(args)); }); try { if (detached) p->_thr.detach(); } catch (...) { start.set_value(false); p->_thr.join(); throw; } *thread = p.release(); start.set_value(true); return SCE_OK; } int APS5_VABI scePthreadJoin(Pthread thread, void** retval) { if (!thread) throw std::runtime_error("scePthreadJoin: null thread"); if (thread->_detached) return SCE_KERNEL_ERROR_EINVAL; if (thread->_thr.joinable()) thread->_thr.join(); if (retval) *retval = thread->_retval; delete thread; return SCE_OK; } int APS5_VABI scePthreadDetach(Pthread thread) { if (!thread) throw std::runtime_error("scePthreadDetach: null thread"); if (thread->_detached) return SCE_KERNEL_ERROR_EINVAL; thread->_detached = true; if (thread->_thr.joinable()) thread->_thr.detach(); return SCE_OK; } void APS5_VABI scePthreadExit(void* retval) { #ifdef _WIN32 ExitThread(0); #else pthread_exit(retval); #endif __builtin_unreachable(); } Pthread APS5_VABI scePthreadSelf() { return nullptr; } void APS5_VABI scePthreadYield() { std::this_thread::yield(); } } // extern "C"