feat(libkernel): add pthread module impl(wip)

This commit is contained in:
boykopovar 2026-09-07 08:50:31 +03:00
parent e79f5ebc58
commit e77d724a1b
5 changed files with 578 additions and 644 deletions

View File

@ -1,6 +1,8 @@
add_library(libkernel SHARED EXCLUDE_FROM_ALL
${CMAKE_CURRENT_SOURCE_DIR}/Export.cpp
${CMAKE_CURRENT_SOURCE_DIR}/DirectMemory/DirectMemory.cpp
${CMAKE_CURRENT_SOURCE_DIR}/DirectMemory/MemoryPool.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Pthread/Pthread.cpp
)
target_include_directories(libkernel PRIVATE ${LIBS_INCLUDE_DIR})

View File

@ -0,0 +1,95 @@
int sceKernelAllocateDirectMemory(int64_t search_start, int64_t search_end, size_t len, size_t alignment, int memory_type, int64_t* phys_addr_out) {
(void)memory_type;
if (search_start < 0 || search_end <= search_start || len == 0
|| (len & (PS5_PAGE_SIZE - 1)) || !phys_addr_out
|| (alignment != 0 && (alignment & (PS5_PAGE_SIZE - 1))))
return SCE_KERNEL_ERROR_EINVAL;
return DirectMemoryAlloc(search_start, search_end, len, alignment, phys_addr_out);
}
int sceKernelAllocateMainDirectMemory(size_t len, size_t alignment, int memory_type, int64_t* phys_addr_out) {
return sceKernelAllocateDirectMemory(0, static_cast<int64_t>(DIRECT_MEMORY_SIZE), len, alignment, memory_type, phys_addr_out);
}
int sceKernelAvailableDirectMemorySize(int64_t search_start, int64_t search_end, size_t alignment, int64_t* phys_addr_out, size_t* size_out) {
if (!phys_addr_out || !size_out) return SCE_KERNEL_ERROR_EINVAL;
int64_t tmpPhys = 0;
int ret = DirectMemoryAlloc(search_start, search_end, PS5_PAGE_SIZE, alignment, &tmpPhys);
if (ret != 0) { *phys_addr_out = 0; *size_out = 0; return ret; }
DirectMemoryFree(tmpPhys, PS5_PAGE_SIZE);
*phys_addr_out = tmpPhys;
*size_out = static_cast<size_t>(search_end) - static_cast<size_t>(tmpPhys);
return 0;
}
int sceKernelDirectMemoryQuery(int64_t offset, int flags, void* info, size_t info_size) {
(void)flags;
if (!info || offset < 0) return SCE_KERNEL_ERROR_EINVAL;
struct DirectMemoryQueryInfo { int64_t start; int64_t end; int memory_type; };
if (info_size < sizeof(DirectMemoryQueryInfo)) return SCE_KERNEL_ERROR_EINVAL;
auto* q = static_cast<DirectMemoryQueryInfo*>(info);
q->start = offset & ~static_cast<int64_t>(PS5_PAGE_SIZE - 1);
q->end = q->start + PS5_PAGE_SIZE;
q->memory_type = 3;
return 0;
}
size_t sceKernelGetDirectMemorySize(void) {
return DIRECT_MEMORY_SIZE;
}
int sceKernelMapDirectMemory(void** addr, size_t len, int prot, int flags, int64_t direct_memory_start, size_t alignment) {
(void)alignment;
return DoMapDirect(addr, len, prot, flags, direct_memory_start, alignment);
}
int sceKernelMapDirectMemory2(void** addr, size_t len, int type, int prot, int flags, int64_t direct_memory_start, size_t alignment) {
(void)type;
return DoMapDirect(addr, len, prot, flags, direct_memory_start, alignment);
}
int sceKernelMapFlexibleMemory(void** addr_in_out, size_t len, int prot, int flags) {
return DoMapAnon(addr_in_out, len, prot, flags);
}
int sceKernelMapNamedDirectMemory(void** addr, size_t len, int prot, int flags, int64_t direct_memory_start, size_t alignment, const char* name) {
(void)name;
return DoMapDirect(addr, len, prot, flags, direct_memory_start, alignment);
}
int32_t sceKernelMapNamedFlexibleMemory(void** addr_in_out, size_t len, int prot, int flags, const char* name) {
(void)name;
return DoMapAnon(addr_in_out, len, prot, flags);
}
int sceKernelMprotect(const void* addr, size_t len, int prot) {
return DoMprotect(addr, len, prot);
}
int sceKernelMunmap(uint64_t vaddr, size_t len) {
return DoMunmap(reinterpret_cast<void*>(vaddr), len);
}
int sceKernelReleaseDirectMemory(int64_t start, size_t len) {
if (start < 0 || len == 0) return SCE_KERNEL_ERROR_EINVAL;
DirectMemoryFree(start, len);
return 0;
}
int sceKernelReserveVirtualRange(void** addr, size_t len, int flags, size_t alignment) {
(void)flags;
return DoReserveVirtual(addr, len, alignment);
}
int sceKernelVirtualQuery(const void* addr, int flags, VirtualQueryInfo* info, uint64_t info_size) {
(void)flags;
if (!info || info_size < sizeof(VirtualQueryInfo)) return SCE_KERNEL_ERROR_EINVAL;
memset(info, 0, sizeof(VirtualQueryInfo));
uintptr_t ptr = reinterpret_cast<uintptr_t>(addr);
info->start = ptr & ~static_cast<uintptr_t>(PS5_PAGE_SIZE - 1);
info->end = info->start + PS5_PAGE_SIZE;
info->is_direct = 1;
info->protection = 3;
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,299 @@
#include "Pthread.hpp"
#include "prx/libc/include/General.hpp"
#include <cerrno>
#include <chrono>
#include <cstdlib>
#include <cstring>
#include <stdexcept>
#include <thread>
#ifdef _WIN32
#include <windows.h>
#else
#include <pthread.h>
#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(ThreadArgs* args) {
void* retval = args->entry(args->arg);
PthreadPrivate* self = args->self;
delete args;
{
std::unique_lock<std::mutex> lk(self->_join_mtx);
self->_retval = retval;
self->_finished.store(true, std::memory_order_release);
}
self->_join_cv.notify_all();
}
extern "C" {
int 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 scePthreadMutexattrDestroy(PthreadMutexattr* attr) {
if (!attr || !*attr) throw std::runtime_error("scePthreadMutexattrDestroy: null attr");
delete *attr;
*attr = nullptr;
return SCE_OK;
}
int 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 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 scePthreadMutexDestroy(PthreadMutex* mutex) {
if (!mutex || !*mutex) throw std::runtime_error("scePthreadMutexDestroy: null mutex");
delete *mutex;
*mutex = nullptr;
return SCE_OK;
}
int 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 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 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 scePthreadCondattrDestroy(PthreadCondattr* attr) {
if (!attr || !*attr) throw std::runtime_error("scePthreadCondattrDestroy: null attr");
delete *attr;
*attr = nullptr;
return SCE_OK;
}
int 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 scePthreadCondDestroy(PthreadCond* cond) {
if (!cond || !*cond) throw std::runtime_error("scePthreadCondDestroy: null cond");
delete *cond;
*cond = nullptr;
return SCE_OK;
}
int scePthreadCondSignal(PthreadCond* cond) {
if (!cond || !*cond) throw std::runtime_error("scePthreadCondSignal: null cond");
(*cond)->_cv.notify_one();
return SCE_OK;
}
int scePthreadCondBroadcast(PthreadCond* cond) {
if (!cond || !*cond) throw std::runtime_error("scePthreadCondBroadcast: null cond");
(*cond)->_cv.notify_all();
return SCE_OK;
}
int 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<std::recursive_timed_mutex> 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<std::timed_mutex> 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 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 scePthreadAttrDestroy(PthreadAttr* attr) {
if (!attr || !*attr) throw std::runtime_error("scePthreadAttrDestroy: null attr");
delete *attr;
*attr = nullptr;
return SCE_OK;
}
int 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 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 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 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 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 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 = new (std::nothrow) PthreadPrivate{};
if (!p) return SCE_KERNEL_ERROR_ENOMEM;
bool detached = false;
if (attr && *attr) detached = ((*attr)->_detachstate == DETACH_DETACHED);
p->_detached = detached;
auto* targs = new ThreadArgs{entry, arg, p};
p->_thr = std::thread([targs]() { RunThread(targs); });
if (detached) p->_thr.detach();
*thread = p;
return SCE_OK;
}
int 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 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 scePthreadExit(void* retval) {
#ifdef _WIN32
ExitThread(0);
#else
pthread_exit(retval);
#endif
__builtin_unreachable();
}
Pthread scePthreadSelf() {
return nullptr;
}
void scePthreadYield() {
std::this_thread::yield();
}
} // extern "C"

View File

@ -0,0 +1,57 @@
#pragma once
#include <sched.h>
#include "SceTypes.hpp"
#include <atomic>
#include <condition_variable>
#include <cstddef>
#include <cstdint>
#include <mutex>
#include <string>
#include <thread>
enum class MutexType : std::uint32_t {
ErrorCheck = 1,
Recursive = 2,
Normal = 3,
};
struct PthreadMutexattrPrivate {
MutexType type;
};
struct PthreadMutexPrivate {
std::recursive_timed_mutex _rmtx;
std::timed_mutex _mtx;
MutexType _type;
std::atomic<std::thread::id> _owner;
int _count;
PthreadMutexPrivate() : _type(MutexType::Normal), _count(0) {}
};
struct PthreadCondattrPrivate {
int _clockid;
};
struct PthreadCondPrivate {
std::condition_variable_any _cv;
};
struct PthreadAttrPrivate {
std::size_t _stacksize;
int _detachstate;
int _schedpriority;
int _schedpolicy;
int _inheritsched;
};
struct PthreadPrivate {
std::thread _thr;
std::atomic<bool> _finished;
void* _retval;
bool _detached;
std::mutex _join_mtx;
std::condition_variable _join_cv;
PthreadPrivate() : _finished(false), _retval(nullptr), _detached(false) {}
};