feat(libkernel): impl file, time, process, signal for posix

This commit is contained in:
boykopovar 2026-09-26 18:35:20 +03:00
parent 62c16792ff
commit 13c648bebb
9 changed files with 227 additions and 95 deletions

View File

@ -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

View File

@ -2,11 +2,23 @@
#include <cstddef>
#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 <cerrno>
#include <cstdarg>
#include <string>
#ifdef _WIN32
#include <io.h>
#include <direct.h>
static int NativeRmdir(const std::filesystem::path& path) {
return ::_wrmdir(path.wstring().c_str());
}
#else
#include <unistd.h>
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<std::uint16_t>(__builtin_va_arg(arguments, int));
__builtin_sysv_va_end(arguments);
#else
std::va_list arguments;
va_start(arguments, flags);
mode = static_cast<std::uint16_t>(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);
}
}

View File

@ -2,6 +2,20 @@
#include <cstddef>
#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<std::uint32_t>(result);
if ((error & 0xffff0000u) != 0x80020000u)
throw std::runtime_error("Unexpected SCE rwlock error");
return static_cast<int>(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__);

View File

@ -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

View File

@ -1,4 +1,5 @@
#include "../include/Pthread.hpp"
#include "../include/Rwlock.hpp"
#include "prx/libc/include/General.hpp"
extern "C" {

View File

@ -1,91 +0,0 @@
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
#include <cstddef>
#include <cstdint>
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;
}
}

View File

@ -17,6 +17,7 @@
#include <cerrno>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <limits>
@ -26,6 +27,9 @@
#include <string>
#include <system_error>
#include <vector>
#ifndef _WIN32
#include <sys/resource.h>
#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<std::uint64_t>(time.dwHighDateTime) << 32) | time.dwLowDateTime) / 10ULL;
};
const auto userMicros = toMicros(user);
const auto kernelMicros = toMicros(kernel);
usage->ru_utime.tv_sec = static_cast<std::int64_t>(userMicros / 1000000ULL);
usage->ru_utime.tv_usec = static_cast<std::int64_t>(userMicros % 1000000ULL);
usage->ru_stime.tv_sec = static_cast<std::int64_t>(kernelMicros / 1000000ULL);
usage->ru_stime.tv_usec = static_cast<std::int64_t>(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<std::int64_t>(native.ru_utime.tv_sec);
usage->ru_utime.tv_usec = static_cast<std::int64_t>(native.ru_utime.tv_usec);
usage->ru_stime.tv_sec = static_cast<std::int64_t>(native.ru_stime.tv_sec);
usage->ru_stime.tv_usec = static_cast<std::int64_t>(native.ru_stime.tv_usec);
usage->ru_maxrss = static_cast<std::int64_t>(native.ru_maxrss);
usage->ru_ixrss = static_cast<std::int64_t>(native.ru_ixrss);
usage->ru_idrss = static_cast<std::int64_t>(native.ru_idrss);
usage->ru_isrss = static_cast<std::int64_t>(native.ru_isrss);
usage->ru_minflt = static_cast<std::int64_t>(native.ru_minflt);
usage->ru_majflt = static_cast<std::int64_t>(native.ru_majflt);
usage->ru_nswap = static_cast<std::int64_t>(native.ru_nswap);
usage->ru_inblock = static_cast<std::int64_t>(native.ru_inblock);
usage->ru_oublock = static_cast<std::int64_t>(native.ru_oublock);
usage->ru_msgsnd = static_cast<std::int64_t>(native.ru_msgsnd);
usage->ru_msgrcv = static_cast<std::int64_t>(native.ru_msgrcv);
usage->ru_nsignals = static_cast<std::int64_t>(native.ru_nsignals);
usage->ru_nvcsw = static_cast<std::int64_t>(native.ru_nvcsw);
usage->ru_nivcsw = static_cast<std::int64_t>(native.ru_nivcsw);
#endif
return 0;
}
}

View File

@ -10,6 +10,8 @@ namespace {
using GuestHandler = void (APS5_VABI *)(int);
std::atomic<GuestHandler> handlers[32]{};
static_assert(std::atomic<GuestHandler>::is_always_lock_free);
std::atomic<std::uint32_t> blockedMask{0};
static_assert(std::atomic<std::uint32_t>::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<std::uintptr_t>(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<GuestHandler>(static_cast<std::uintptr_t>(-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" {

View File

@ -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;