mirror of
https://github.com/devkitPro/wut.git
synced 2026-03-21 17:34:47 -05:00
wutnewlib: implement new unified threading syscalls (replaces wutstdc++) (#434)
Some checks failed
C/C++ CI / ubuntu-latest (push) Has been cancelled
Some checks failed
C/C++ CI / ubuntu-latest (push) Has been cancelled
This commit is contained in:
parent
26ed8f3b39
commit
afa43f676d
1
Makefile
1
Makefile
|
|
@ -16,7 +16,6 @@ TARGET := wut
|
|||
SOURCES := cafe \
|
||||
libraries/wutcrt \
|
||||
libraries/wutnewlib \
|
||||
libraries/wutstdc++ \
|
||||
libraries/wutmalloc \
|
||||
libraries/wutdevoptab \
|
||||
libraries/wutsocket \
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
void
|
||||
__init_wut_newlib();
|
||||
void
|
||||
__init_wut_stdcpp();
|
||||
void
|
||||
__init_wut_devoptab();
|
||||
void __attribute__((weak))
|
||||
__init_wut_socket();
|
||||
|
|
@ -11,8 +9,6 @@ __init_wut_socket();
|
|||
void
|
||||
__fini_wut_newlib();
|
||||
void
|
||||
__fini_wut_stdcpp();
|
||||
void
|
||||
__fini_wut_devoptab();
|
||||
void __attribute__((weak))
|
||||
__fini_wut_socket();
|
||||
|
|
@ -21,7 +17,6 @@ void __attribute__((weak))
|
|||
__init_wut()
|
||||
{
|
||||
__init_wut_newlib();
|
||||
__init_wut_stdcpp();
|
||||
__init_wut_devoptab();
|
||||
if (&__init_wut_socket) __init_wut_socket();
|
||||
}
|
||||
|
|
@ -31,6 +26,5 @@ __fini_wut()
|
|||
{
|
||||
if (&__fini_wut_socket) __fini_wut_socket();
|
||||
__fini_wut_devoptab();
|
||||
__fini_wut_stdcpp();
|
||||
__fini_wut_newlib();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
void
|
||||
__init_wut_sbrk_heap(MEMHeapHandle heapHandle);
|
||||
void
|
||||
__init_wut_malloc_lock();
|
||||
__init_wut_thread();
|
||||
void
|
||||
__init_wut_defaultheap();
|
||||
|
||||
|
|
@ -13,6 +13,6 @@ __preinit_user(MEMHeapHandle *mem1,
|
|||
MEMHeapHandle *mem2)
|
||||
{
|
||||
__init_wut_sbrk_heap(*mem2);
|
||||
__init_wut_malloc_lock();
|
||||
__init_wut_thread();
|
||||
__init_wut_defaultheap();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,80 +0,0 @@
|
|||
#include "wut_newlib.h"
|
||||
|
||||
#include <coreinit/atomic.h>
|
||||
#include <coreinit/mutex.h>
|
||||
|
||||
#define MAX_LOCKS 16
|
||||
|
||||
static OSMutex sLibcLocks[MAX_LOCKS];
|
||||
static volatile uint32_t sLibcLockUsedMask = 0;
|
||||
|
||||
static inline bool
|
||||
__wut_is_lock_valid(int *lock)
|
||||
{
|
||||
return lock && *lock >= 0 && *lock < MAX_LOCKS;
|
||||
}
|
||||
|
||||
int
|
||||
__wut_lock_init(int *lock,
|
||||
int recursive)
|
||||
{
|
||||
if (!lock) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int slot;
|
||||
uint32_t new_mask;
|
||||
uint32_t cur_mask = sLibcLockUsedMask;
|
||||
do {
|
||||
slot = __builtin_ffs(~cur_mask) - 1;
|
||||
if (slot < 0 || slot >= MAX_LOCKS) break;
|
||||
new_mask = cur_mask | (1U << slot);
|
||||
} while (!OSCompareAndSwapAtomicEx(&sLibcLockUsedMask, cur_mask, new_mask, &cur_mask));
|
||||
|
||||
if (slot < 0 || slot >= MAX_LOCKS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*lock = slot;
|
||||
OSInitMutex(&sLibcLocks[*lock]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__wut_lock_close(int *lock)
|
||||
{
|
||||
if (!__wut_is_lock_valid(lock)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t new_mask;
|
||||
uint32_t cur_mask = sLibcLockUsedMask;
|
||||
do {
|
||||
new_mask = cur_mask & ~(1U << *lock);
|
||||
} while (!OSCompareAndSwapAtomicEx(&sLibcLockUsedMask, cur_mask, new_mask, &cur_mask));
|
||||
|
||||
*lock = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__wut_lock_acquire(int *lock)
|
||||
{
|
||||
if (!__wut_is_lock_valid(lock)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
OSLockMutex(&sLibcLocks[*lock]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__wut_lock_release(int *lock)
|
||||
{
|
||||
if (!__wut_is_lock_valid(lock)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
OSUnlockMutex(&sLibcLocks[*lock]);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
#include "wut_newlib.h"
|
||||
|
||||
#include <coreinit/spinlock.h>
|
||||
|
||||
static OSSpinLock sMallocSpinLock;
|
||||
|
||||
void
|
||||
__wut_malloc_lock(struct _reent *r)
|
||||
{
|
||||
OSUninterruptibleSpinLock_Acquire(&sMallocSpinLock);
|
||||
}
|
||||
|
||||
void
|
||||
__wut_malloc_unlock(struct _reent *r)
|
||||
{
|
||||
OSUninterruptibleSpinLock_Release(&sMallocSpinLock);
|
||||
}
|
||||
|
||||
void
|
||||
__init_wut_malloc_lock()
|
||||
{
|
||||
OSInitSpinLock(&sMallocSpinLock);
|
||||
}
|
||||
|
|
@ -71,65 +71,6 @@ _sbrk_r(struct _reent *ptr, ptrdiff_t incr)
|
|||
return __wut_sbrk_r(ptr, incr);
|
||||
}
|
||||
|
||||
void
|
||||
__syscall_lock_init(int *lock)
|
||||
{
|
||||
__wut_lock_init(lock, 0);
|
||||
}
|
||||
|
||||
void
|
||||
__syscall_lock_acquire(int *lock)
|
||||
{
|
||||
__wut_lock_acquire(lock);
|
||||
}
|
||||
|
||||
void
|
||||
__syscall_lock_release(int *lock)
|
||||
{
|
||||
__wut_lock_release(lock);
|
||||
}
|
||||
|
||||
void
|
||||
__syscall_lock_close(int *lock)
|
||||
{
|
||||
__wut_lock_close(lock);
|
||||
}
|
||||
void
|
||||
__syscall_lock_init_recursive(_LOCK_T *lock)
|
||||
{
|
||||
__wut_lock_init(lock, 1);
|
||||
}
|
||||
|
||||
void
|
||||
__syscall_lock_acquire_recursive(int *lock)
|
||||
{
|
||||
__wut_lock_acquire(lock);
|
||||
}
|
||||
|
||||
void
|
||||
__syscall_lock_release_recursive(int *lock)
|
||||
{
|
||||
__wut_lock_release(lock);
|
||||
}
|
||||
|
||||
void
|
||||
__syscall_lock_close_recursive(int *lock)
|
||||
{
|
||||
__wut_lock_close(lock);
|
||||
}
|
||||
|
||||
void
|
||||
__syscall_malloc_lock(struct _reent *ptr)
|
||||
{
|
||||
return __wut_malloc_lock(ptr);
|
||||
}
|
||||
|
||||
void
|
||||
__syscall_malloc_unlock(struct _reent *ptr)
|
||||
{
|
||||
return __wut_malloc_unlock(ptr);
|
||||
}
|
||||
|
||||
struct _reent *
|
||||
__syscall_getreent(void)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,21 +6,14 @@
|
|||
#include <sys/reent.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#define __WUT_MAX_KEYS (128)
|
||||
#define __WUT_STACK_SIZE (128 * 1024)
|
||||
|
||||
#define __WUT_KEY_THREAD_SPECIFIC_ID WUT_THREAD_SPECIFIC_0
|
||||
|
||||
void *
|
||||
__wut_sbrk_r(struct _reent *r, ptrdiff_t incr);
|
||||
int
|
||||
__wut_lock_init(int *lock, int recursive);
|
||||
int
|
||||
__wut_lock_close(int *lock);
|
||||
int
|
||||
__wut_lock_acquire(int *lock);
|
||||
int
|
||||
__wut_lock_release(int *lock);
|
||||
void
|
||||
__wut_malloc_lock(struct _reent *r);
|
||||
void
|
||||
__wut_malloc_unlock(struct _reent *r);
|
||||
int
|
||||
__wut_gettod_r(struct _reent *ptr, struct timeval *tp, struct timezone *tz);
|
||||
int
|
||||
__wut_clock_gettime(clockid_t clock_id, struct timespec *tp);
|
||||
|
|
|
|||
293
libraries/wutnewlib/wut_thread.c
Normal file
293
libraries/wutnewlib/wut_thread.c
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
#include "wut_newlib.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <coreinit/atomic.h>
|
||||
#include <coreinit/core.h>
|
||||
#include <coreinit/fastcondition.h>
|
||||
#include <coreinit/fastmutex.h>
|
||||
#include <coreinit/memdefaultheap.h>
|
||||
#include <coreinit/spinlock.h>
|
||||
#include <coreinit/thread.h>
|
||||
|
||||
static OSSpinLock sSyncSpinLock;
|
||||
static OSSpinLock sMallocSpinLock;
|
||||
|
||||
void
|
||||
__init_wut_thread()
|
||||
{
|
||||
OSInitSpinLock(&sSyncSpinLock);
|
||||
OSInitSpinLock(&sMallocSpinLock);
|
||||
}
|
||||
|
||||
static OSFastMutex *
|
||||
__wut_get_mutex(_LOCK_T *lock)
|
||||
{
|
||||
if (*lock) {
|
||||
return (OSFastMutex *)*lock;
|
||||
}
|
||||
|
||||
OSUninterruptibleSpinLock_Acquire(&sSyncSpinLock);
|
||||
|
||||
OSFastMutex *m = (OSFastMutex *)*lock;
|
||||
if (!m) {
|
||||
m = MEMAllocFromDefaultHeap(sizeof(OSFastMutex));
|
||||
OSFastMutex_Init(m, NULL);
|
||||
*lock = (uint32_t)m;
|
||||
}
|
||||
|
||||
OSUninterruptibleSpinLock_Release(&sSyncSpinLock);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
static OSFastCondition *
|
||||
__wut_get_cond(_COND_T *cond)
|
||||
{
|
||||
if (*cond) {
|
||||
return (OSFastCondition *)*cond;
|
||||
}
|
||||
|
||||
OSUninterruptibleSpinLock_Acquire(&sSyncSpinLock);
|
||||
|
||||
OSFastCondition *c = (OSFastCondition *)*cond;
|
||||
if (!c) {
|
||||
c = MEMAllocFromDefaultHeap(sizeof(OSFastCondition));
|
||||
OSFastCond_Init(c, NULL);
|
||||
*cond = (uint32_t)c;
|
||||
}
|
||||
|
||||
OSUninterruptibleSpinLock_Release(&sSyncSpinLock);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void
|
||||
__SYSCALL(malloc_lock)(struct _reent *ptr)
|
||||
{
|
||||
OSUninterruptibleSpinLock_Acquire(&sMallocSpinLock);
|
||||
}
|
||||
|
||||
void
|
||||
__SYSCALL(malloc_unlock)(struct _reent *ptr)
|
||||
{
|
||||
OSUninterruptibleSpinLock_Release(&sMallocSpinLock);
|
||||
}
|
||||
|
||||
void
|
||||
__SYSCALL(lock_close)(_LOCK_T *lock)
|
||||
{
|
||||
if (*lock) {
|
||||
MEMFreeToDefaultHeap((void *)*lock);
|
||||
*lock = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
__SYSCALL(lock_acquire)(_LOCK_T *lock)
|
||||
{
|
||||
OSFastMutex_Lock(__wut_get_mutex(lock));
|
||||
}
|
||||
|
||||
int
|
||||
__SYSCALL(lock_try_acquire)(_LOCK_T *lock)
|
||||
{
|
||||
return OSFastMutex_TryLock(__wut_get_mutex(lock));
|
||||
}
|
||||
|
||||
void
|
||||
__SYSCALL(lock_release)(_LOCK_T *lock)
|
||||
{
|
||||
OSFastMutex_Unlock(__wut_get_mutex(lock));
|
||||
}
|
||||
|
||||
void
|
||||
__SYSCALL(lock_close_recursive)(_LOCK_RECURSIVE_T *lock)
|
||||
{
|
||||
__SYSCALL(lock_close)
|
||||
(&lock->lock);
|
||||
}
|
||||
|
||||
void
|
||||
__SYSCALL(lock_acquire_recursive)(_LOCK_RECURSIVE_T *lock)
|
||||
{
|
||||
__SYSCALL(lock_acquire)
|
||||
(&lock->lock);
|
||||
}
|
||||
|
||||
int32_t
|
||||
__SYSCALL(lock_try_acquire_recursive)(_LOCK_RECURSIVE_T *lock)
|
||||
{
|
||||
return __SYSCALL(lock_try_acquire)(&lock->lock);
|
||||
}
|
||||
|
||||
void
|
||||
__SYSCALL(lock_release_recursive)(_LOCK_RECURSIVE_T *lock)
|
||||
{
|
||||
__SYSCALL(lock_release)
|
||||
(&lock->lock);
|
||||
}
|
||||
|
||||
void
|
||||
__SYSCALL(cond_close)(_COND_T *cond)
|
||||
{
|
||||
if (*cond) {
|
||||
MEMFreeToDefaultHeap((void *)*cond);
|
||||
*cond = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
__SYSCALL(cond_signal)(_COND_T *cond)
|
||||
{
|
||||
OSFastCond_Signal(__wut_get_cond(cond)); // XX: this is broadcast
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__SYSCALL(cond_broadcast)(_COND_T *cond)
|
||||
{
|
||||
OSFastCond_Signal(__wut_get_cond(cond));
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
OSFastCondition *cond;
|
||||
bool timed_out;
|
||||
} __wut_condwait_t;
|
||||
|
||||
static void
|
||||
__wut_cond_alarmcb(OSAlarm *alarm, OSContext *context)
|
||||
{
|
||||
__wut_condwait_t *data = OSGetAlarmUserData(alarm);
|
||||
data->timed_out = true;
|
||||
OSFastCond_Signal(data->cond);
|
||||
}
|
||||
|
||||
int
|
||||
__SYSCALL(cond_wait)(_COND_T *cond, _LOCK_T *lock, uint64_t timeout_ns)
|
||||
{
|
||||
if (timeout_ns == UINT64_MAX) {
|
||||
OSFastCond_Wait(__wut_get_cond(cond), __wut_get_mutex(lock));
|
||||
return 0;
|
||||
}
|
||||
|
||||
__wut_condwait_t data;
|
||||
data.cond = __wut_get_cond(cond);
|
||||
data.timed_out = false;
|
||||
|
||||
OSAlarm alarm;
|
||||
OSCreateAlarm(&alarm);
|
||||
OSSetAlarmUserData(&alarm, &data);
|
||||
OSSetAlarm(&alarm, OSNanosecondsToTicks(timeout_ns), __wut_cond_alarmcb);
|
||||
OSFastCond_Wait(data.cond, __wut_get_mutex(lock));
|
||||
OSCancelAlarm(&alarm);
|
||||
|
||||
return data.timed_out ? ETIMEDOUT : 0;
|
||||
}
|
||||
|
||||
int
|
||||
__SYSCALL(cond_wait_recursive)(_COND_T *cond, _LOCK_RECURSIVE_T *lock, uint64_t timeout_ns)
|
||||
{
|
||||
return __SYSCALL(cond_wait)(cond, &lock->lock, timeout_ns);
|
||||
}
|
||||
|
||||
struct __pthread_t
|
||||
{
|
||||
OSThread base;
|
||||
};
|
||||
|
||||
int
|
||||
__SYSCALL(thread_create)(struct __pthread_t **thread, void *(*func)(void *), void *arg, void *stack_addr, size_t stack_size)
|
||||
{
|
||||
if (!stack_size) {
|
||||
stack_size = __WUT_STACK_SIZE;
|
||||
}
|
||||
|
||||
uint32_t alloc_size = sizeof(struct __pthread_t);
|
||||
alloc_size = (alloc_size + 15) & ~15;
|
||||
stack_size = stack_size & ~15;
|
||||
|
||||
if (!stack_addr) {
|
||||
alloc_size += stack_size;
|
||||
}
|
||||
|
||||
struct __pthread_t *t = MEMAllocFromDefaultHeapEx(alloc_size, 0x10);
|
||||
if (!t) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
memset(t, 0, sizeof(*t));
|
||||
|
||||
if (!stack_addr) {
|
||||
stack_addr = (char *)t + alloc_size;
|
||||
} else {
|
||||
stack_addr = (char *)stack_addr + stack_size;
|
||||
}
|
||||
|
||||
BOOL ok = OSCreateThread(
|
||||
&t->base,
|
||||
(OSThreadEntryPointFn)func,
|
||||
(int32_t)arg,
|
||||
NULL,
|
||||
stack_addr,
|
||||
stack_size,
|
||||
16,
|
||||
OS_THREAD_ATTRIB_AFFINITY_ANY);
|
||||
|
||||
if (!ok) {
|
||||
MEMFreeToDefaultHeap(t);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
*thread = t;
|
||||
OSSetThreadDeallocator(&t->base, (OSThreadDeallocatorFn)MEMFreeToDefaultHeap);
|
||||
//XX: OSSetThreadCleanupCallback: use to free TLS slots
|
||||
|
||||
// Enable timeslicing, using 1ms as the thread run quantum
|
||||
OSSetThreadRunQuantum(&t->base, 1000);
|
||||
|
||||
OSResumeThread(&t->base);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *
|
||||
__SYSCALL(thread_join)(struct __pthread_t *thread)
|
||||
{
|
||||
int res = 0;
|
||||
OSJoinThread(&thread->base, &res); // XX: assert?
|
||||
return (void *)res;
|
||||
}
|
||||
|
||||
int
|
||||
__SYSCALL(thread_detach)(struct __pthread_t *thread)
|
||||
{
|
||||
OSDetachThread(&thread->base);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
__SYSCALL(thread_exit)(void *value)
|
||||
{
|
||||
OSExitThread((int)value);
|
||||
}
|
||||
|
||||
struct __pthread_t *
|
||||
__SYSCALL(thread_self)(void)
|
||||
{
|
||||
return (struct __pthread_t *)OSGetCurrentThread();
|
||||
}
|
||||
|
||||
int
|
||||
sched_yield(void)
|
||||
{
|
||||
OSYieldThread();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
sched_getcpu(void)
|
||||
{
|
||||
return OSGetCoreId();
|
||||
}
|
||||
|
|
@ -1,197 +0,0 @@
|
|||
#include "wut_gthread.h"
|
||||
#include <bit>
|
||||
#include <bits/gthr-default.h>
|
||||
|
||||
static constexpr __wut_key_t
|
||||
gthread_key_to_wut(__gthread_key_t key)
|
||||
{
|
||||
__wut_key_t dst = {};
|
||||
static_assert(sizeof(__wut_key_t) == sizeof(__gthread_key_t), "Incompatible definition of thread local key type");
|
||||
__builtin_memcpy(&dst, &key, sizeof(dst));
|
||||
return dst;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int
|
||||
__gthr_impl_active(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_impl_create(__gthread_t *__threadid, void *(*__func)(void *), void *__args)
|
||||
{
|
||||
return __wut_thread_create((OSThread **)__threadid, __func, __args);
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_impl_join(__gthread_t __threadid, void **__value_ptr)
|
||||
{
|
||||
return __wut_thread_join((OSThread *)__threadid, __value_ptr);
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_impl_detach(__gthread_t __threadid)
|
||||
{
|
||||
return __wut_thread_detach((OSThread *)__threadid);
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_impl_equal(__gthread_t __t1, __gthread_t __t2)
|
||||
{
|
||||
return __wut_thread_equal((OSThread *)__t1, (OSThread *)__t2);
|
||||
}
|
||||
|
||||
__gthread_t
|
||||
__gthr_impl_self(void)
|
||||
{
|
||||
return __wut_thread_self();
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_impl_yield(void)
|
||||
{
|
||||
return __wut_thread_yield();
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_impl_once(__gthread_once_t *__once, void (*__func)(void))
|
||||
{
|
||||
return __wut_once((__wut_once_t *)__once, __func);
|
||||
}
|
||||
|
||||
int
|
||||
__gth_impl_key_create(__gthread_key_t *__key, void (*__dtor)(void *))
|
||||
{
|
||||
return __wut_key_create((__wut_key_t *)__key, __dtor);
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_impl_key_delete(__gthread_key_t __key)
|
||||
{
|
||||
return __wut_key_delete(gthread_key_to_wut(__key));
|
||||
}
|
||||
void *
|
||||
__gthr_impl_getspecific(__gthread_key_t __key)
|
||||
{
|
||||
return __wut_getspecific(gthread_key_to_wut(__key));
|
||||
}
|
||||
int
|
||||
__gthr_impl_setspecific(__gthread_key_t __key, const void *__ptr)
|
||||
{
|
||||
return __wut_setspecific(gthread_key_to_wut(__key), __ptr);
|
||||
}
|
||||
|
||||
void
|
||||
__gthr_impl_mutex_init_function(__gthread_mutex_t *__mutex)
|
||||
{
|
||||
return __wut_mutex_init_function((OSMutex *)__mutex);
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_impl_mutex_destroy(__gthread_mutex_t *__mutex)
|
||||
{
|
||||
return __wut_mutex_destroy((OSMutex *)__mutex);
|
||||
}
|
||||
int
|
||||
__gthr_impl_mutex_lock(__gthread_mutex_t *__mutex)
|
||||
{
|
||||
return __wut_mutex_lock((OSMutex *)__mutex);
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_impl_mutex_trylock(__gthread_mutex_t *__mutex)
|
||||
{
|
||||
return __wut_mutex_trylock((OSMutex *)__mutex);
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_impl_mutex_unlock(__gthread_mutex_t *__mutex)
|
||||
{
|
||||
return __wut_mutex_unlock((OSMutex *)__mutex);
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_impl_recursive_mutex_init_function(__gthread_recursive_mutex_t *__mutex)
|
||||
{
|
||||
return __wut_recursive_mutex_init_function((OSMutex *)__mutex);
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_impl_recursive_mutex_lock(__gthread_recursive_mutex_t *__mutex)
|
||||
{
|
||||
return __wut_recursive_mutex_lock((OSMutex *)__mutex);
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_impl_recursive_mutex_trylock(__gthread_recursive_mutex_t *__mutex)
|
||||
{
|
||||
return __wut_recursive_mutex_trylock((OSMutex *)__mutex);
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_impl_recursive_mutex_unlock(__gthread_recursive_mutex_t *__mutex)
|
||||
{
|
||||
return __wut_recursive_mutex_unlock((OSMutex *)__mutex);
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_impl_recursive_mutex_destroy(__gthread_recursive_mutex_t *__mutex)
|
||||
{
|
||||
return __wut_recursive_mutex_destroy((OSMutex *)__mutex);
|
||||
}
|
||||
|
||||
void
|
||||
__gthr_impl_cond_init_function(__gthread_cond_t *__cond)
|
||||
{
|
||||
return __wut_cond_init_function((OSCondition *)__cond);
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_impl_cond_broadcast(__gthread_cond_t *__cond)
|
||||
{
|
||||
return __wut_cond_broadcast((OSCondition *)__cond);
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_impl_cond_signal(__gthread_cond_t *__cond)
|
||||
{
|
||||
return __wut_cond_signal((OSCondition *)__cond);
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_impl_cond_wait(__gthread_cond_t *__cond, __gthread_mutex_t *__mutex)
|
||||
{
|
||||
return __wut_cond_wait((OSCondition *)__cond, (OSMutex *)__mutex);
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_impl_cond_timedwait(__gthread_cond_t *__cond, __gthread_mutex_t *__mutex, const __gthread_time_t *__abs_timeout)
|
||||
{
|
||||
return __wut_cond_timedwait((OSCondition *)__cond, (OSMutex *)__mutex, __abs_timeout);
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_impl_cond_wait_recursive(__gthread_cond_t *__cond, __gthread_recursive_mutex_t *__mutex)
|
||||
{
|
||||
return __wut_cond_wait_recursive((OSCondition *)__cond, (OSMutex *)__mutex);
|
||||
}
|
||||
|
||||
int
|
||||
__gthr_impl_cond_destroy(__gthread_cond_t *__cond)
|
||||
{
|
||||
return __wut_cond_destroy((OSCondition *)__cond);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
__init_wut_stdcpp()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
__fini_wut_stdcpp()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
#pragma once
|
||||
#include <bits/gthr-default.h>
|
||||
|
||||
#include <coreinit/atomic.h>
|
||||
#include <coreinit/condition.h>
|
||||
#include <coreinit/mutex.h>
|
||||
#include <coreinit/thread.h>
|
||||
|
||||
#include "../wutnewlib/wut_thread_specific.h"
|
||||
|
||||
#define __WUT_MAX_KEYS (128)
|
||||
#define __WUT_STACK_SIZE (128 * 1024)
|
||||
|
||||
#define __WUT_ONCE_VALUE_INIT (0)
|
||||
#define __WUT_ONCE_VALUE_STARTED (1)
|
||||
#define __WUT_ONCE_VALUE_DONE (2)
|
||||
|
||||
#define __WUT_KEY_THREAD_SPECIFIC_ID WUT_THREAD_SPECIFIC_0
|
||||
|
||||
typedef volatile uint32_t __wut_once_t;
|
||||
typedef struct
|
||||
{
|
||||
uint32_t index;
|
||||
} __wut_key_t;
|
||||
|
||||
void
|
||||
__init_wut_gthread();
|
||||
|
||||
int
|
||||
__wut_active_p();
|
||||
|
||||
int
|
||||
__wut_thread_create(OSThread **outThread,
|
||||
void *(*func)(void *),
|
||||
void *args);
|
||||
|
||||
int
|
||||
__wut_thread_join(OSThread *thread,
|
||||
void **outValue);
|
||||
|
||||
int
|
||||
__wut_thread_detach(OSThread *thread);
|
||||
|
||||
int
|
||||
__wut_thread_equal(OSThread *thread1,
|
||||
OSThread *thread2);
|
||||
|
||||
OSThread *
|
||||
__wut_thread_self();
|
||||
|
||||
int
|
||||
__wut_thread_yield();
|
||||
|
||||
int
|
||||
__wut_once(__wut_once_t *once,
|
||||
void (*func)(void));
|
||||
|
||||
void
|
||||
__wut_key_cleanup(OSThread *thread);
|
||||
|
||||
int
|
||||
__wut_key_create(__wut_key_t *key,
|
||||
void (*dtor)(void *));
|
||||
|
||||
int
|
||||
__wut_key_delete(__wut_key_t key);
|
||||
|
||||
void *
|
||||
__wut_getspecific(__wut_key_t key);
|
||||
|
||||
int
|
||||
__wut_setspecific(__wut_key_t key,
|
||||
const void *ptr);
|
||||
|
||||
void
|
||||
__wut_mutex_init_function(OSMutex *mutex);
|
||||
|
||||
int
|
||||
__wut_mutex_destroy(OSMutex *mutex);
|
||||
|
||||
int
|
||||
__wut_mutex_lock(OSMutex *mutex);
|
||||
|
||||
int
|
||||
__wut_mutex_trylock(OSMutex *mutex);
|
||||
|
||||
int
|
||||
__wut_mutex_unlock(OSMutex *mutex);
|
||||
|
||||
int
|
||||
__wut_recursive_mutex_init_function(OSMutex *mutex);
|
||||
|
||||
int
|
||||
__wut_recursive_mutex_lock(OSMutex *mutex);
|
||||
|
||||
int
|
||||
__wut_recursive_mutex_trylock(OSMutex *mutex);
|
||||
|
||||
int
|
||||
__wut_recursive_mutex_unlock(OSMutex *mutex);
|
||||
|
||||
int
|
||||
__wut_recursive_mutex_destroy(OSMutex *mutex);
|
||||
|
||||
void
|
||||
__wut_cond_init_function(OSCondition *cond);
|
||||
|
||||
int
|
||||
__wut_cond_broadcast(OSCondition *cond);
|
||||
|
||||
int
|
||||
__wut_cond_signal(OSCondition *cond);
|
||||
|
||||
int
|
||||
__wut_cond_wait(OSCondition *cond,
|
||||
OSMutex *mutex);
|
||||
|
||||
int
|
||||
__wut_cond_timedwait(OSCondition *cond,
|
||||
OSMutex *mutex,
|
||||
const __gthread_time_t *abs_timeout);
|
||||
|
||||
int
|
||||
__wut_cond_wait_recursive(OSCondition *cond,
|
||||
OSMutex *mutex);
|
||||
|
||||
int
|
||||
__wut_cond_destroy(OSCondition *cond);
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
#include "wut_gthread.h"
|
||||
#include "../wutnewlib/wut_clock.h"
|
||||
|
||||
#include <sys/errno.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <coreinit/alarm.h>
|
||||
#include <coreinit/systeminfo.h>
|
||||
#include <coreinit/time.h>
|
||||
|
||||
void
|
||||
__wut_cond_init_function(OSCondition *cond)
|
||||
{
|
||||
OSInitCond(cond);
|
||||
}
|
||||
|
||||
int
|
||||
__wut_cond_broadcast(OSCondition *cond)
|
||||
{
|
||||
OSSignalCond(cond);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__wut_cond_signal(OSCondition *cond)
|
||||
{
|
||||
OSSignalCond(cond);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__wut_cond_wait(OSCondition *cond,
|
||||
OSMutex *mutex)
|
||||
{
|
||||
OSWaitCond(cond, mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct __wut_cond_timedwait_data_t
|
||||
{
|
||||
OSCondition *cond;
|
||||
bool timed_out;
|
||||
};
|
||||
|
||||
static void
|
||||
__wut_cond_timedwait_alarm_callback(OSAlarm *alarm,
|
||||
OSContext *context)
|
||||
{
|
||||
__wut_cond_timedwait_data_t *data = (__wut_cond_timedwait_data_t *)OSGetAlarmUserData(alarm);
|
||||
data->timed_out = true;
|
||||
OSSignalCond(data->cond);
|
||||
}
|
||||
|
||||
int
|
||||
__wut_cond_timedwait(OSCondition *cond, OSMutex *mutex, const __gthread_time_t *abs_timeout)
|
||||
{
|
||||
__wut_cond_timedwait_data_t data;
|
||||
data.timed_out = false;
|
||||
data.cond = cond;
|
||||
|
||||
OSTime time = OSGetTime();
|
||||
OSTime timeout =
|
||||
OSSecondsToTicks(abs_timeout->tv_sec - EPOCH_DIFF_SECS(WIIU_OSTIME_EPOCH_YEAR)) +
|
||||
OSNanosecondsToTicks(abs_timeout->tv_nsec);
|
||||
|
||||
// Already timed out!
|
||||
if (timeout <= time) {
|
||||
return ETIMEDOUT;
|
||||
}
|
||||
|
||||
// Set an alarm
|
||||
OSAlarm alarm;
|
||||
OSCreateAlarm(&alarm);
|
||||
OSSetAlarmUserData(&alarm, &data);
|
||||
OSSetAlarm(&alarm, timeout - time,
|
||||
&__wut_cond_timedwait_alarm_callback);
|
||||
|
||||
// Wait on the condition
|
||||
OSWaitCond(cond, mutex);
|
||||
|
||||
OSCancelAlarm(&alarm);
|
||||
return data.timed_out ? ETIMEDOUT : 0;
|
||||
}
|
||||
|
||||
int
|
||||
__wut_cond_wait_recursive(OSCondition *cond,
|
||||
OSMutex *mutex)
|
||||
{
|
||||
OSWaitCond(cond, mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__wut_cond_destroy(OSCondition *cond)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,119 +0,0 @@
|
|||
#include "wut_gthread.h"
|
||||
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <sys/errno.h>
|
||||
|
||||
struct __wut_key_table_entry
|
||||
{
|
||||
bool in_use;
|
||||
void (*dtor)(void *);
|
||||
};
|
||||
|
||||
static __wut_key_table_entry key_table[__WUT_MAX_KEYS];
|
||||
|
||||
static OSMutex key_mutex;
|
||||
static __wut_once_t init_once_control = __WUT_ONCE_VALUE_INIT;
|
||||
|
||||
static void
|
||||
init()
|
||||
{
|
||||
__wut_mutex_init_function(&key_mutex);
|
||||
memset(key_table, 0, sizeof(key_table));
|
||||
}
|
||||
|
||||
int
|
||||
__wut_key_create(__wut_key_t *key,
|
||||
void (*dtor)(void *))
|
||||
{
|
||||
int res = EAGAIN;
|
||||
__wut_once(&init_once_control, init);
|
||||
__wut_mutex_lock(&key_mutex);
|
||||
|
||||
for (uint32_t i = 0; i < __WUT_MAX_KEYS; ++i) {
|
||||
if (key_table[i].in_use) {
|
||||
continue;
|
||||
}
|
||||
|
||||
key_table[i].in_use = 1;
|
||||
key_table[i].dtor = dtor;
|
||||
|
||||
res = 0;
|
||||
key->index = i;
|
||||
break;
|
||||
}
|
||||
|
||||
__wut_mutex_unlock(&key_mutex);
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
__wut_key_delete(__wut_key_t key)
|
||||
{
|
||||
__wut_mutex_lock(&key_mutex);
|
||||
key_table[key.index].in_use = 0;
|
||||
key_table[key.index].dtor = NULL;
|
||||
__wut_mutex_unlock(&key_mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static const void **
|
||||
__wut_get_thread_keys()
|
||||
{
|
||||
const void **keys = (const void **)wut_get_thread_specific(__WUT_KEY_THREAD_SPECIFIC_ID);
|
||||
if (!keys) {
|
||||
keys = (const void **)malloc(sizeof(void *) * sizeof(__WUT_MAX_KEYS));
|
||||
if (!keys) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(keys, 0, sizeof(void *) * sizeof(__WUT_MAX_KEYS));
|
||||
wut_set_thread_specific(__WUT_KEY_THREAD_SPECIFIC_ID, keys);
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
void *
|
||||
__wut_getspecific(__wut_key_t key)
|
||||
{
|
||||
const void **keys = __wut_get_thread_keys();
|
||||
if (!keys) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (void *)(keys[key.index]);
|
||||
}
|
||||
|
||||
int
|
||||
__wut_setspecific(__wut_key_t key,
|
||||
const void *ptr)
|
||||
{
|
||||
const void **keys = __wut_get_thread_keys();
|
||||
if (!keys) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
keys[key.index] = ptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
__wut_key_cleanup(OSThread *thread)
|
||||
{
|
||||
void **keys = (void **)wut_get_thread_specific(__WUT_KEY_THREAD_SPECIFIC_ID);
|
||||
if (!keys) {
|
||||
return;
|
||||
}
|
||||
|
||||
__wut_mutex_lock(&key_mutex);
|
||||
|
||||
for (int i = 0; i < __WUT_MAX_KEYS; ++i) {
|
||||
if (key_table[i].in_use && key_table[i].dtor && keys[i]) {
|
||||
key_table[i].dtor(keys[i]);
|
||||
}
|
||||
}
|
||||
|
||||
__wut_mutex_unlock(&key_mutex);
|
||||
free(keys);
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
#include "wut_gthread.h"
|
||||
|
||||
void
|
||||
__wut_mutex_init_function(OSMutex *mutex)
|
||||
{
|
||||
OSInitMutex(mutex);
|
||||
}
|
||||
|
||||
int
|
||||
__wut_mutex_lock(OSMutex *mutex)
|
||||
{
|
||||
OSLockMutex(mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__wut_mutex_trylock(OSMutex *mutex)
|
||||
{
|
||||
if (!OSTryLockMutex(mutex)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__wut_mutex_unlock(OSMutex *mutex)
|
||||
{
|
||||
OSUnlockMutex(mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__wut_mutex_destroy(OSMutex *mutex)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
#include "wut_gthread.h"
|
||||
|
||||
int
|
||||
__wut_once(__wut_once_t *once,
|
||||
void (*func)(void))
|
||||
{
|
||||
uint32_t value = 0;
|
||||
|
||||
if (OSCompareAndSwapAtomicEx(once,
|
||||
__WUT_ONCE_VALUE_INIT,
|
||||
__WUT_ONCE_VALUE_STARTED,
|
||||
&value)) {
|
||||
func();
|
||||
OSSwapAtomic(once,
|
||||
__WUT_ONCE_VALUE_DONE);
|
||||
} else if (value != __WUT_ONCE_VALUE_DONE) {
|
||||
while (!OSCompareAndSwapAtomic(once,
|
||||
__WUT_ONCE_VALUE_DONE,
|
||||
__WUT_ONCE_VALUE_DONE));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
#include "wut_gthread.h"
|
||||
|
||||
int
|
||||
__wut_recursive_mutex_init_function(OSMutex *mutex)
|
||||
{
|
||||
OSInitMutex(mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__wut_recursive_mutex_lock(OSMutex *mutex)
|
||||
{
|
||||
OSLockMutex(mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__wut_recursive_mutex_trylock(OSMutex *mutex)
|
||||
{
|
||||
if (!OSTryLockMutex(mutex)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__wut_recursive_mutex_unlock(OSMutex *mutex)
|
||||
{
|
||||
OSUnlockMutex(mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__wut_recursive_mutex_destroy(OSMutex *mutex)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
#include "wut_gthread.h"
|
||||
|
||||
#include <malloc.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/errno.h>
|
||||
uint32_t __attribute__((weak)) __wut_thread_default_stack_size = __WUT_STACK_SIZE;
|
||||
|
||||
static void
|
||||
__wut_thread_deallocator(OSThread *thread,
|
||||
void *stack)
|
||||
{
|
||||
free(thread);
|
||||
free(stack);
|
||||
}
|
||||
|
||||
static void
|
||||
__wut_thread_cleanup(OSThread *thread, void *stack)
|
||||
{
|
||||
__wut_key_cleanup(thread);
|
||||
}
|
||||
|
||||
int
|
||||
__wut_thread_create(OSThread **outThread,
|
||||
void *(*entryPoint)(void *),
|
||||
void *entryArgs)
|
||||
{
|
||||
OSThread *thread = (OSThread *)memalign(16, sizeof(OSThread));
|
||||
if (!thread) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
memset(thread, 0, sizeof(OSThread));
|
||||
|
||||
char *stack = (char *)memalign(16, __wut_thread_default_stack_size);
|
||||
if (!stack) {
|
||||
free(thread);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
if (!OSCreateThread(thread,
|
||||
(OSThreadEntryPointFn)entryPoint,
|
||||
(int)entryArgs,
|
||||
NULL,
|
||||
stack + __wut_thread_default_stack_size,
|
||||
__wut_thread_default_stack_size,
|
||||
16,
|
||||
OS_THREAD_ATTRIB_AFFINITY_ANY)) {
|
||||
free(thread);
|
||||
free(stack);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
*outThread = thread;
|
||||
OSSetThreadDeallocator(thread, &__wut_thread_deallocator);
|
||||
OSSetThreadCleanupCallback(thread, &__wut_thread_cleanup);
|
||||
|
||||
// Set a thread run quantum to 1 millisecond, to force the threads to
|
||||
// behave more like pre-emptive scheduling rather than co-operative.
|
||||
OSSetThreadRunQuantum(thread, 1000);
|
||||
|
||||
OSResumeThread(thread);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__wut_thread_join(OSThread *thread,
|
||||
void **outValue)
|
||||
{
|
||||
if (!OSJoinThread(thread, (int *)outValue)) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__wut_thread_detach(OSThread *thread)
|
||||
{
|
||||
OSDetachThread(thread);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
__wut_thread_equal(OSThread *thread1,
|
||||
OSThread *thread2)
|
||||
{
|
||||
return thread1 == thread2;
|
||||
}
|
||||
|
||||
OSThread *
|
||||
__wut_thread_self()
|
||||
{
|
||||
return OSGetCurrentThread();
|
||||
}
|
||||
|
||||
int
|
||||
__wut_thread_yield()
|
||||
{
|
||||
OSYieldThread();
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user