mirror of
https://github.com/wiiu-env/WiiUPluginSystem.git
synced 2026-05-20 14:28:03 -05:00
Move reent logic into the wupsbackend
Some checks failed
Publish Docker Image / clang-format-lib (push) Has been cancelled
Publish Docker Image / clang-format-examples (push) Has been cancelled
Publish Docker Image / build-lib (push) Has been cancelled
Publish Docker Image / build-examples (push) Has been cancelled
Publish Docker Image / build-and-push-image (push) Has been cancelled
Some checks failed
Publish Docker Image / clang-format-lib (push) Has been cancelled
Publish Docker Image / clang-format-examples (push) Has been cancelled
Publish Docker Image / build-lib (push) Has been cancelled
Publish Docker Image / build-examples (push) Has been cancelled
Publish Docker Image / build-and-push-image (push) Has been cancelled
This commit is contained in:
parent
fa90de3802
commit
77ab748eb4
|
|
@ -19,6 +19,7 @@
|
|||
#include "common.h"
|
||||
#include <wups/button_combo_internal.h>
|
||||
#include <wups/config.h>
|
||||
#include <wups/reent_internal.h>
|
||||
#include <wups/storage.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
@ -59,10 +60,11 @@ typedef enum wups_loader_hook_type_t {
|
|||
WUPS_LOADER_HOOK_APPLICATION_REQUESTS_EXIT, /* Called when an application wants to exit */
|
||||
WUPS_LOADER_HOOK_APPLICATION_ENDS, /* Called when an application ends */
|
||||
|
||||
WUPS_LOADER_HOOK_INIT_STORAGE, /* Only for internal usage */
|
||||
WUPS_LOADER_HOOK_INIT_CONFIG, /* Only for internal usage */
|
||||
WUPS_LOADER_HOOK_INIT_BUTTON_COMBO, /* Only for internal usage */
|
||||
WUPS_LOADER_HOOK_INIT_WUT_THREAD, /* Only for internal usage */
|
||||
WUPS_LOADER_HOOK_INIT_STORAGE, /* Only for internal usage */
|
||||
WUPS_LOADER_HOOK_INIT_CONFIG, /* Only for internal usage */
|
||||
WUPS_LOADER_HOOK_INIT_BUTTON_COMBO, /* Only for internal usage */
|
||||
WUPS_LOADER_HOOK_INIT_WUT_THREAD, /* Only for internal usage */
|
||||
WUPS_LOADER_HOOK_INIT_REENT_FUNCTIONS, /* Only for internal usage */
|
||||
} wups_loader_hook_type_t;
|
||||
|
||||
typedef struct wups_loader_hook_t {
|
||||
|
|
@ -142,6 +144,14 @@ typedef struct wups_loader_hook_t {
|
|||
return WUPSButtonComboAPI_InitInternal(args); \
|
||||
}
|
||||
|
||||
#define WUPS_INIT_REENT_FUNCTIONS() \
|
||||
__EXTERN_C_MACRO void WUPSReentAPI_InitInternal(wups_loader_init_reent_args_t_); \
|
||||
void wups_init_reent_functions(wups_loader_init_reent_args_t_ args); \
|
||||
WUPS_HOOK_EX(WUPS_LOADER_HOOK_INIT_REENT_FUNCTIONS, wups_init_reent_functions); \
|
||||
void wups_init_reent_functions(wups_loader_init_reent_args_t_ args) { \
|
||||
return WUPSReentAPI_InitInternal(args); \
|
||||
}
|
||||
|
||||
#define WUPS_USE_WUT_MALLOC() \
|
||||
__EXTERN_C_MACRO void __init_wut_malloc(); \
|
||||
void on_init_wut_malloc() { \
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define WUPS_VERSION_STR "0.9.0"
|
||||
#define WUPS_VERSION_STR "0.9.1"
|
||||
#define WUPS_PLUGIN_NAME(__plugin_name) \
|
||||
WUPS_META(name, __plugin_name); \
|
||||
WUPS_META(wups, WUPS_VERSION_STR); \
|
||||
|
|
@ -51,6 +51,7 @@ extern "C" {
|
|||
WUPS___FINI_WRAPPER(); \
|
||||
WUPS_INIT_CONFIG_FUNCTIONS(); \
|
||||
WUPS_INIT_BUTTON_COMBO_FUNCTIONS(); \
|
||||
WUPS_INIT_REENT_FUNCTIONS(); \
|
||||
WUPS_META(buildtimestamp, __DATE__ " " __TIME__); \
|
||||
WUPS_SECTION("meta") \
|
||||
const char wups_meta_plugin_name[] = __plugin_name; \
|
||||
|
|
|
|||
35
include/wups/reent_internal.h
Normal file
35
include/wups/reent_internal.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum wups_loader_init_reent_errors_t_ {
|
||||
WUPSReent_ERROR_NONE = 0,
|
||||
WUPSReent_ERROR_GLOBAL_REENT_REQUESTED = 1,
|
||||
WUPSReent_ERROR_NO_THREAD = 2,
|
||||
} wups_loader_init_reent_errors_t_;
|
||||
|
||||
typedef void *(*WUPSReent_GetReentContext)(const void *pluginId, wups_loader_init_reent_errors_t_ *outError);
|
||||
typedef void *(*WUPSReent_SetSentinel)();
|
||||
typedef void (*WUPSReent_RestoreHead)(void *oldHead);
|
||||
typedef bool (*WUPSReent_AddReentContext)(const void *pluginId, void *reentPtr, void (*cleanupFn)(void *), void *oldHead);
|
||||
|
||||
typedef uint32_t WUPS_REENT_API_VERSION;
|
||||
|
||||
#define WUPS_REENT_CUR_API_VERSION 0x01
|
||||
|
||||
typedef struct wups_loader_init_reent_args_t_ {
|
||||
WUPS_REENT_API_VERSION version;
|
||||
WUPSReent_GetReentContext get_context_ptr;
|
||||
WUPSReent_SetSentinel set_sentinel_ptr;
|
||||
WUPSReent_RestoreHead restore_head_ptr;
|
||||
WUPSReent_AddReentContext add_reent_context_ptr;
|
||||
} wups_loader_init_reent_args_t_;
|
||||
|
||||
void WUPSReentAPI_InitInternal(wups_loader_init_reent_args_t_ args);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -18,4 +18,4 @@ extern const char wups_meta_info_dump[];
|
|||
#define WUPS_DEBUG_REPORT(fmt, ...)
|
||||
#endif
|
||||
|
||||
#define WUPS_DEBUG_WARN(fmt, ...) OSReport("[%s] " fmt, wups_meta_info_dump, ##__VA_ARGS__)
|
||||
#define WUPS_DEBUG_WARN(fmt, ...) OSReport("\033[33m[%s] " fmt "\033[0m", wups_meta_info_dump, ##__VA_ARGS__)
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
#include "wups_reent.h"
|
||||
#include "wups_thread_specific.h"
|
||||
#include <coreinit/debug.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
|
@ -44,16 +45,25 @@ extern "C" struct _reent *__getreent(void) {
|
|||
return __wups_getreent();
|
||||
}
|
||||
|
||||
extern "C" void __attribute__((weak)) wut_set_thread_specific(__wut_thread_specific_id id, void *value);
|
||||
extern const char wups_meta_info_dump[];
|
||||
|
||||
typedef enum __wut_thread_specific_id {
|
||||
WUT_THREAD_SPECIFIC_0 = 0,
|
||||
WUT_THREAD_SPECIFIC_1 = 1,
|
||||
} __wut_thread_specific_id;
|
||||
|
||||
void wut_set_thread_specific(__wut_thread_specific_id id, void *value) {
|
||||
return wups_set_thread_specific(id, value);
|
||||
}
|
||||
|
||||
extern "C" void *__attribute__((weak)) wut_get_thread_specific(__wut_thread_specific_id id);
|
||||
|
||||
void *wut_get_thread_specific(__wut_thread_specific_id id) {
|
||||
return wups_get_thread_specific(id);
|
||||
if ((uint32_t) id == 0x13371337) { // Mechanism to detect if the function was overridden properly
|
||||
return (void *) 0x42424242;
|
||||
}
|
||||
|
||||
OSReport("[%s] wups_get_thread_specific: NOT SUPPORTED\n", wups_meta_info_dump);
|
||||
OSFatal("wups_get_thread_specific: NOT SUPPORTED\n");
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -102,6 +112,8 @@ __assert_func(const char *file,
|
|||
}
|
||||
|
||||
OSFatal(buffer);
|
||||
while (true)
|
||||
;
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,175 +1,103 @@
|
|||
#include "wups_reent.h"
|
||||
#include "wups_thread_specific.h"
|
||||
#include <cstring>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "wups/hooks.h"
|
||||
#include "wups/reent_internal.h"
|
||||
#include "wups/wups_debug.h"
|
||||
#include <coreinit/debug.h>
|
||||
#include <coreinit/thread.h>
|
||||
#include <stdlib.h>
|
||||
#include <wups/wups_debug.h>
|
||||
|
||||
#define __WUPS_CONTEXT_THREAD_SPECIFIC_ID WUT_THREAD_SPECIFIC_0
|
||||
#define WUPS_REENT_ALLOC_SENTINEL ((__wups_reent_node *) 0xFFFFFFFF)
|
||||
|
||||
extern "C" __attribute__((weak)) void wut_set_thread_specific(__wut_thread_specific_id id, void *value);
|
||||
extern "C" __attribute__((weak)) void *wut_get_thread_specific(__wut_thread_specific_id);
|
||||
|
||||
typedef uint32_t OSThread;
|
||||
|
||||
extern "C" void OSFatal(const char *);
|
||||
extern "C" void OSReport(const char *, ...);
|
||||
|
||||
extern "C" OSThread *OSGetCurrentThread();
|
||||
|
||||
typedef void (*OSThreadCleanupCallbackFn)(OSThread *thread, void *stack);
|
||||
|
||||
extern "C" OSThreadCleanupCallbackFn
|
||||
OSSetThreadCleanupCallback(OSThread *thread,
|
||||
OSThreadCleanupCallbackFn callback);
|
||||
|
||||
#define WUPS_REENT_NODE_VERSION 1
|
||||
#define WUPS_REENT_NODE_MAGIC 0x57555053 // WUPS
|
||||
static const int sReentPluginId = 0;
|
||||
|
||||
struct __wups_reent_node {
|
||||
// FIXED HEADER (Never move or change these offsets!)
|
||||
uint32_t magic; // Guarantees this is a __wups_reent_node
|
||||
uint32_t version;
|
||||
__wups_reent_node *next;
|
||||
|
||||
// Node Version 1 Payload
|
||||
const void *pluginId;
|
||||
void *reentPtr;
|
||||
void (*cleanupFn)(__wups_reent_node *);
|
||||
OSThreadCleanupCallbackFn savedCleanup;
|
||||
struct wups_loader_init_reent_args_t {
|
||||
WUPSReent_GetReentContext get_context_ptr = nullptr;
|
||||
WUPSReent_SetSentinel set_sentinel_ptr = nullptr;
|
||||
WUPSReent_RestoreHead restore_head_ptr = nullptr;
|
||||
WUPSReent_AddReentContext add_reent_context_ptr = nullptr;
|
||||
};
|
||||
|
||||
static void reclaim_reent_trampoline(__wups_reent_node *node) {
|
||||
WUPS_DEBUG_REPORT("reclaim_reent_trampoline: Destroying node %p (reent: %p)\n", node, node->reentPtr);
|
||||
static wups_loader_init_reent_args_t __internal_functions = {};
|
||||
|
||||
if (node->reentPtr) {
|
||||
_reclaim_reent(static_cast<_reent *>(node->reentPtr));
|
||||
free(node->reentPtr);
|
||||
void WUPSReentAPI_InitInternal(wups_loader_init_reent_args_t_ args) {
|
||||
if (args.version > WUPS_REENT_CUR_API_VERSION) {
|
||||
OSFatal("Incompatible reent api version");
|
||||
return;
|
||||
}
|
||||
free(node);
|
||||
WUPS_DEBUG_REPORT("WUPSReentAPI_InitInternal: Initializing reent plugin\n");
|
||||
|
||||
__internal_functions.get_context_ptr = args.get_context_ptr;
|
||||
__internal_functions.set_sentinel_ptr = args.set_sentinel_ptr;
|
||||
__internal_functions.add_reent_context_ptr = args.add_reent_context_ptr;
|
||||
__internal_functions.restore_head_ptr = args.restore_head_ptr;
|
||||
}
|
||||
|
||||
static void __wups_thread_cleanup(OSThread *thread, void *stack) {
|
||||
auto *head = static_cast<__wups_reent_node *>(wut_get_thread_specific(__WUPS_CONTEXT_THREAD_SPECIFIC_ID));
|
||||
// use variable in the .data section as unique plugin id
|
||||
static const int sReentPluginId = 0;
|
||||
|
||||
if (!head || head == WUPS_REENT_ALLOC_SENTINEL) {
|
||||
return;
|
||||
}
|
||||
void *wups_backend_get_context(const void *id, wups_loader_init_reent_errors_t_ *outError) {
|
||||
return __internal_functions.get_context_ptr(id, outError);
|
||||
}
|
||||
|
||||
if (head->magic != WUPS_REENT_NODE_MAGIC) {
|
||||
WUPS_DEBUG_WARN("__wups_thread_cleanup: Unexpected node magic word: %08X (expected %08X).\n", head->magic, WUPS_REENT_NODE_MAGIC);
|
||||
return;
|
||||
}
|
||||
void *wups_backend_set_sentinel() {
|
||||
return __internal_functions.set_sentinel_ptr();
|
||||
}
|
||||
|
||||
WUPS_DEBUG_REPORT("__wups_thread_cleanup: Triggered for thread %p\n", thread);
|
||||
void wups_backend_restore_head(void *head) {
|
||||
__internal_functions.restore_head_ptr(head);
|
||||
}
|
||||
|
||||
OSThreadCleanupCallbackFn savedCleanup = nullptr;
|
||||
if (head->version >= 1) {
|
||||
savedCleanup = head->savedCleanup;
|
||||
}
|
||||
bool wups_backend_register_context(const void *pluginId, void *reentPtr, void (*cleanupFn)(void *), void *oldHead) {
|
||||
return __internal_functions.add_reent_context_ptr(pluginId, reentPtr, cleanupFn, oldHead);
|
||||
}
|
||||
|
||||
// Set to effective global during free to prevent malloc re-entrancy loops
|
||||
wut_set_thread_specific(__WUPS_CONTEXT_THREAD_SPECIFIC_ID, WUPS_REENT_ALLOC_SENTINEL);
|
||||
static void reclaim_reent_trampoline(void *payload) {
|
||||
WUPS_DEBUG_REPORT("reclaim_reent_trampoline: Destroying reent payload: %p\n", payload);
|
||||
|
||||
// Safely iterate the ABI-stable list.
|
||||
auto *curr = head;
|
||||
while (curr) {
|
||||
// Read the "next" pointer BEFORE destroying the current node.
|
||||
__wups_reent_node *next = curr->next;
|
||||
|
||||
// Trigger the self-destruct sequence. Frees curr
|
||||
if (curr->cleanupFn) {
|
||||
curr->cleanupFn(curr);
|
||||
}
|
||||
|
||||
curr = next;
|
||||
}
|
||||
|
||||
wut_set_thread_specific(__WUPS_CONTEXT_THREAD_SPECIFIC_ID, nullptr);
|
||||
|
||||
if (savedCleanup) {
|
||||
WUPS_DEBUG_REPORT("__wups_thread_cleanup: Chaining to saved cleanup for thread %p\n", thread);
|
||||
savedCleanup(thread, stack);
|
||||
if (payload) {
|
||||
auto *reentPtr = static_cast<_reent *>(payload);
|
||||
_reclaim_reent(reentPtr);
|
||||
free(reentPtr);
|
||||
}
|
||||
}
|
||||
|
||||
struct _reent *__wups_getreent() {
|
||||
if (!wut_get_thread_specific || !wut_set_thread_specific || OSGetCurrentThread() == nullptr) {
|
||||
if (!OSGetCurrentThread()) {
|
||||
return _GLOBAL_REENT;
|
||||
}
|
||||
|
||||
auto head = static_cast<__wups_reent_node *>(wut_get_thread_specific(__WUPS_CONTEXT_THREAD_SPECIFIC_ID));
|
||||
|
||||
if (head == WUPS_REENT_ALLOC_SENTINEL) {
|
||||
return _GLOBAL_REENT;
|
||||
wups_loader_init_reent_errors_t_ error = WUPSReent_ERROR_NONE;
|
||||
if (void *existingCtx = wups_backend_get_context(&sReentPluginId, &error)) {
|
||||
return static_cast<_reent *>(existingCtx);
|
||||
}
|
||||
switch (error) {
|
||||
case WUPSReent_ERROR_GLOBAL_REENT_REQUESTED:
|
||||
case WUPSReent_ERROR_NO_THREAD:
|
||||
return _GLOBAL_REENT;
|
||||
case WUPSReent_ERROR_NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
if (head && head->magic != WUPS_REENT_NODE_MAGIC) {
|
||||
WUPS_DEBUG_WARN("__wups_getreent: Unexpected node magic word: %08X (expected %08X).\n", head->magic, WUPS_REENT_NODE_MAGIC);
|
||||
return _GLOBAL_REENT;
|
||||
}
|
||||
|
||||
// Check for already allocated reent ptr.
|
||||
// (Intentionally not logging here to prevent console spam on the fast path)
|
||||
const __wups_reent_node *curr = head;
|
||||
while (curr) {
|
||||
// Use a memory address as a unique id
|
||||
if (curr->version >= 1 && curr->pluginId == &sReentPluginId) {
|
||||
return static_cast<_reent *>(curr->reentPtr);
|
||||
}
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
WUPS_DEBUG_REPORT("__wups_getreent: Allocating new context for thread %p\n", OSGetCurrentThread());
|
||||
|
||||
// If not found allocate a new for THIS plugin.
|
||||
// Temporarily effectively use global reent during context allocation
|
||||
wut_set_thread_specific(__WUPS_CONTEXT_THREAD_SPECIFIC_ID, WUPS_REENT_ALLOC_SENTINEL);
|
||||
|
||||
auto *newNode = static_cast<__wups_reent_node *>(malloc(sizeof(__wups_reent_node)));
|
||||
auto *oldHead = wups_backend_set_sentinel();
|
||||
auto *newReent = static_cast<struct _reent *>(malloc(sizeof(struct _reent)));
|
||||
|
||||
if (!newNode || !newReent) {
|
||||
WUPS_DEBUG_WARN("__wups_getreent: Failed to allocate context! Falling back to _GLOBAL_REENT.\n");
|
||||
if (newNode) {
|
||||
free(newNode);
|
||||
}
|
||||
if (newReent) {
|
||||
free(newReent);
|
||||
}
|
||||
// reset on error
|
||||
wut_set_thread_specific(__WUPS_CONTEXT_THREAD_SPECIFIC_ID, head);
|
||||
if (!newReent) {
|
||||
wups_backend_restore_head(oldHead);
|
||||
return _GLOBAL_REENT;
|
||||
}
|
||||
|
||||
WUPS_DEBUG_REPORT("Allocated context! for thread %p: %p\n", OSGetCurrentThread(), newReent);
|
||||
|
||||
_REENT_INIT_PTR(newReent);
|
||||
|
||||
newNode->magic = WUPS_REENT_NODE_MAGIC;
|
||||
newNode->version = WUPS_REENT_NODE_VERSION;
|
||||
newNode->next = head;
|
||||
newNode->pluginId = &sReentPluginId;
|
||||
newNode->reentPtr = newReent;
|
||||
newNode->cleanupFn = reclaim_reent_trampoline;
|
||||
newNode->savedCleanup = nullptr;
|
||||
bool result = wups_backend_register_context(
|
||||
&sReentPluginId,
|
||||
newReent,
|
||||
reclaim_reent_trampoline,
|
||||
oldHead);
|
||||
|
||||
auto oldHead = head;
|
||||
|
||||
// Hook cleanup logic
|
||||
if (oldHead == nullptr) {
|
||||
WUPS_DEBUG_REPORT("__wups_getreent: Hooking OSSetThreadCleanupCallback for thread %p\n", OSGetCurrentThread());
|
||||
newNode->savedCleanup = OSSetThreadCleanupCallback(OSGetCurrentThread(), &__wups_thread_cleanup);
|
||||
} else {
|
||||
WUPS_DEBUG_REPORT("__wups_getreent: Prepending to existing list for thread %p\n", OSGetCurrentThread());
|
||||
// We prepend, so we must inherit the saved cleanup from the previous head
|
||||
if (oldHead->version >= 1) {
|
||||
newNode->savedCleanup = oldHead->savedCleanup;
|
||||
oldHead->savedCleanup = nullptr;
|
||||
}
|
||||
if (!result) {
|
||||
WUPS_DEBUG_WARN("Failed to register context for thread %p\n", OSGetCurrentThread());
|
||||
_reclaim_reent(newReent);
|
||||
free(newReent);
|
||||
wups_backend_restore_head(oldHead);
|
||||
return _GLOBAL_REENT;
|
||||
}
|
||||
|
||||
wut_set_thread_specific(__WUPS_CONTEXT_THREAD_SPECIFIC_ID, newNode);
|
||||
|
||||
return newReent;
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
#include "wups_thread_specific.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern "C" void OSFatal(const char *);
|
||||
extern "C" void OSReport(const char *, ...);
|
||||
|
||||
typedef struct OSThread {
|
||||
uint8_t other[0x68c];
|
||||
void *reserved[5];
|
||||
} OSThread;
|
||||
|
||||
static_assert(offsetof(OSThread, reserved) == 0x68c, "OSThread: \"reserved\" at wrong offset");
|
||||
static_assert(sizeof(OSThread) == 0x6a0, "OSThread: wrong size");
|
||||
|
||||
extern "C" const char wups_meta_info_dump[];
|
||||
|
||||
void wups_set_thread_specific(__wut_thread_specific_id id, void *value) {
|
||||
OSThread *thread;
|
||||
asm volatile("lwz %0, -0x20(0)"
|
||||
: "=r"(thread)); // OSGetCurrentThread()
|
||||
if (thread != nullptr) {
|
||||
if (id == WUT_THREAD_SPECIFIC_0) {
|
||||
thread->reserved[3] = value;
|
||||
} else if (id == WUT_THREAD_SPECIFIC_1) {
|
||||
thread->reserved[4] = value;
|
||||
} else {
|
||||
OSReport("[%s] wups_set_thread_specific: invalid id\n", wups_meta_info_dump);
|
||||
OSFatal("wups_set_thread_specific: invalid id");
|
||||
}
|
||||
} else {
|
||||
OSReport("[%s] wups_set_thread_specific: invalid thread\n", wups_meta_info_dump);
|
||||
OSFatal("wups_set_thread_specific: invalid thread");
|
||||
}
|
||||
}
|
||||
|
||||
void *wups_get_thread_specific(__wut_thread_specific_id id) {
|
||||
OSThread *thread;
|
||||
asm volatile("lwz %0, -0x20(0)"
|
||||
: "=r"(thread)); // OSGetCurrentThread()
|
||||
if (thread != nullptr) {
|
||||
if (id == WUT_THREAD_SPECIFIC_0) {
|
||||
return thread->reserved[3];
|
||||
} else if (id == WUT_THREAD_SPECIFIC_1) {
|
||||
return thread->reserved[4];
|
||||
} else if ((uint32_t) id == 0x13371337) { // Mechanism to detect if the function was overridden properly
|
||||
return (void *) 0x42424242;
|
||||
} else {
|
||||
OSReport("[%s] wups_get_thread_specific: invalid id\n", wups_meta_info_dump);
|
||||
OSFatal("wups_get_thread_specific: invalid id");
|
||||
}
|
||||
} else {
|
||||
OSReport("[%s] wups_get_thread_specific: invalid thread\n", wups_meta_info_dump);
|
||||
OSFatal("wups_get_thread_specific: invalid thread\n");
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
typedef enum __wut_thread_specific_id {
|
||||
WUT_THREAD_SPECIFIC_0 = 0,
|
||||
WUT_THREAD_SPECIFIC_1 = 1,
|
||||
} __wut_thread_specific_id;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void wups_set_thread_specific(__wut_thread_specific_id id, void *value);
|
||||
|
||||
void *wups_get_thread_specific(__wut_thread_specific_id id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Loading…
Reference in New Issue
Block a user