mirror of
https://github.com/mihawk-99/PS5_RetroArch.git
synced 2026-10-22 00:22:29 -05:00
Beetle PSX HW, Mupen64Plus-Next, Beetle Saturn, VICE x64sc, MAME 0.289, DeSmuME and Azahar, each built from my fork of it at a pinned revision (tools/core-fork.sh, tools/build-<core>.sh), with the PS5 defaults at the most each offers that holds full speed. The loader grew to fit them. A core's file and image come from direct memory, up to 1 GiB (MAME's image is 413 MB), and each image is zeroed when it is reserved: direct memory is not, and a reloaded core's .bss held its predecessor's bytes, which faulted every core on a reload. Each image's .eh_frame is registered with the title's unwinder, for the cores that throw. Initializers are capped at 65,536 (Azahar has 2,476). A load that misses imports lists all of them. Aligned operator new comes from the core heap, a core's atexit belongs to the core, and the imports the new cores need are bound to the platform layer's getcwd, tmpfile, mkstemp and the rest (SDK fork ebd0fe2).
77 lines
2.0 KiB
C++
77 lines
2.0 KiB
C++
/* Core-local C++ destructor ownership. Never register unloadable code with the
|
|
* process-wide atexit list. The native loader executes .fini_array before unmap. */
|
|
#include <cstdlib>
|
|
#include <pthread.h>
|
|
|
|
namespace
|
|
{
|
|
struct Destructor
|
|
{
|
|
void (*callback)(void *);
|
|
void *argument;
|
|
void *dso;
|
|
Destructor *next;
|
|
};
|
|
Destructor *pending = nullptr;
|
|
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
|
|
} // namespace
|
|
|
|
extern "C"
|
|
{
|
|
void *__dso_handle = &__dso_handle;
|
|
|
|
int __cxa_atexit(void (*callback)(void *), void *argument, void *dso)
|
|
{
|
|
auto *entry = static_cast<Destructor *>(std::malloc(sizeof(Destructor)));
|
|
if (!entry)
|
|
return -1;
|
|
entry->callback = callback;
|
|
entry->argument = argument;
|
|
entry->dso = dso;
|
|
pthread_mutex_lock(&lock);
|
|
entry->next = pending;
|
|
pending = entry;
|
|
pthread_mutex_unlock(&lock);
|
|
return 0;
|
|
}
|
|
|
|
void __cxa_finalize(void *dso)
|
|
{
|
|
for (;;)
|
|
{
|
|
pthread_mutex_lock(&lock);
|
|
Destructor **slot = &pending;
|
|
while (*slot && dso && (*slot)->dso != dso)
|
|
slot = &(*slot)->next;
|
|
Destructor *entry = *slot;
|
|
if (entry)
|
|
*slot = entry->next;
|
|
pthread_mutex_unlock(&lock);
|
|
if (!entry)
|
|
break;
|
|
auto callback = entry->callback;
|
|
void *argument = entry->argument;
|
|
std::free(entry);
|
|
callback(argument);
|
|
}
|
|
}
|
|
|
|
/* C's atexit belongs to the core too: a handler on the process-wide list
|
|
* would outlive the module that holds it. */
|
|
static void call_atexit_handler(void *handler)
|
|
{
|
|
reinterpret_cast<void (*)()>(handler)();
|
|
}
|
|
|
|
int atexit(void (*handler)())
|
|
{
|
|
return __cxa_atexit(call_atexit_handler, reinterpret_cast<void *>(handler), &__dso_handle);
|
|
}
|
|
}
|
|
|
|
__attribute__((destructor)) static void finish_core()
|
|
{
|
|
__cxa_finalize(nullptr);
|
|
pthread_mutex_destroy(&lock);
|
|
}
|