Files
AnyPS5/core/libs/prx/libSceLibcInternal/InitOnce.cpp
T
hypermistandClaude Opus 5.5 b3b6e83aca feat(libSceLibcInternal): add the __std_init_once _clr calls
__std_init_once_begin_initialize_clr, __std_init_once_complete_clr and
__std_init_once_link_alternate_names_and_abort were not exported. As in
the PS5 12.00 module, begin moves an idle once object to running and
reports pending, reports done without pending, and waits on the object
while another caller runs; complete marks it done, or idle again for
flag 4, wakes every waiter and returns 1; the third aborts.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RbLgECLQ2bpDM7oe2urGZK
2026-10-21 22:02:40 +13:00

59 lines
1.8 KiB
C++

#include "SceTypes.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"
#include <atomic>
#include <climits>
#include <cstdint>
#include <cstdlib>
extern "C" int APS5_VABI sceKernelSyncOnAddressWait(std::uint32_t* address, std::uint32_t expected, const KernelUseconds* timeout, const char* name);
extern "C" int APS5_VABI sceKernelSyncOnAddressWake(void* address, std::int32_t count);
namespace {
constexpr std::uintptr_t OnceIdle = 0;
constexpr std::uintptr_t OnceRunning = 1;
constexpr std::uintptr_t OnceDone = 2;
constexpr unsigned long InitFailed = 4;
std::atomic<std::uintptr_t>& OnceState(void** once) {
return *reinterpret_cast<std::atomic<std::uintptr_t>*>(once);
}
}
extern "C" {
int APS5_VABI __std_init_once_begin_initialize_clr_nid_postfix(void** once, unsigned long flags, int* pending, void** context) {
(void)flags;
(void)context;
auto& state = OnceState(once);
for (;;) {
std::uintptr_t current = state.load(std::memory_order_acquire);
if (current == OnceIdle) {
if (state.compare_exchange_weak(current, OnceRunning, std::memory_order_acq_rel)) {
*pending = 1;
return 1;
}
continue;
}
if (current == OnceDone) {
*pending = 0;
return 1;
}
sceKernelSyncOnAddressWait(reinterpret_cast<std::uint32_t*>(once), static_cast<std::uint32_t>(OnceRunning), nullptr, nullptr);
}
}
int APS5_VABI __std_init_once_complete_clr_nid_postfix(void** once, unsigned long flags, void* context) {
(void)context;
OnceState(once).store(flags == InitFailed ? OnceIdle : OnceDone, std::memory_order_release);
sceKernelSyncOnAddressWake(once, INT_MAX);
return 1;
}
[[noreturn]] void APS5_VABI __std_init_once_link_alternate_names_and_abort_nid_postfix() {
std::abort();
}
}