Skip to content
Open
Show file tree
Hide file tree
Changes from 72 commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
a23af5d
chore(libkernel): compose released-thread handle prerequisite
Felipebmaitan Oct 27, 2026
0fbaef4
feat(libkernel): cancel blocked POSIX reads safely
Felipebmaitan Oct 27, 2026
23dba78
fix(libkernel): preserve read validation and partial receive progress
Felipebmaitan Oct 27, 2026
857c3e8
fix(libkernel): preserve descriptor ownership during cancellable reads
Felipebmaitan Oct 27, 2026
c63fba6
fix(libkernel): preserve stream locking and bounded descriptor state
Felipebmaitan Oct 27, 2026
686ae27
chore(libkernel): integrate current main for read cancellation
Felipebmaitan Oct 27, 2026
a39219f
chore(libkernel): compose current read lifetime prerequisite
Felipebmaitan Oct 27, 2026
3f3f324
fix(libkernel): retain zero-length receives and append handles
Felipebmaitan Oct 27, 2026
7177d3a
chore(libkernel): compose stdio descriptor lifetime prerequisite
Felipebmaitan Oct 27, 2026
5550769
chore(libkernel): record incremental read review base
Felipebmaitan Oct 27, 2026
2eee76f
chore(libkernel): compose read lifetime prerequisites
Felipebmaitan Oct 27, 2026
6a95e13
fix(libkernel): release read ownership before asynchronous signal han…
Felipebmaitan Oct 27, 2026
82c9029
chore(libkernel): integrate current main before signal review
Felipebmaitan Oct 27, 2026
cad3634
test(libkernel): bound signal delivery coverage and check I/O startup…
Felipebmaitan Oct 27, 2026
35d1e6f
chore(libkernel): compose current read cancellation prerequisites
Felipebmaitan Oct 27, 2026
faf62ef
chore(libkernel): record updated read cancellation review base
Felipebmaitan Oct 27, 2026
f30678f
chore(libkernel): compose updated read cancellation prerequisites
Felipebmaitan Oct 27, 2026
6de6c5b
fix(libkernel): preserve I/O delivery across user contexts
Felipebmaitan Oct 27, 2026
0e45e49
chore(libkernel): integrate current read cancellation prerequisites
Felipebmaitan Oct 27, 2026
5cfba81
fix(libkernel): identify suspended I/O contexts without stack registries
Felipebmaitan Oct 27, 2026
cf6dbf6
chore(libkernel): compose current publication prerequisites
Felipebmaitan Oct 27, 2026
4e5cd17
test(libkernel): verify restarting handlers that change errno
Felipebmaitan Oct 27, 2026
e93539c
chore(libkernel): integrate current publication prerequisites
Felipebmaitan Oct 27, 2026
24c755f
chore(libkernel): integrate current main for close review
Felipebmaitan Oct 27, 2026
0403250
fix(libkernel): wake admitted POSIX reads before closing
Felipebmaitan Oct 27, 2026
fdd4ba3
fix(libkernel): handle mixed close and pre-call interruption errors
Felipebmaitan Oct 27, 2026
bcf5df1
docs(libkernel): clarify remaining close limitations concisely
Felipebmaitan Oct 27, 2026
f1bfb9b
chore(libkernel): compose blocking-write prerequisites
Felipebmaitan Oct 27, 2026
12f084e
chore(libkernel): prepare the read prerequisite review base
Felipebmaitan Oct 27, 2026
eebaac5
fix(libkernel): retain I/O signal state through native thread teardown
Felipebmaitan Oct 27, 2026
4527224
fix(libc): preserve descriptor coordination across patched libraries
Felipebmaitan Oct 27, 2026
8c68efe
chore(libkernel): refresh reviewed reads with current main
Felipebmaitan Oct 27, 2026
21d5a97
chore: integrate current main for posix-io-cancellation-reads
Felipebmaitan Oct 28, 2026
06036bf
chore(libkernel): compose read cancellation with current main
Felipebmaitan Oct 29, 2026
3b0d2c6
fix(libkernel): retain renamed kqueue checks in read wrappers
Felipebmaitan Oct 29, 2026
5f6d8e8
chore(libkernel): refresh cancellation reads against main
Felipebmaitan Oct 29, 2026
cb4335c
test(libkernel): force stream close lock interleavings
Felipebmaitan Oct 29, 2026
654ba49
chore: compose thread prerequisite review base
Felipebmaitan Oct 29, 2026
e5e1732
chore: compose read prerequisite review base
Felipebmaitan Oct 29, 2026
bc9022d
test(libkernel): check POSIX admission while a stream close waits
Felipebmaitan Oct 29, 2026
f1d9305
chore(libkernel): record the composed prerequisite comparison base
Felipebmaitan Oct 29, 2026
543e97b
Merge remote-tracking branch 'origin/main' into reference/posix-reads…
Felipebmaitan Oct 29, 2026
15a594b
Merge branch 'reference/posix-reads-composed-base' into feat/posix-re…
Felipebmaitan Oct 29, 2026
55161f9
test(libkernel): await readable data before nonblocking receive races
Felipebmaitan Oct 30, 2026
ccc7482
Merge commit 'refs/pull/12149/head' of https://github.com/boykopovar/…
Felipebmaitan Oct 31, 2026
078a861
chore: merge current main into read cancellation stack
Felipebmaitan Oct 31, 2026
75147ee
fix(libc): restore I/O contexts through underscore jumps
Felipebmaitan Oct 31, 2026
90f1c5f
chore: compose current main and read prerequisites
Felipebmaitan Oct 31, 2026
0e88eee
chore: record exact reads prerequisite comparison
Felipebmaitan Oct 31, 2026
8fdab41
chore: compose underscore jumps as read prerequisite
Felipebmaitan Oct 31, 2026
4888011
chore(libkernel): integrate current main into cancellation reads
Felipebmaitan Nov 1, 2026
a84b9bd
chore(libkernel): compose macOS prerequisite before cancellation reads
Felipebmaitan Nov 1, 2026
8b74140
Merge commit 'refs/io-feedback/pr-12149' into HEAD
Felipebmaitan Nov 1, 2026
8af4225
fix(libkernel): bound I/O retries and shard descriptor ownership
Felipebmaitan Nov 1, 2026
98e9567
chore: compose main into cancellation comparison prerequisites
Felipebmaitan Nov 1, 2026
56ca395
chore: compose macOS and underscore-jump prerequisite heads
Felipebmaitan Nov 1, 2026
00dedbf
chore: record refreshed reads prerequisite comparison
Felipebmaitan Nov 1, 2026
274fd6f
chore: compose macOS and underscore-jump prerequisite heads
Felipebmaitan Nov 1, 2026
5d01e01
test(libkernel): drain the interrupted native-entry control before re…
Felipebmaitan Nov 1, 2026
ce73e60
Merge commit 'refs/pr/base' into HEAD
Felipebmaitan Nov 1, 2026
327cb8a
chore: record current reads comparison ancestor
Felipebmaitan Nov 1, 2026
af9cd6d
chore: record current main in comparison prerequisites
Felipebmaitan Nov 1, 2026
c155f5f
fix(libkernel): integrate main and retain Windows drain coverage
Felipebmaitan Nov 2, 2026
b0b8c21
chore: record integrated reads comparison ancestry
Felipebmaitan Nov 2, 2026
6fd8146
chore: compose current main and declared I/O prerequisites
Felipebmaitan Nov 2, 2026
acd2259
chore: integrate current main into read cancellation
Felipebmaitan Nov 3, 2026
97a5bb6
chore: compose current main and read comparison prerequisites
Felipebmaitan Nov 3, 2026
da29e64
chore: retain current read comparison ancestry
Felipebmaitan Nov 3, 2026
32169af
docs(libkernel): keep composed context debt concise
Felipebmaitan Nov 3, 2026
7d9ebe6
fix(libkernel): integrate main and document cancelling caller limits
Felipebmaitan Nov 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions core/libs/prx/libSceLibcInternal/UserContext.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
#include "prx/libkernel/include/Api.hpp"
#include "prx/libSceLibcInternal/include/Api.hpp"
#include "prx/libc/include/GuestStacks.hpp"
#include "prx/libc/include/JumpBuffer.hpp"
#include "prx/libc/include/Shutdown.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"
#include "prx/libkernel/System/include/UserContext.hpp"
#include <cstdarg>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>

namespace {

Expand Down Expand Up @@ -98,6 +100,8 @@ void APS5_VABI makecontext_nid_postfix(UserUcontext* context, void (APS5_VABI* s
machine.rbx = reinterpret_cast<std::uint64_t>(stack);
machine.rsp = reinterpret_cast<std::uint64_t>(stack);
machine.rip = reinterpret_cast<std::uint64_t>(&Aps5MakecontextStart_nid_no_patch);
const auto identity = JumpBuffer::GuestContextCreate_nid_no_patch(machine.rsp);
std::memcpy(machine.spare, &identity, sizeof(identity));
GuestStacks::GuestStackRegister_nid_no_patch(context->stackPointer, context->stackSize);
}

Expand Down
2 changes: 1 addition & 1 deletion core/libs/prx/libSceNet/Export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1129,14 +1129,14 @@ int APS5_VABI sceNetSocketClose(int s) {
if (!GuestSocketIsOpen_nid_no_patch(s)) return fail(NET_EBADF);
return close_nid_postfix(s) == 0 ? 0 : fail(*__error_nid_postfix());
}
KernelReleaseSocketNumber_nid_no_patch(s);
if (native) {
#ifdef _WIN32
::shutdown(native->value, SD_BOTH);
#else
::shutdown(native->value, SHUT_RDWR);
#endif
}
KernelReleaseSocketNumber_nid_no_patch(s);
g_cv.NotifyAll();
return 0;
}
Expand Down
1 change: 1 addition & 0 deletions core/libs/prx/libc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ target_sources(libc PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src/FileAndHeap.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/HostErrno.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/FileLock.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/DescriptorAccess.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/StdioExtras.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/StandardStreams.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/StreamPurge.cpp
Expand Down
3 changes: 3 additions & 0 deletions core/libs/prx/libc/include/Api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "prx/libc/include/GuestDirectory.hpp"
#include "prx/libc/include/GuestErrno.hpp"
#include "prx/libc/include/FileStream.hpp"
#include "prx/libc/include/JumpBuffer.hpp"
#include "prx/libc/include/exceptions/Unwind.hpp"
#include "prx/libc/include/exceptions/Runtime.hpp"
#include "prx/libc/include/LegacySignals.hpp"
Expand Down Expand Up @@ -1576,6 +1577,8 @@ int APS5_VABI dl_iterate_phdr_nid_postfix(int (*callback)(dl_phdr_info*, std::si

[[gnu::returns_twice]] int APS5_VABI setjmp_nid_postfix(std::uint64_t* buffer);
[[noreturn]] void APS5_VABI longjmp_nid_postfix(std::uint64_t* buffer, int value);
[[gnu::returns_twice]] int APS5_VABI _setjmp_nid_postfix(std::uint64_t* buffer);
[[noreturn]] void APS5_VABI _longjmp_nid_postfix(std::uint64_t* buffer, int value);

std::uint8_t APS5_VABI __atomic_load_1_nid_postfix(const volatile std::uint8_t* target, int);
std::uint16_t APS5_VABI __atomic_load_2_nid_postfix(const volatile std::uint16_t* target, int);
Expand Down
123 changes: 123 additions & 0 deletions core/libs/prx/libc/include/DescriptorAccess.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#ifndef CORE_LIBS_PRX_LIBC_INCLUDE_DESCRIPTORACCESS_HPP
#define CORE_LIBS_PRX_LIBC_INCLUDE_DESCRIPTORACCESS_HPP

#include <memory>
#include <mutex>
#include <cstdint>
#include <atomic>

extern "C" {
void FileStreamSetCloseHookForTest_nid_no_patch(void (*hook)(int, int));
bool FileStreamCloseHookActive_nid_no_patch();
void FileStreamCloseEventForTest_nid_no_patch(int descriptor, int event);
void DescriptorAccessInitialize_nid_no_patch(void* access, int descriptor);
void DescriptorAccessLock_nid_no_patch(void* access);
bool DescriptorAccessTryLock_nid_no_patch(void* access);
void DescriptorAccessUnlock_nid_no_patch(void* access);
bool DescriptorAccessReadOrWait_nid_no_patch(void* access);
void DescriptorAccessWake_nid_no_patch(void* access) noexcept;
bool DescriptorVersionUnchanged_nid_no_patch(const void* version);
void DescriptorAccessSnapshot_nid_no_patch(const void* access, void* version);
void DescriptorOperationInitialize_nid_no_patch(void* operation, void* access);
void DescriptorOperationDestroy_nid_no_patch(void* operation);
bool DescriptorOperationInterrupted_nid_no_patch();
void DescriptorWakeInitialize_nid_no_patch(void* registration);
void DescriptorWakeDestroy_nid_no_patch(void* registration);
}

class GuestDescriptorAccess {
struct State;
public:
class Version {
public:
bool Unchanged() const { return DescriptorVersionUnchanged_nid_no_patch(this); }
private:
friend class GuestDescriptorAccess;
friend bool DescriptorVersionUnchanged_nid_no_patch(const void* version);
friend void DescriptorAccessSnapshot_nid_no_patch(const void* access, void* version);
Version() = default;
std::shared_ptr<State> state;
std::uint64_t value = 0;
};
enum class Mode { Read, Change, Update, Close };
class Operation {
public:
explicit Operation(GuestDescriptorAccess& access) { DescriptorOperationInitialize_nid_no_patch(this, &access); }
~Operation() { DescriptorOperationDestroy_nid_no_patch(this); }
Operation(const Operation&) = delete;
Operation& operator=(const Operation&) = delete;
bool Interrupted() const { return interrupted.load(); }
static bool CurrentInterrupted() { return DescriptorOperationInterrupted_nid_no_patch(); }
class WakeRegistration {
public:
WakeRegistration(void (*interrupt)(void*) noexcept, void* argument)
: interrupt(interrupt), argument(argument) { DescriptorWakeInitialize_nid_no_patch(this); }
~WakeRegistration() { DescriptorWakeDestroy_nid_no_patch(this); }
WakeRegistration(const WakeRegistration&) = delete;
WakeRegistration& operator=(const WakeRegistration&) = delete;
private:
friend class Operation;
friend void DescriptorWakeInitialize_nid_no_patch(void* registration);
friend void DescriptorWakeDestroy_nid_no_patch(void* registration);
WakeRegistration* previous = nullptr;
Operation* operation = nullptr;
void (*interrupt)(void*) noexcept;
void* argument;
};
private:
friend struct State;
friend void DescriptorOperationInitialize_nid_no_patch(void* operation, void* access);
friend void DescriptorOperationDestroy_nid_no_patch(void* operation);
friend bool DescriptorOperationInterrupted_nid_no_patch();
friend void DescriptorWakeInitialize_nid_no_patch(void* registration);
friend void DescriptorWakeDestroy_nid_no_patch(void* registration);
static thread_local Operation* current;
std::shared_ptr<State> state;
Operation* previous = nullptr;
WakeRegistration* wake = nullptr;
std::atomic<bool> interrupted{false};
void Interrupt() noexcept;
};
GuestDescriptorAccess(int descriptor, Mode mode)
: GuestDescriptorAccess(descriptor, mode, std::defer_lock) { Lock(); }
GuestDescriptorAccess(int descriptor, Mode mode, std::defer_lock_t)
: mode(mode) { DescriptorAccessInitialize_nid_no_patch(this, descriptor); }
~GuestDescriptorAccess() { if (held) Unlock(); }
GuestDescriptorAccess(const GuestDescriptorAccess&) = delete;
GuestDescriptorAccess& operator=(const GuestDescriptorAccess&) = delete;
void Lock() { DescriptorAccessLock_nid_no_patch(this); }
bool TryLock() { return DescriptorAccessTryLock_nid_no_patch(this); }
void Unlock() { DescriptorAccessUnlock_nid_no_patch(this); }
bool ReadOrWait() { return DescriptorAccessReadOrWait_nid_no_patch(this); }
void Wake() noexcept { DescriptorAccessWake_nid_no_patch(this); }
Version Snapshot() const {
Version result;
DescriptorAccessSnapshot_nid_no_patch(this, &result);
return result;
}
static void LockTogether(GuestDescriptorAccess& first, GuestDescriptorAccess& second) {
struct Lockable {
GuestDescriptorAccess& access;
void lock() { access.Lock(); }
bool try_lock() { return access.TryLock(); }
void unlock() { access.Unlock(); }
} firstLock{first}, secondLock{second};
std::lock(firstLock, secondLock);
}

private:
friend void DescriptorAccessInitialize_nid_no_patch(void* access, int descriptor);
friend void DescriptorAccessLock_nid_no_patch(void* access);
friend bool DescriptorAccessTryLock_nid_no_patch(void* access);
friend void DescriptorAccessUnlock_nid_no_patch(void* access);
friend bool DescriptorAccessReadOrWait_nid_no_patch(void* access);
friend void DescriptorAccessWake_nid_no_patch(void* access) noexcept;
friend void DescriptorAccessSnapshot_nid_no_patch(const void* access, void* version);
friend void DescriptorOperationInitialize_nid_no_patch(void* operation, void* access);
static std::shared_ptr<State> Get(int descriptor);
std::shared_ptr<State> state;
Mode mode;
bool held = false;
};

#endif
61 changes: 57 additions & 4 deletions core/libs/prx/libc/include/FileStream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <cstdint>
#include <cstddef>
#include <type_traits>
#include "prx/libc/include/DescriptorAccess.hpp"
#ifdef _WIN32
#include <io.h>
#include "prx/libc/include/FileLock.hpp"
Expand Down Expand Up @@ -43,9 +44,9 @@ class ClosingDescriptor {
public:
ClosingDescriptor([[maybe_unused]] std::FILE* stream, int descriptor)
#ifdef _WIN32
: _stream(stream), _closing(BeginClosingDescriptor_nid_no_patch(descriptor)) {}
: _stream(stream), _access(descriptor, GuestDescriptorAccess::Mode::Change), _closing(BeginClosingDescriptor_nid_no_patch(descriptor)) {}
#else
: _closing(BeginClosingDescriptor_nid_no_patch(descriptor)) {}
: _access(descriptor, GuestDescriptorAccess::Mode::Change), _closing(BeginClosingDescriptor_nid_no_patch(descriptor)) {}
#endif
~ClosingDescriptor() { EndClosingDescriptor_nid_no_patch(_closing); }
ClosingDescriptor(const ClosingDescriptor&) = delete;
Expand All @@ -61,6 +62,7 @@ class ClosingDescriptor {
std::FILE* stream;
} _stream;
#endif
GuestDescriptorAccess _access;
void* _closing;
};

Expand Down Expand Up @@ -89,7 +91,53 @@ static constexpr const char* FOPEN_MSG_OPEN_FAILED = "open failed";
extern "C" int KeepHostStandardError_nid_no_patch();
#endif

extern "C" bool TryLockNativeStream_nid_no_patch(std::FILE* stream);

class FileStream {
class NativeLock {
std::FILE* handle;
public:
explicit NativeLock(std::FILE* handle, bool closing = false) : handle(handle) {
if (!handle) return;
if (closing && FileStreamCloseHookActive_nid_no_patch()) {
#ifdef _WIN32
const bool acquired = TryLockNativeStream_nid_no_patch(handle);
const int descriptor = ::_fileno(handle);
#else
const bool acquired = ::ftrylockfile(handle) == 0;
const int descriptor = ::fileno(handle);
#endif
FileStreamCloseEventForTest_nid_no_patch(descriptor, acquired ? 3 : 2);
if (acquired) return;
}
#ifdef _WIN32
::_lock_file(handle);
#else
::flockfile(handle);
#endif
}
~NativeLock() {
if (!handle) return;
#ifdef _WIN32
::_unlock_file(handle);
#else
::funlockfile(handle);
#endif
}
NativeLock(const NativeLock&) = delete;
NativeLock& operator=(const NativeLock&) = delete;
void Forget() { handle = nullptr; }
void Retain(std::FILE* value) { handle = value; }
int Close() {
#ifdef _WIN32
const int result = ::_fclose_nolock(handle);
::_unlock_file(std::exchange(handle, nullptr));
return result;
#else
return std::fclose(std::exchange(handle, nullptr));
#endif
}
};
// Only the macro-accessed FreeBSD prefix is exposed. The remaining guest
// FILE area is reserved; host state lives beyond it and is never a guest FILE*.
GuestFilePrefix _guest{};
Expand Down Expand Up @@ -217,6 +265,7 @@ class FileStream {
return Adopt(open(filename, mode));
}
auto* previous = GetHandle();
NativeLock streamLock(previous, true);
_guest = {};
guestError = false;
randomDevice = false;
Expand All @@ -234,7 +283,7 @@ class FileStream {
if (open && !filename.empty()) {
if (!IsHostStandard()) {
_handle = nullptr;
std::fclose(previous);
streamLock.Close();
closing.reset();
_handle = open(filename, mode);
} else {
Expand Down Expand Up @@ -275,10 +324,13 @@ class FileStream {
KeepStandardHandle_nid_no_patch(replaced, standard);
#else
if (::fileno(previous) == 2) KeepHostStandardError_nid_no_patch();
const bool hostStandard = IsHostStandard();
const ClosingDescriptor closing(previous, ::fileno(previous));
const int kept = IsHostStandard() ? DuplicateHostDescriptor_nid_no_patch(::fileno(previous)) : -1;
if (kept >= 0) ::flockfile(previous);
if (!hostStandard) streamLock.Forget();
_handle = std::freopen(filename.c_str(), mode, previous);
if (!hostStandard && _handle) streamLock.Retain(_handle);
if (kept >= 0) RestoreHostStandard(previous, kept);
#endif
return Adopt(_handle);
Expand Down Expand Up @@ -438,14 +490,15 @@ class FileStream {

int Close() {
GetHandle();
NativeLock streamLock(_handle, true);
#ifdef _WIN32
GuestFileLockForget_nid_no_patch(::_fileno(_handle));
if (std::exchange(directory, false)) ForgetDirectoryStream_nid_no_patch(::_fileno(_handle));
const ClosingDescriptor closing(_handle, ::_fileno(_handle));
#else
const ClosingDescriptor closing(_handle, ::fileno(_handle));
#endif
const int result = std::fclose(_handle);
const int result = streamLock.Close();
_handle = nullptr;
_guest.flags = 0;
_guest.descriptor = -1;
Expand Down
30 changes: 29 additions & 1 deletion core/libs/prx/libc/include/HostThreadLocal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,40 @@
#include <stdexcept>
#ifdef _WIN32
#include <windows.h>
#include <atomic>
#endif

#ifdef _WIN32
template<typename TValue, typename TTag>
class HostThreadLocalSlot {
public:
static DWORD Get() {
static const DWORD slot = [] {
const DWORD created = FlsAlloc(+[](void* value) { delete static_cast<TValue*>(value); });
published.store(created, std::memory_order_release);
return created;
}();
return slot;
}
static TValue* Find() {
const DWORD slot = published.load(std::memory_order_acquire);
if (slot == FLS_OUT_OF_INDEXES) return nullptr;
const DWORD saved = GetLastError();
auto* value = static_cast<TValue*>(FlsGetValue(slot));
SetLastError(saved);
return value;
}
private:
static inline std::atomic<DWORD> published{FLS_OUT_OF_INDEXES};
};
template<typename TValue, typename TTag>
TValue* FindHostThreadLocal() { return HostThreadLocalSlot<TValue, TTag>::Find(); }
#endif

template<typename TValue, typename TTag>
TValue& HostThreadLocal() {
#ifdef _WIN32
static const DWORD slot = FlsAlloc(+[](void* value) { delete static_cast<TValue*>(value); });
const DWORD slot = HostThreadLocalSlot<TValue, TTag>::Get();
if (slot == FLS_OUT_OF_INDEXES) throw std::runtime_error("host thread-local slot allocation failed");
auto* value = static_cast<TValue*>(FlsGetValue(slot));
if (value == nullptr) {
Expand Down
20 changes: 20 additions & 0 deletions core/libs/prx/libc/include/JumpBuffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,34 @@
#define CORE_LIBS_PRX_LIBC_INCLUDE_JUMPBUFFER_HPP

#include "prx/libc/include/general/VabiMacros.hpp"
#include <cstdint>

namespace JumpBuffer {

using Sigprocmask = int (APS5_VABI*)(int how, const void* set, void* previousSet);
using StackRestore = void (*)(std::uintptr_t stack, std::uint32_t context);

struct Context {
std::uintptr_t stack;
std::uint32_t identity;
std::uint32_t signature;
};

static_assert(sizeof(Context) == 16);

extern "C" {

void GuestSigprocmaskRegister_nid_no_patch(Sigprocmask sigprocmask);
void GuestIoJumpRegister_nid_no_patch(StackRestore restore);
std::uint32_t GuestContextCurrent_nid_no_patch();
void GuestContextSet_nid_no_patch(std::uint32_t context);
Context GuestContextCapture_nid_no_patch(std::uintptr_t stack);
Context GuestContextCreate_nid_no_patch(std::uintptr_t stack);
std::uint32_t GuestContextIdentify_nid_no_patch(const Context& context, std::uintptr_t stack);
void APS5_VABI JumpBufferSaveContext_nid_no_patch(unsigned char* buffer);
void APS5_VABI JumpBufferSaveMask_nid_no_patch(unsigned char* buffer);
void APS5_VABI JumpBufferRestoreMask_nid_no_patch(const unsigned char* buffer);
void APS5_VABI GuestIoStackRestore_nid_no_patch(std::uintptr_t stack, std::uint32_t context);

}

Expand Down
Loading
Loading