Support for WUMS 0.3.6 - implement reent for modules

This commit is contained in:
Maschell 2026-04-10 13:21:08 +02:00
parent f00d4a9dc0
commit b41a83d9bb
8 changed files with 423 additions and 82 deletions

View File

@ -35,50 +35,6 @@ fini_wut() {
__fini_wut_malloc();
}
typedef enum __wut_thread_specific_id {
WUT_THREAD_SPECIFIC_0 = 0,
WUT_THREAD_SPECIFIC_1 = 1,
} __wut_thread_specific_id;
extern void __attribute__((weak)) wut_set_thread_specific(__wut_thread_specific_id id, void *value);
void wut_set_thread_specific(__wut_thread_specific_id id, void *value) {
OSThread *thread;
asm volatile("lwz %0, -0x20(0)"
: "=r"(thread)); // OSGetCurrentThread()
if (thread != NULL) {
if (id == WUT_THREAD_SPECIFIC_0) {
thread->reserved[3] = (uint32_t) value;
} else if (id == WUT_THREAD_SPECIFIC_1) {
thread->reserved[4] = (uint32_t) value;
} else {
OSReport("[WUMSLOADER] wut_set_thread_specific: invalid id\n");
OSFatal("[WUMSLOADER] wut_set_thread_specific: invalid id");
}
} else {
OSReport("[WUMSLOADER] wut_set_thread_specific: invalid thread\n");
OSFatal("[WUMSLOADER] wut_set_thread_specific: invalid thread");
}
struct _reent *__getreent(void) {
return _GLOBAL_REENT;
}
extern void *__attribute__((weak)) wut_get_thread_specific(__wut_thread_specific_id id);
void *wut_get_thread_specific(__wut_thread_specific_id id) {
OSThread *thread;
asm volatile("lwz %0, -0x20(0)"
: "=r"(thread)); // OSGetCurrentThread()
if (thread != NULL) {
if (id == WUT_THREAD_SPECIFIC_0) {
return (void *) thread->reserved[3];
} else if (id == WUT_THREAD_SPECIFIC_1) {
return (void *) thread->reserved[4];
} else {
OSReport("[WUMSLOADER] wut_get_thread_specific: invalid id\n");
OSFatal("[WUMSLOADER] wut_get_thread_specific: invalid id");
}
} else {
OSReport("[WUMSLOADER] wut_get_thread_specific: invalid thread\n");
OSFatal("[WUMSLOADER] wut_get_thread_specific: invalid thread");
}
return NULL;
}

View File

@ -11,6 +11,7 @@
#include "utils/SegmentedTimer.h"
#include "utils/dynamic.h"
#include "utils/logger.h"
#include "utils/reent.h"
#include <coreinit/debug.h>
#include <coreinit/interrupts.h>
@ -101,6 +102,9 @@ void doStart(int argc, char **argv) {
init_wut();
initLogging();
// We must be 100% sure we never call this more than once per application cycle
ClearDanglingReentPtr();
OSReport("Running WUMSLoader " VERSION VERSION_EXTRA "\n");
#ifdef WUMS_ENABLE_PROFILING

View File

@ -4,10 +4,12 @@
#include "ModuleDataPersistence.h"
#include "globals.h"
#include "utils/logger.h"
#include "utils/reent.h"
#include <wums/reent_internal.h>
#include <coreinit/memexpheap.h>
namespace WUMSLoader::Modules::HooksManagement {
namespace {
@ -63,6 +65,8 @@ constexpr std::string_view hookNameToStr(wums_hook_type_t hook) {
return "WUMS_HOOK_CLEAR_ALLOCATED_RPL_MEMORY";
case WUMS_HOOK_INIT_WUT_THREAD:
return "WUMS_HOOK_INIT_WUT_THREAD";
case WUMS_HOOK_INIT_REENT_FUNCTIONS:
return "WUMS_HOOK_INIT_REENT_FUNCTIONS";
}
return "";
}
@ -147,6 +151,23 @@ void CallHook(const ModuleContainer &module, wums_hook_type_t type) {
gCustomRPLAllocatorAllocFn = allocFn;
gCustomRPLAllocatorFreeFn = freeFn;
} else if (type == WUMS_HOOK_INIT_REENT_FUNCTIONS) {
if (module.getMetaInformation().getWUMSVersion() <= WUMSVersion(0, 3, 5)) {
break;
}
wums_loader_init_reent_args_t_ args;
args.version = WUMS_REENT_CUR_API_VERSION;
args.restore_head_ptr = &wums_backend_restore_head;
args.get_context_ptr = &wums_backend_get_context;
args.set_sentinel_ptr = &wums_backend_set_sentinel;
args.add_reent_context_ptr = &wums_backend_register_context;
// clang-format off
((void (*)(wums_loader_init_reent_args_t_))((uint32_t *) func_ptr))(args);
// clang-format on
break;
} else {
DEBUG_FUNCTION_LINE_ERR("#########################################");
DEBUG_FUNCTION_LINE_ERR("#########HOOK NOT IMPLEMENTED %d#########", type);

View File

@ -150,6 +150,7 @@ std::vector<ModuleInfoWithLoadedFileWrapper> OrderModulesMetaByDependencies(std:
}
void CallInitHooksForModule(const ModuleContainer &curModule) {
HooksManagement::CallHook(curModule, WUMS_HOOK_INIT_REENT_FUNCTIONS);
HooksManagement::CallHook(curModule, WUMS_HOOK_INIT_WUT_THREAD);
HooksManagement::CallHook(curModule, WUMS_HOOK_INIT_WUT_MALLOC);
HooksManagement::CallHook(curModule, WUMS_HOOK_INIT_WUT_NEWLIB);

View File

@ -102,6 +102,8 @@ std::optional<ModuleMetaInformation> ModuleMetaInformationFactory::loadModuleMet
moduleInfo.setWUMSVersion(0, 3, 4);
} else if (value == "0.3.5") {
moduleInfo.setWUMSVersion(0, 3, 5);
} else if (value == "0.3.6") {
moduleInfo.setWUMSVersion(0, 3, 6);
} else {
error = MODULE_PARSE_ERROR_INCOMPATIBLE_VERSION;
DEBUG_FUNCTION_LINE_WARN("Ignoring module - Unsupported WUMS version: %.*s.", static_cast<int>(value.length()), value.data());

View File

@ -8,62 +8,61 @@
extern "C" {
#endif
#define LOG_APP_TYPE "M"
#define LOG_APP_NAME "WUMSLoader"
#define LOG_APP_TYPE "M"
#define LOG_APP_NAME "WUMSLoader"
#ifdef __cplusplus
constexpr const char *ConstexprFileName(const char *path) {
const char *file = path;
for (const char *p = path; *p; ++p) {
if (*p == '/' || *p == '\\') {
file = p + 1;
}
}
return file;
}
#define __FILENAME__ ConstexprFileName(__FILE__)
#else
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
#endif
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
#define LOG(LOG_FUNC, FMT, ARGS...) LOG_EX(LOG_FUNC, "", "", FMT, ##ARGS)
#define LOG(LOG_FUNC, FMT, ARGS...) LOG_EX_DEFAULT(LOG_FUNC, "", "", "", FMT, ##ARGS)
#define LOG_EX(LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) \
do { \
LOG_FUNC("[(%s)%18s][%23s]%30s@L%04d: " LOG_LEVEL "" FMT "" LINE_END, LOG_APP_TYPE, LOG_APP_NAME, __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
#define CONSOLE_COLOR_RED "\033[31m"
#define CONSOLE_COLOR_YELLOW "\033[33m"
#define CONSOLE_COLOR_CYAN "\033[36m"
#define CONSOLE_COLOR_RESET "\033[0m"
#define LOG_EX_DEFAULT(LOG_FUNC, LOG_COLOR, LOG_LEVEL, LINE_END, FMT, ARGS...) LOG_EX(__FILENAME__, __FUNCTION__, __LINE__, LOG_FUNC, LOG_COLOR, LOG_LEVEL, LINE_END, FMT, ##ARGS)
#define LOG_EX(FILENAME, FUNCTION, LINE, LOG_FUNC, LOG_COLOR, LOG_LEVEL, LINE_END, FMT, ARGS...) \
do { \
LOG_FUNC(LOG_COLOR "[(%s)%18s][%23s]%30s@L%04d: " LOG_LEVEL "" FMT "" LINE_END, LOG_APP_TYPE, LOG_APP_NAME, FILENAME, FUNCTION, LINE, ##ARGS); \
} while (0)
#ifdef DEBUG
#ifdef VERBOSE_DEBUG
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_VERBOSE_EX(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, WHBLogPrintf, "", "", FMT, ##ARGS);
#else
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_VERBOSE_EX(FMT, ARGS...) while (0)
#endif
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) LOG(WHBLogWritef, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) LOG(WHBLogWritef, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX(WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, CONSOLE_COLOR_RED, "## ERROR## ", CONSOLE_COLOR_RESET, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, CONSOLE_COLOR_YELLOW, "##WARN ## ", CONSOLE_COLOR_RESET, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, CONSOLE_COLOR_CYAN, "##INFO ## ", CONSOLE_COLOR_RESET, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX(WHBLogPrintf, "##WARN ## ", "", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) LOG_EX(OSReport, "##INFO ## ", "\n", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, WHBLogPrintf, CONSOLE_COLOR_RED, "##ERROR## ", CONSOLE_COLOR_RESET, FMT, ##ARGS);
#else
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_VERBOSE_EX(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX(OSReport, "##ERROR## ", "\n", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX(OSReport, "##WARN ## ", "\n", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) LOG_EX(OSReport, "##INFO ## ", "\n", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, CONSOLE_COLOR_RED, "##ERROR## ", CONSOLE_COLOR_RESET "\n", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, CONSOLE_COLOR_YELLOW, "##WARN ## ", CONSOLE_COLOR_RESET "\n", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, CONSOLE_COLOR_CYAN, "##INFO ## ", CONSOLE_COLOR_RESET "\n", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, OSReport, CONSOLE_COLOR_RED, "##ERROR## ", CONSOLE_COLOR_RESET "\n", FMT, ##ARGS);
#endif

View File

@ -0,0 +1,345 @@
#include "reent.h"
#include "globals.h"
#include "logger.h"
#include <wums/reent_internal.h>
#include <coreinit/debug.h>
#include <coreinit/thread.h>
#include <coreinit/memexpheap.h>
#include <cstdlib>
#include <mutex>
#include <vector>
#define __WUMS_CONTEXT_THREAD_SPECIFIC_ID 0
#define WUMS_REENT_ALLOC_SENTINEL ((__wums_reent_node *) 0xFFFFFFFF)
#define WUMS_REENT_NODE_VERSION 1
#define WUMS_REENT_NODE_MAGIC 0x57554D53 // WUMS
void wums_set_thread_specific_ex(const int id, void *value, OSThread *thread) {
if (thread != nullptr) {
if (id == 0) {
thread->reserved[1] = reinterpret_cast<uint32_t>(value);
} else {
OSReport("wums_set_thread_specific: invalid id\n");
OSFatal("wums_set_thread_specific: invalid id");
}
} else {
OSReport("wums_set_thread_specific: invalid thread\n");
OSFatal("wums_set_thread_specific: invalid thread");
}
}
void *wums_get_thread_specific_ex(const int id, const OSThread *thread) {
if (thread != nullptr) {
if (id == 0) {
return reinterpret_cast<void *>(thread->reserved[1]);
} else {
OSReport("wums_get_thread_specific: invalid id\n");
OSFatal("wums_get_thread_specific: invalid id");
}
} else {
OSReport("wums_get_thread_specific: invalid thread\n");
OSFatal("wums_get_thread_specific: invalid thread\n");
}
return nullptr;
}
void wums_set_thread_specific(int id, void *value) {
return wums_set_thread_specific_ex(id, value, OSGetCurrentThread());
}
void *wums_get_thread_specific(int id) {
return wums_get_thread_specific_ex(id, OSGetCurrentThread());
}
struct __wums_reent_node {
uint32_t magic;
uint32_t version;
__wums_reent_node *next;
const void *moduleId;
void *reentPtr; // The ABI payload
void (*cleanupFn)(void *); // The trampoline to clean up the payload
OSThreadCleanupCallbackFn savedCleanup;
};
namespace {
std::unordered_set<__wums_reent_node *> sGlobalNodesSeen;
std::vector<__wums_reent_node *> sGlobalNodes;
std::recursive_mutex sGlobalNodesMutex;
void removeNodeFromListsLocked(__wums_reent_node *curr) {
std::lock_guard lock(sGlobalNodesMutex);
if (const auto it = std::ranges::find(sGlobalNodes, curr); it != sGlobalNodes.end()) {
*it = sGlobalNodes.back();
sGlobalNodes.pop_back();
}
sGlobalNodesSeen.erase(curr);
}
} // namespace
void ClearDanglingReentPtr() {
std::lock_guard lock(sGlobalNodesMutex);
// This function is expected to be called exactly once at the start of each new application cycle.
// It acts as a garbage collector for nodes left behind by the previous application.
// Leftover nodes typically occur when threads are forcefully killed before they can execute
// their cleanup callbacks, or if a thread's cleanup function was wrongly overridden.
//
// Mechanism: Since threads do not survive across application boundaries, any node we
// observe across multiple cycles is guaranteed to be a dangling pointer from a dead thread.
std::erase_if(sGlobalNodes, [](__wums_reent_node *ptr) {
if (ptr == nullptr) {
return true;
}
// Try to register the pointer in our historical "seen" tracker.
auto [iterator, isNewValue] = sGlobalNodesSeen.insert(ptr);
if (isNewValue) {
// If it was newly inserted, it might be a valid node created during the current
// application cycle (e.g., initialized via a hook in an RPL's init function).
// We keep it in the vector for now.
return false;
}
// Otherwise, we have already seen this address in a previous cycle.
// This means the node belongs to a dead thread from an older application.
// It is now safe to execute its payload cleanup and free the memory.
auto *nodeToFree = *iterator;
if (nodeToFree->cleanupFn) {
nodeToFree->cleanupFn(nodeToFree->reentPtr);
}
free(nodeToFree);
// Make to remove it from the "seen" list as well.
sGlobalNodesSeen.erase(iterator);
return true;
});
}
static void __wums_thread_cleanup(OSThread *thread, void *stack) {
auto *head = static_cast<__wums_reent_node *>(wums_get_thread_specific(__WUMS_CONTEXT_THREAD_SPECIFIC_ID));
if (!head || head == WUMS_REENT_ALLOC_SENTINEL || head->magic != WUMS_REENT_NODE_MAGIC) {
return;
}
OSThreadCleanupCallbackFn savedCleanup = head->savedCleanup;
// Set to effective global during free to prevent malloc re-entrancy loops
wums_set_thread_specific(__WUMS_CONTEXT_THREAD_SPECIFIC_ID, WUMS_REENT_ALLOC_SENTINEL);
auto *curr = head;
while (curr) {
__wums_reent_node *next = curr->next;
if (curr->cleanupFn) {
curr->cleanupFn(curr->reentPtr);
}
removeNodeFromListsLocked(curr);
free(curr);
curr = next;
}
wums_set_thread_specific(__WUMS_CONTEXT_THREAD_SPECIFIC_ID, nullptr);
// Chain to previous OS callback
if (savedCleanup) {
savedCleanup(thread, stack);
}
}
void *wums_backend_get_context(const void *moduleId, wums_loader_init_reent_errors_t_ *outError) {
if (!outError) {
OSFatal("Called wums_backend_get_context with error nullptr");
return nullptr;
}
if (!OSGetCurrentThread()) {
*outError = WUMSReent_ERROR_NO_THREAD;
return nullptr;
}
auto *head = static_cast<__wums_reent_node *>(wums_get_thread_specific(__WUMS_CONTEXT_THREAD_SPECIFIC_ID));
if (head == WUMS_REENT_ALLOC_SENTINEL) {
*outError = WUMSReent_ERROR_GLOBAL_REENT_REQUESTED;
return nullptr;
}
if (head && head->magic != WUMS_REENT_NODE_MAGIC) {
*outError = WUMSReent_ERROR_GLOBAL_REENT_REQUESTED;
return nullptr;
}
const __wums_reent_node *curr = head;
while (curr) {
if (curr->version >= 1 && curr->moduleId == moduleId) {
return curr->reentPtr;
}
curr = curr->next;
}
*outError = WUMSReent_ERROR_NONE;
return nullptr;
}
void *wums_backend_set_sentinel() {
auto *head = wums_get_thread_specific(__WUMS_CONTEXT_THREAD_SPECIFIC_ID);
wums_set_thread_specific(__WUMS_CONTEXT_THREAD_SPECIFIC_ID, WUMS_REENT_ALLOC_SENTINEL);
return head;
}
void wums_backend_restore_head(void *oldHead) {
wums_set_thread_specific(__WUMS_CONTEXT_THREAD_SPECIFIC_ID, oldHead);
}
bool wums_backend_register_context(const void *moduleId, void *reentPtr, void (*cleanupFn)(void *), void *oldHeadVoid) {
auto *oldHead = static_cast<__wums_reent_node *>(oldHeadVoid);
auto *newNode = static_cast<__wums_reent_node *>(malloc(sizeof(__wums_reent_node)));
if (!newNode) {
return false;
}
newNode->magic = WUMS_REENT_NODE_MAGIC;
newNode->version = WUMS_REENT_NODE_VERSION;
newNode->next = oldHead;
newNode->moduleId = moduleId;
newNode->reentPtr = reentPtr;
newNode->cleanupFn = cleanupFn;
newNode->savedCleanup = nullptr;
if (oldHead == nullptr || oldHead == WUMS_REENT_ALLOC_SENTINEL || oldHead->magic != WUMS_REENT_NODE_MAGIC || oldHead->version < WUMS_REENT_NODE_VERSION) {
newNode->savedCleanup = OSSetThreadCleanupCallback(OSGetCurrentThread(), &__wums_thread_cleanup);
} else {
newNode->savedCleanup = oldHead->savedCleanup;
oldHead->savedCleanup = nullptr;
}
wums_set_thread_specific(__WUMS_CONTEXT_THREAD_SPECIFIC_ID, newNode);
{
std::lock_guard lock(sGlobalNodesMutex);
sGlobalNodes.push_back(newNode);
}
return true;
}
/*
void ClearReentDataForModules(const std::vector<WUMSLoader::Modules::ModuleContainer> &modules) {
auto *curThread = OSGetCurrentThread();
for (const auto &cur : modules) {
if (!cur.isLinkedAndLoaded()) {
continue;
}
if (cur.getMetaInformation().getWUMSVersion() <= WUMSLoader::Modules::WUMSVersion(0, 3, 5)) {
continue;
}
const auto startAddress = cur.getLinkInformation().getStartAddress();
const auto endAddress = cur.getLinkInformation().getEndAddress();
// Zero-allocation deferred free list
__wums_reent_node *deferredFreeHead = nullptr;
struct PendingRestore {
OSThread *thread;
OSThreadCleanupCallbackFn callback;
};
std::vector<PendingRestore> pendingRestores;
constexpr int PENDING_RESTORES_SIZE = 128;
// Pre-allocate to prevent malloc() from firing while the scheduler is locked!
pendingRestores.reserve(PENDING_RESTORES_SIZE);
{
// Acquire GLOBAL scheduler lock
const int state = OSDisableInterrupts();
__OSLockScheduler(curThread);
OSThread *t = *reinterpret_cast<OSThread **>(0x100567F8);
while (t) {
auto *head = static_cast<__wums_reent_node *>(wums_get_thread_specific_ex(__WUMS_CONTEXT_THREAD_SPECIFIC_ID, t));
// Safety checks with Sentinel/Magic
if (!head || head == WUMS_REENT_ALLOC_SENTINEL || head->magic != WUMS_REENT_NODE_MAGIC) {
t = t->activeLink.next;
continue;
}
__wums_reent_node *prev = nullptr;
auto *curr = head;
while (curr) {
__wums_reent_node *next = curr->next;
auto moduleIdAddr = reinterpret_cast<uint32_t>(curr->moduleId);
// module id lives in the .data/.bss section of a module
if (moduleIdAddr >= startAddress && moduleIdAddr < endAddress) {
// remove from linked list
if (prev) {
prev->next = next;
} else {
head = next;
if (curr->savedCleanup) {
if (head) {
head->savedCleanup = curr->savedCleanup;
} else {
// No WUMS nodes left, mark for restoring.
if (pendingRestores.size() == PENDING_RESTORES_SIZE) {
OSFatal("WUMSBackend pendingRestores size limit hit");
}
pendingRestores.push_back({t, curr->savedCleanup});
}
}
}
curr->next = deferredFreeHead;
deferredFreeHead = curr;
} else {
prev = curr;
}
curr = next;
}
// Restore the updated head to the thread
wums_set_thread_specific_ex(__WUMS_CONTEXT_THREAD_SPECIFIC_ID, head, t);
t = t->activeLink.next;
}
__OSUnlockScheduler(curThread);
OSRestoreInterrupts(state);
}
for (const auto &restore : pendingRestores) {
DEBUG_FUNCTION_LINE_VERBOSE("Set cleanup function for thread %p to %p", restore.thread, restore.callback);
OSSetThreadCleanupCallback(restore.thread, restore.callback);
}
// Free removed entries
auto *oldHead = wums_backend_set_sentinel();
__wums_reent_node *nodeToFree = deferredFreeHead;
while (nodeToFree) {
__wums_reent_node *nextNode = nodeToFree->next;
if (nodeToFree->cleanupFn) {
nodeToFree->cleanupFn(nodeToFree->reentPtr);
}
removeNodeFromListsLocked(nodeToFree);
free(nodeToFree);
nodeToFree = nextNode;
}
wums_backend_restore_head(oldHead);
}
}
*/

View File

@ -0,0 +1,13 @@
#pragma once
#include <wums/reent_internal.h>
void *wums_backend_get_context(const void *pluginId, wums_loader_init_reent_errors_t_ *outError);
void *wums_backend_set_sentinel();
void wums_backend_restore_head(void *oldHead);
bool wums_backend_register_context(const void *pluginId, void *reentPtr, void (*cleanupFn)(void *), void *oldHead);
void ClearDanglingReentPtr();