mirror of
https://github.com/wiiu-env/WiiUPluginLoaderBackend.git
synced 2026-04-15 13:05:47 -05:00
Simplify ClearDanglingReentPtr
This commit is contained in:
parent
2e5de3e6e7
commit
8b19bcc85b
|
|
@ -1,7 +1,7 @@
|
|||
FROM ghcr.io/wiiu-env/devkitppc:20260225
|
||||
|
||||
COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:reentfix-dev-20260403-5ca1144 /artifacts $DEVKITPRO
|
||||
COPY --from=ghcr.io/wiiu-env/wiiupluginsystem:abifix-dev-20260408-77ab748 /artifacts $DEVKITPRO
|
||||
COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:reentfix-dev-20260410-ae8bf4a /artifacts $DEVKITPRO
|
||||
COPY --from=ghcr.io/wiiu-env/wiiupluginsystem:abifix-dev-20260410-b1ab874 /artifacts $DEVKITPRO
|
||||
COPY --from=ghcr.io/wiiu-env/libfunctionpatcher:20260331 /artifacts $DEVKITPRO
|
||||
COPY --from=ghcr.io/wiiu-env/libmappedmemory:20260331 /artifacts $DEVKITPRO
|
||||
COPY --from=ghcr.io/wiiu-env/libwupsbackend:20260331 /artifacts $DEVKITPRO
|
||||
|
|
|
|||
|
|
@ -190,6 +190,7 @@ WUMS_APPLICATION_STARTS() {
|
|||
|
||||
initLogging();
|
||||
|
||||
// Only call this EXACTLY once per application cycle
|
||||
ClearDanglingReentPtr();
|
||||
|
||||
std::lock_guard lock(gLoadedDataMutex);
|
||||
|
|
|
|||
|
|
@ -277,15 +277,6 @@ DECL_FUNCTION(uint32_t, KiGetAppSymbolName, uint32_t addr, char *buffer, int32_t
|
|||
|
||||
#pragma GCC pop_options
|
||||
|
||||
|
||||
DECL_FUNCTION(uint32_t, SomeExitHook) {
|
||||
// Thats the last thing called in __PPCExit
|
||||
const auto res = real_SomeExitHook();
|
||||
|
||||
MarkReentNodesForDeletion();
|
||||
return res;
|
||||
}
|
||||
|
||||
function_replacement_data_t method_hooks_static[] __attribute__((section(".data"))) = {
|
||||
REPLACE_FUNCTION(GX2SwapScanBuffers, LIBRARY_GX2, GX2SwapScanBuffers),
|
||||
REPLACE_FUNCTION(GX2SetTVBuffer, LIBRARY_GX2, GX2SetTVBuffer),
|
||||
|
|
@ -297,7 +288,6 @@ function_replacement_data_t method_hooks_static[] __attribute__((section(".data"
|
|||
REPLACE_FUNCTION(WPADRead, LIBRARY_PADSCORE, WPADRead),
|
||||
REPLACE_FUNCTION_VIA_ADDRESS(SC17_FindClosestSymbol, 0xfff10218, 0xfff10218),
|
||||
REPLACE_FUNCTION_VIA_ADDRESS(KiGetAppSymbolName, 0xfff0e3a0, 0xfff0e3a0),
|
||||
REPLACE_FUNCTION_VIA_ADDRESS(SomeExitHook, 0x3201C400 + 0x40b4c, 0x101C400 + 0x40b4c),
|
||||
};
|
||||
|
||||
uint32_t method_hooks_static_size __attribute__((section(".data"))) = sizeof(method_hooks_static) / sizeof(function_replacement_data_t);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <coreinit/scheduler.h>
|
||||
#include <coreinit/thread.h>
|
||||
#include <forward_list>
|
||||
#include <unordered_set>
|
||||
#include <wups/reent_internal.h>
|
||||
|
||||
#define __WUPS_CONTEXT_THREAD_SPECIFIC_ID 0
|
||||
|
|
@ -64,24 +65,65 @@ struct __wups_reent_node {
|
|||
OSThreadCleanupCallbackFn savedCleanup;
|
||||
};
|
||||
|
||||
|
||||
namespace {
|
||||
std::vector<__wups_reent_node *> sGlobalNodesCopy;
|
||||
std::unordered_set<__wups_reent_node *> sGlobalNodesSeen;
|
||||
std::vector<__wups_reent_node *> sGlobalNodes;
|
||||
std::recursive_mutex sGlobalNodesMutex;
|
||||
|
||||
void removeNodeFromListsLocked(__wups_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 MarkReentNodesForDeletion() {
|
||||
sGlobalNodesCopy = std::move(sGlobalNodes);
|
||||
}
|
||||
|
||||
void ClearDanglingReentPtr() {
|
||||
for (auto nodeToFree : sGlobalNodesCopy) {
|
||||
std::lock_guard lock(sGlobalNodesMutex);
|
||||
|
||||
DEBUG_FUNCTION_LINE_ERR("Before clean up having %d entries", sGlobalNodes.size());
|
||||
|
||||
// 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, [](__wups_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);
|
||||
}
|
||||
sGlobalNodesCopy.clear();
|
||||
|
||||
// Make to remove it from the "seen" list as well.
|
||||
sGlobalNodesSeen.erase(iterator);
|
||||
return true;
|
||||
});
|
||||
|
||||
DEBUG_FUNCTION_LINE_ERR("After clean up having %d entries", sGlobalNodes.size());
|
||||
}
|
||||
|
||||
static void __wups_thread_cleanup(OSThread *thread, void *stack) {
|
||||
|
|
@ -104,10 +146,7 @@ static void __wups_thread_cleanup(OSThread *thread, void *stack) {
|
|||
curr->cleanupFn(curr->reentPtr);
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard lock(sGlobalNodesMutex);
|
||||
std::erase(sGlobalNodes, curr);
|
||||
}
|
||||
removeNodeFromListsLocked(curr);
|
||||
|
||||
free(curr);
|
||||
curr = next;
|
||||
|
|
@ -299,11 +338,10 @@ void ClearReentDataForPlugins(const std::vector<PluginContainer> &plugins) {
|
|||
if (nodeToFree->cleanupFn) {
|
||||
nodeToFree->cleanupFn(nodeToFree->reentPtr);
|
||||
}
|
||||
|
||||
removeNodeFromListsLocked(nodeToFree);
|
||||
free(nodeToFree);
|
||||
{
|
||||
std::lock_guard lock(sGlobalNodesMutex);
|
||||
std::erase(sGlobalNodes, nodeToFree);
|
||||
}
|
||||
|
||||
nodeToFree = nextNode;
|
||||
}
|
||||
wups_backend_restore_head(oldHead);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,4 @@ bool wups_backend_register_context(const void *pluginId, void *reentPtr, void (*
|
|||
|
||||
void ClearReentDataForPlugins(const std::vector<PluginContainer> &plugins);
|
||||
|
||||
void MarkReentNodesForDeletion();
|
||||
|
||||
void ClearDanglingReentPtr();
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user