From 13c648bebbdcdc501b4b67ed01670e84647cf91d Mon Sep 17 00:00:00 2001 From: boykopovar Date: Sat, 26 Sep 2026 18:35:20 +0300 Subject: [PATCH] feat(libkernel): impl file, time, process, signal for posix --- core/libs/prx/libkernel/CMakeLists.txt | 1 - core/libs/prx/libkernel/File/src/Stdio.cpp | 61 +++++++++++- .../prx/libkernel/Pthread/Posix/Rwlock.cpp | 22 +++++ .../prx/libkernel/Pthread/include/Rwlock.hpp | 21 ++++ .../libs/prx/libkernel/Pthread/src/Rwlock.cpp | 1 + .../libkernel/System/src/PosixImportStubs.cpp | 91 ------------------ .../libs/prx/libkernel/System/src/Process.cpp | 95 +++++++++++++++++++ .../libs/prx/libkernel/System/src/Signals.cpp | 26 +++++ core/libs/prx/libkernel/Time/Time.cpp | 4 + 9 files changed, 227 insertions(+), 95 deletions(-) create mode 100644 core/libs/prx/libkernel/Pthread/include/Rwlock.hpp delete mode 100644 core/libs/prx/libkernel/System/src/PosixImportStubs.cpp diff --git a/core/libs/prx/libkernel/CMakeLists.txt b/core/libs/prx/libkernel/CMakeLists.txt index 965749d04..394bad513 100644 --- a/core/libs/prx/libkernel/CMakeLists.txt +++ b/core/libs/prx/libkernel/CMakeLists.txt @@ -39,7 +39,6 @@ add_library(libkernel SHARED EXCLUDE_FROM_ALL ${CMAKE_CURRENT_SOURCE_DIR}/System/src/Sanitizer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/System/src/Rtld.cpp ${CMAKE_CURRENT_SOURCE_DIR}/System/src/Process.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/System/src/PosixImportStubs.cpp ${CMAKE_CURRENT_SOURCE_DIR}/System/src/SystemConfiguration.cpp ${CMAKE_CURRENT_SOURCE_DIR}/System/src/Signals.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Time/Time.cpp diff --git a/core/libs/prx/libkernel/File/src/Stdio.cpp b/core/libs/prx/libkernel/File/src/Stdio.cpp index 81704d09d..c0cefcd8b 100644 --- a/core/libs/prx/libkernel/File/src/Stdio.cpp +++ b/core/libs/prx/libkernel/File/src/Stdio.cpp @@ -2,11 +2,23 @@ #include #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +#include "prx/libkernel/File/include/File.hpp" +#include "prx/libkernel/File/include/FileFlags.hpp" #include "prx/libkernel/Socket/include/SocketRuntime.hpp" +#include +#include +#include #ifdef _WIN32 #include +#include +static int NativeRmdir(const std::filesystem::path& path) { + return ::_wrmdir(path.wstring().c_str()); +} #else #include +static int NativeRmdir(const std::filesystem::path& path) { + return ::rmdir(path.c_str()); +} #endif extern "C" { @@ -27,6 +39,10 @@ int APS5_VABI close_nid_postfix(int d) { #endif } +int APS5_VABI _close_nid_postfix(int descriptor) { + return close_nid_postfix(descriptor); +} + int APS5_VABI flock_nid_postfix(int d, int operation) { (void)d; (void)operation; @@ -71,6 +87,24 @@ int APS5_VABI open_nid_postfix(const char* path, int flags, int mode) { return 0; } +int APS5_VABI _open_nid_postfix(const char* path, int flags, ...) { + std::uint16_t mode = 0; + if (flags & SCE_KERNEL_O_CREAT) { +#ifdef _WIN32 + __builtin_sysv_va_list arguments; + __builtin_sysv_va_start(arguments, flags); + mode = static_cast(__builtin_va_arg(arguments, int)); + __builtin_sysv_va_end(arguments); +#else + std::va_list arguments; + va_start(arguments, flags); + mode = static_cast(va_arg(arguments, int)); + va_end(arguments); +#endif + } + return sceKernelOpen(path, flags, mode); +} + int64_t APS5_VABI pread_nid_postfix(int d, void* buf, size_t nbytes, int64_t offset) { (void)d; (void)buf; @@ -97,6 +131,10 @@ int64_t APS5_VABI read_nid_postfix(int d, void* buf, uint64_t nbytes) { return 0; } +std::int64_t APS5_VABI _read_nid_postfix(int descriptor, void* buffer, std::size_t count) { + return sceKernelRead(descriptor, buffer, count); +} + int64_t APS5_VABI write_nid_postfix(int d, const char* str, int64_t size) { (void)d; (void)str; @@ -105,6 +143,10 @@ int64_t APS5_VABI write_nid_postfix(int d, const char* str, int64_t size) { return 0; } +std::int64_t APS5_VABI _write_nid_postfix(int descriptor, const void* buffer, std::size_t count) { + return sceKernelWrite(descriptor, buffer, count); +} + int APS5_VABI stat_nid_postfix(const char* path, FileStat* sb) { (void)path; (void)sb; @@ -112,6 +154,10 @@ int APS5_VABI stat_nid_postfix(const char* path, FileStat* sb) { return 0; } +int APS5_VABI unlink_nid_postfix(const char* path) { + return sceKernelUnlink(path); +} + int APS5_VABI sceKernelCheckReachability(const char* path) { (void)path; NotImplemented_nid_no_patch(__func__); @@ -181,9 +227,18 @@ int APS5_VABI sceKernelRename(const char* from, const char* to) { } int APS5_VABI sceKernelRmdir(const char* path) { - (void)path; - NotImplemented_nid_no_patch(__func__); - return 0; + if (path == nullptr) { + throw std::invalid_argument(std::string(__func__) + ": path is null"); + } + auto native = ResolvePath_nid_no_patch(path); + if (NativeRmdir(native) != 0) { + throw std::runtime_error(std::string(__func__) + ": rmdir failed for " + native.string() + ", errno=" + std::to_string(errno)); + } + return 0; +} + +int APS5_VABI rmdir_nid_postfix(const char* path) { + return sceKernelRmdir(path); } } diff --git a/core/libs/prx/libkernel/Pthread/Posix/Rwlock.cpp b/core/libs/prx/libkernel/Pthread/Posix/Rwlock.cpp index 2f1ee6a98..52f67399e 100644 --- a/core/libs/prx/libkernel/Pthread/Posix/Rwlock.cpp +++ b/core/libs/prx/libkernel/Pthread/Posix/Rwlock.cpp @@ -2,6 +2,20 @@ #include #include "SceTypes.hpp" #include "prx/libc/include/General.hpp" +#include "../include/Rwlock.hpp" + +namespace { + +int toPosix(int result) { + if (result == 0) + return 0; + const auto error = static_cast(result); + if ((error & 0xffff0000u) != 0x80020000u) + throw std::runtime_error("Unexpected SCE rwlock error"); + return static_cast(error & 0xffffu); +} + +} extern "C" { @@ -18,6 +32,14 @@ int APS5_VABI pthread_rwlock_init_nid_postfix(PthreadRwlock* rwlock, const Pthre return 0; } +int APS5_VABI pthread_rwlock_rdlock_nid_postfix(PthreadRwlock* rwlock) { + return toPosix(scePthreadRwlockRdlock(rwlock)); +} + +int APS5_VABI pthread_rwlock_unlock_nid_postfix(PthreadRwlock* rwlock) { + return toPosix(scePthreadRwlockUnlock(rwlock)); +} + int APS5_VABI pthread_rwlock_wrlock_nid_postfix(PthreadRwlock* rwlock) { (void)rwlock; NotImplemented_nid_no_patch(__func__); diff --git a/core/libs/prx/libkernel/Pthread/include/Rwlock.hpp b/core/libs/prx/libkernel/Pthread/include/Rwlock.hpp new file mode 100644 index 000000000..0c9668003 --- /dev/null +++ b/core/libs/prx/libkernel/Pthread/include/Rwlock.hpp @@ -0,0 +1,21 @@ +#ifndef CORE_LIBS_PRX_LIBKERNEL_PTHREAD_RWLOCK_HPP +#define CORE_LIBS_PRX_LIBKERNEL_PTHREAD_RWLOCK_HPP + +#include "SceTypes.hpp" + +extern "C" { + +int APS5_VABI scePthreadRwlockattrInit(PthreadRwlockattr* attr); +int APS5_VABI scePthreadRwlockattrDestroy(PthreadRwlockattr* attr); +int APS5_VABI scePthreadRwlockattrSettype(PthreadRwlockattr* attr, int type); +int APS5_VABI scePthreadRwlockInit(PthreadRwlock* rwlock, const PthreadRwlockattr* attr, const char* name); +int APS5_VABI scePthreadRwlockDestroy(PthreadRwlock* rwlock); +int APS5_VABI scePthreadRwlockRdlock(PthreadRwlock* rwlock); +int APS5_VABI scePthreadRwlockTryrdlock(PthreadRwlock* rwlock); +int APS5_VABI scePthreadRwlockWrlock(PthreadRwlock* rwlock); +int APS5_VABI scePthreadRwlockTrywrlock(PthreadRwlock* rwlock); +int APS5_VABI scePthreadRwlockUnlock(PthreadRwlock* rwlock); + +} + +#endif diff --git a/core/libs/prx/libkernel/Pthread/src/Rwlock.cpp b/core/libs/prx/libkernel/Pthread/src/Rwlock.cpp index 12a6040a2..4804e2dac 100644 --- a/core/libs/prx/libkernel/Pthread/src/Rwlock.cpp +++ b/core/libs/prx/libkernel/Pthread/src/Rwlock.cpp @@ -1,4 +1,5 @@ #include "../include/Pthread.hpp" +#include "../include/Rwlock.hpp" #include "prx/libc/include/General.hpp" extern "C" { diff --git a/core/libs/prx/libkernel/System/src/PosixImportStubs.cpp b/core/libs/prx/libkernel/System/src/PosixImportStubs.cpp deleted file mode 100644 index bfb5cd145..000000000 --- a/core/libs/prx/libkernel/System/src/PosixImportStubs.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include "SceTypes.hpp" -#include "prx/libc/include/General.hpp" -#include -#include - -struct GuestSignalSet; -struct GuestResourceUsage; - -extern "C" { - -int APS5_VABI _close_nid_postfix(int descriptor) { - (void)descriptor; - NotImplemented_nid_no_patch(__func__); - return 0; -} - -void APS5_VABI _exit_nid_postfix(int status) { - (void)status; - NotImplemented_nid_no_patch(__func__); -} - -int APS5_VABI _nanosleep_nid_postfix(const KernelTimespec* requested, KernelTimespec* remaining) { - (void)requested; - (void)remaining; - NotImplemented_nid_no_patch(__func__); - return 0; -} - -int APS5_VABI _open_nid_postfix(const char* path, int flags, ...) { - (void)path; - (void)flags; - NotImplemented_nid_no_patch(__func__); - return 0; -} - -std::int64_t APS5_VABI _read_nid_postfix(int descriptor, void* buffer, std::size_t count) { - (void)descriptor; - (void)buffer; - (void)count; - NotImplemented_nid_no_patch(__func__); - return 0; -} - -int APS5_VABI _sigprocmask_nid_postfix(int how, const GuestSignalSet* set, GuestSignalSet* previousSet) { - (void)how; - (void)set; - (void)previousSet; - NotImplemented_nid_no_patch(__func__); - return 0; -} - -std::int64_t APS5_VABI _write_nid_postfix(int descriptor, const void* buffer, std::size_t count) { - (void)descriptor; - (void)buffer; - (void)count; - NotImplemented_nid_no_patch(__func__); - return 0; -} - -int APS5_VABI getrusage_nid_postfix(int who, GuestResourceUsage* usage) { - (void)who; - (void)usage; - NotImplemented_nid_no_patch(__func__); - return 0; -} - -int APS5_VABI pthread_rwlock_rdlock_nid_postfix(PthreadRwlock* rwlock) { - (void)rwlock; - NotImplemented_nid_no_patch(__func__); - return 0; -} - -int APS5_VABI pthread_rwlock_unlock_nid_postfix(PthreadRwlock* rwlock) { - (void)rwlock; - NotImplemented_nid_no_patch(__func__); - return 0; -} - -int APS5_VABI rmdir_nid_postfix(const char* path) { - (void)path; - NotImplemented_nid_no_patch(__func__); - return 0; -} - -int APS5_VABI unlink_nid_postfix(const char* path) { - (void)path; - NotImplemented_nid_no_patch(__func__); - return 0; -} - -} diff --git a/core/libs/prx/libkernel/System/src/Process.cpp b/core/libs/prx/libkernel/System/src/Process.cpp index 4fa1e7ea9..7fe1ad6bb 100644 --- a/core/libs/prx/libkernel/System/src/Process.cpp +++ b/core/libs/prx/libkernel/System/src/Process.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -26,6 +27,9 @@ #include #include #include +#ifndef _WIN32 +#include +#endif namespace { @@ -116,6 +120,25 @@ void syncVolumes() { } +struct GuestResourceUsage { + KernelTimeval ru_utime; + KernelTimeval ru_stime; + std::int64_t ru_maxrss; + std::int64_t ru_ixrss; + std::int64_t ru_idrss; + std::int64_t ru_isrss; + std::int64_t ru_minflt; + std::int64_t ru_majflt; + std::int64_t ru_nswap; + std::int64_t ru_inblock; + std::int64_t ru_oublock; + std::int64_t ru_msgsnd; + std::int64_t ru_msgrcv; + std::int64_t ru_nsignals; + std::int64_t ru_nvcsw; + std::int64_t ru_nivcsw; +}; + extern "C" { // unknown signature @@ -148,6 +171,10 @@ void APS5_VABI exit_nid_postfix(int code) { LibcExit_nid_no_patch(code); } +[[noreturn]] void APS5_VABI _exit_nid_postfix(int status) { + std::_Exit(status); +} + int APS5_VABI sceKernelGetCurrentCpu(void) { #ifdef _WIN32 PROCESSOR_NUMBER processor{}; @@ -219,4 +246,72 @@ int APS5_VABI sched_get_priority_min_nid_postfix(int policy) { return 767; } +int APS5_VABI getrusage_nid_postfix(int who, GuestResourceUsage* usage) { + if (usage == nullptr) + throw std::invalid_argument("getrusage: usage is null"); + if (who != 0 && who != 1) + throw std::invalid_argument("getrusage: unsupported who"); +#ifdef _WIN32 + FILETIME creation{}; + FILETIME exitTime{}; + FILETIME kernel{}; + FILETIME user{}; + if (who == 0) { + if (!GetProcessTimes(GetCurrentProcess(), &creation, &exitTime, &kernel, &user)) + throw std::system_error(GetLastError(), std::system_category(), "getrusage: GetProcessTimes failed"); + } else { + if (!GetThreadTimes(GetCurrentThread(), &creation, &exitTime, &kernel, &user)) + throw std::system_error(GetLastError(), std::system_category(), "getrusage: GetThreadTimes failed"); + } + const auto toMicros = [](const FILETIME& time) { + return ((static_cast(time.dwHighDateTime) << 32) | time.dwLowDateTime) / 10ULL; + }; + const auto userMicros = toMicros(user); + const auto kernelMicros = toMicros(kernel); + usage->ru_utime.tv_sec = static_cast(userMicros / 1000000ULL); + usage->ru_utime.tv_usec = static_cast(userMicros % 1000000ULL); + usage->ru_stime.tv_sec = static_cast(kernelMicros / 1000000ULL); + usage->ru_stime.tv_usec = static_cast(kernelMicros % 1000000ULL); + usage->ru_maxrss = 0; + usage->ru_ixrss = 0; + usage->ru_idrss = 0; + usage->ru_isrss = 0; + usage->ru_minflt = 0; + usage->ru_majflt = 0; + usage->ru_nswap = 0; + usage->ru_inblock = 0; + usage->ru_oublock = 0; + usage->ru_msgsnd = 0; + usage->ru_msgrcv = 0; + usage->ru_nsignals = 0; + usage->ru_nvcsw = 0; + usage->ru_nivcsw = 0; +#else + if (who == 1) + throw std::invalid_argument("getrusage: RUSAGE_THREAD is not supported on this platform"); + struct rusage native{}; + if (::getrusage(RUSAGE_SELF, &native) != 0) + throw std::system_error(errno, std::generic_category(), "getrusage: getrusage failed"); + usage->ru_utime.tv_sec = static_cast(native.ru_utime.tv_sec); + usage->ru_utime.tv_usec = static_cast(native.ru_utime.tv_usec); + usage->ru_stime.tv_sec = static_cast(native.ru_stime.tv_sec); + usage->ru_stime.tv_usec = static_cast(native.ru_stime.tv_usec); + usage->ru_maxrss = static_cast(native.ru_maxrss); + usage->ru_ixrss = static_cast(native.ru_ixrss); + usage->ru_idrss = static_cast(native.ru_idrss); + usage->ru_isrss = static_cast(native.ru_isrss); + usage->ru_minflt = static_cast(native.ru_minflt); + usage->ru_majflt = static_cast(native.ru_majflt); + usage->ru_nswap = static_cast(native.ru_nswap); + usage->ru_inblock = static_cast(native.ru_inblock); + usage->ru_oublock = static_cast(native.ru_oublock); + usage->ru_msgsnd = static_cast(native.ru_msgsnd); + usage->ru_msgrcv = static_cast(native.ru_msgrcv); + usage->ru_nsignals = static_cast(native.ru_nsignals); + usage->ru_nvcsw = static_cast(native.ru_nvcsw); + usage->ru_nivcsw = static_cast(native.ru_nivcsw); +#endif + return 0; +} + } diff --git a/core/libs/prx/libkernel/System/src/Signals.cpp b/core/libs/prx/libkernel/System/src/Signals.cpp index 713585c60..94a4e3be5 100644 --- a/core/libs/prx/libkernel/System/src/Signals.cpp +++ b/core/libs/prx/libkernel/System/src/Signals.cpp @@ -10,6 +10,8 @@ namespace { using GuestHandler = void (APS5_VABI *)(int); std::atomic handlers[32]{}; static_assert(std::atomic::is_always_lock_free); +std::atomic blockedMask{0}; +static_assert(std::atomic::is_always_lock_free); std::mutex registration; int NativeSignal(int guest) { switch (guest) { @@ -31,10 +33,16 @@ void Dispatch(int native) { // Preserve the guest's persistent registration across CRT delivery. std::signal(native, Dispatch); #endif + if ((blockedMask.load() & (1u << guest)) != 0) return; const auto callback = handlers[guest].load(); if (reinterpret_cast(callback) > 1) callback(guest); } } + +struct GuestSignalSet { + std::uint32_t bits[4]; +}; + extern "C" { GuestHandler APS5_VABI signal_nid_postfix(int guest, GuestHandler handler) { const auto invalid = reinterpret_cast(static_cast(-1)); @@ -58,6 +66,24 @@ int APS5_VABI raise_nid_postfix(int guest) { if (result) *__error_nid_postfix() = 22; return result ? -1 : 0; } +int APS5_VABI _sigprocmask_nid_postfix(int how, const GuestSignalSet* set, GuestSignalSet* previousSet) { + std::lock_guard lock(registration); + if (previousSet != nullptr) { + previousSet->bits[0] = blockedMask.load(); + previousSet->bits[1] = 0; + previousSet->bits[2] = 0; + previousSet->bits[3] = 0; + } + if (set != nullptr) { + switch (how) { + case 1: blockedMask.fetch_or(set->bits[0]); break; + case 2: blockedMask.fetch_and(~set->bits[0]); break; + case 3: blockedMask.store(set->bits[0]); break; + default: throw std::invalid_argument("_sigprocmask: invalid how"); + } + } + return 0; +} } extern "C" { diff --git a/core/libs/prx/libkernel/Time/Time.cpp b/core/libs/prx/libkernel/Time/Time.cpp index aeb9cafb9..7b641b016 100644 --- a/core/libs/prx/libkernel/Time/Time.cpp +++ b/core/libs/prx/libkernel/Time/Time.cpp @@ -92,6 +92,10 @@ int APS5_VABI nanosleep_nid_postfix(const KernelTimespec* rqtp, KernelTimespec* return sceKernelNanosleep(rqtp, rmtp); } +int APS5_VABI _nanosleep_nid_postfix(const KernelTimespec* rqtp, KernelTimespec* rmtp) { + return sceKernelNanosleep(rqtp, rmtp); +} + int APS5_VABI clock_gettime_nid_postfix(int clockId, KernelTimespec* tp) { if (tp == nullptr) { APS5_INVALID_ARG_EX;