Change to using new gthreads implementation.

Assuming that --enable-threads=dkp gets merged into devkitPPC r31... :)
This commit is contained in:
James Benton 2018-05-26 18:25:36 +01:00
parent 37228a095d
commit ac8a42fa7c
24 changed files with 608 additions and 1177 deletions

View File

@ -3,12 +3,14 @@
#include <coreinit/time.h>
#include <unistd.h>
unsigned sleep(unsigned seconds) {
unsigned sleep(unsigned seconds)
{
OSSleepTicks(OSSeconds(seconds));
return 0;
}
int usleep(useconds_t microseconds) {
int usleep(useconds_t microseconds)
{
OSSleepTicks(OSMicroseconds(microseconds));
return 0;
}

View File

@ -172,10 +172,16 @@ __init_syscall_array()
__syscalls.gettod_r = __libwut_gettod_r;
}
extern void __init_wut_gthread() __attribute__((weak));
void
__init_wut_newlibc()
{
__init_libc_heap();
__init_malloc_lock();
__init_syscall_array();
if (__init_wut_gthread) {
__init_wut_gthread();
}
}

View File

@ -2,18 +2,13 @@ cmake_minimum_required(VERSION 3.2)
project(wutstdc++ CXX)
add_library(wutstdc++
condition_variable.cc
future.cc
gthread.cc
gthread_cond.cc
gthread_keys.cc
gthread_mutex.cc
gthread_once.cc
gthread_recursive_mutex.cc
mutex.cc
shared_ptr.cc
thread.cc
include/bits/gthr-default.h)
wut_gthread.cc
wut_gthread_cond.cc
wut_gthread_keys.cc
wut_gthread_mutex.cc
wut_gthread_once.cc
wut_gthread_recursive_mutex.cc
wut_gthread_thread.cc)
target_compile_definitions(wutstdc++
PRIVATE _GLIBCXX_HAS_GTHREADS)

View File

@ -1,158 +0,0 @@
// condition_variable -*- C++ -*-
// Copyright (C) 2008-2018 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.
// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <http://www.gnu.org/licenses/>.
#include <condition_variable>
#include <cstdlib>
#if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
#ifdef __GTHREAD_COND_INIT
condition_variable::condition_variable() noexcept = default;
#else
condition_variable::condition_variable() noexcept
{
__GTHREAD_COND_INIT_FUNCTION(&_M_cond);
}
#endif
condition_variable::~condition_variable() noexcept
{
// XXX no thread blocked
/* int __e = */ __gthread_cond_destroy(&_M_cond);
// if __e == EBUSY then blocked
}
void
condition_variable::wait(unique_lock<mutex>& __lock) noexcept
{
int __e = __gthread_cond_wait(&_M_cond, __lock.mutex()->native_handle());
if (__e)
std::terminate();
}
void
condition_variable::notify_one() noexcept
{
int __e = __gthread_cond_signal(&_M_cond);
// XXX not in spec
// EINVAL
if (__e)
__throw_system_error(__e);
}
void
condition_variable::notify_all() noexcept
{
int __e = __gthread_cond_broadcast(&_M_cond);
// XXX not in spec
// EINVAL
if (__e)
__throw_system_error(__e);
}
extern void
__at_thread_exit(__at_thread_exit_elt*);
namespace
{
__gthread_key_t key;
void run(void* p)
{
auto elt = (__at_thread_exit_elt*)p;
while (elt)
{
auto next = elt->_M_next;
elt->_M_cb(elt);
elt = next;
}
}
void run()
{
auto elt = (__at_thread_exit_elt*)__gthread_getspecific(key);
__gthread_setspecific(key, nullptr);
run(elt);
}
struct notifier final : __at_thread_exit_elt
{
notifier(condition_variable& cv, unique_lock<mutex>& l)
: cv(&cv), mx(l.release())
{
_M_cb = &notifier::run;
__at_thread_exit(this);
}
~notifier()
{
mx->unlock();
cv->notify_all();
}
condition_variable* cv;
mutex* mx;
static void run(void* p) { delete static_cast<notifier*>(p); }
};
void key_init() {
struct key_s {
key_s() { __gthread_key_create (&key, run); }
~key_s() { __gthread_key_delete (key); }
};
static key_s ks;
// Also make sure the callbacks are run by std::exit.
std::atexit (run);
}
}
void
__at_thread_exit(__at_thread_exit_elt* elt)
{
static __gthread_once_t once = __GTHREAD_ONCE_INIT;
__gthread_once (&once, key_init);
elt->_M_next = (__at_thread_exit_elt*)__gthread_getspecific(key);
__gthread_setspecific(key, elt);
}
void
notify_all_at_thread_exit(condition_variable& cv, unique_lock<mutex> l)
{
(void) new notifier{cv, l};
}
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
#endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1

View File

@ -1,62 +0,0 @@
// future -*- C++ -*-
// Copyright (C) 2009-2018 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.
// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <http://www.gnu.org/licenses/>.
#include <future>
#include <bits/functexcept.h>
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
#if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
__future_base::_Result_base::_Result_base() = default;
__future_base::_Result_base::~_Result_base() = default;
void
__future_base::_State_baseV2::_Make_ready::_S_run(void* p)
{
unique_ptr<_Make_ready> mr{static_cast<_Make_ready*>(p)};
if (auto state = mr->_M_shared_state.lock())
{
// Use release MO to synchronize with observers of the ready state.
state->_M_status._M_store_notify_all(_Status::__ready,
memory_order_release);
}
}
// defined in src/c++11/condition_variable.cc
extern void
__at_thread_exit(__at_thread_exit_elt* elt);
void
__future_base::_State_baseV2::_Make_ready::_M_set()
{
_M_cb = &_Make_ready::_S_run;
__at_thread_exit(this);
}
#endif
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std

View File

@ -1,78 +0,0 @@
#include "include/bits/gthr-default.h"
static void
__gthread_thread_deallocator(OSThread *thread, void *stack)
{
MEMExpandedHeap *heap = (MEMExpandedHeap *)MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM2);
MEMFreeToExpHeap(heap, thread);
MEMFreeToExpHeap(heap, stack);
}
static void
__gthread_thread_cleanup(OSThread *thread, void *stack)
{
__gthread_key_cleanup(thread);
}
int
__gthread_create (__gthread_t *__threadid, void *(*__func) (void*), void *__args)
{
MEMExpandedHeap *heap = (MEMExpandedHeap *)MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM2);
OSThread *thread = (OSThread *)MEMAllocFromExpHeapEx(heap, sizeof(OSThread), 8);
char *stack = (char *)MEMAllocFromExpHeapEx(heap, __GTHREAD_STACK_SIZE, 8);
memset(thread, 0, sizeof(OSThread));
if (!OSCreateThread(thread,
(OSThreadEntryPointFn)__func,
(int)__args,
NULL,
stack + __GTHREAD_STACK_SIZE,
__GTHREAD_STACK_SIZE,
16,
OS_THREAD_ATTRIB_AFFINITY_ANY)) {
MEMFreeToExpHeap((MEMExpandedHeap*)MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM2), thread);
return EINVAL;
}
*__threadid = thread;
OSSetThreadDeallocator(thread, &__gthread_thread_deallocator);
OSSetThreadCleanupCallback(thread, &__gthread_thread_cleanup);
OSResumeThread(thread);
return 0;
}
int
__gthread_join (__gthread_t __threadid, void **__value_ptr)
{
if (!OSJoinThread(__threadid, (int *)__value_ptr)) {
return EINVAL;
}
return 0;
}
int
__gthread_detach (__gthread_t __threadid)
{
OSDetachThread(__threadid);
return 0;
}
int
__gthread_equal (__gthread_t __t1, __gthread_t __t2)
{
return __t1 == __t2;
}
__gthread_t
__gthread_self (void)
{
return OSGetCurrentThread();
}
int
__gthread_yield (void)
{
OSYieldThread();
return 0;
}

View File

@ -1,96 +0,0 @@
#include "include/bits/gthr-default.h"
#include <coreinit/alarm.h>
#include <coreinit/systeminfo.h>
#include <coreinit/time.h>
#include <chrono>
void
__gthread_cond_init_function (__gthread_cond_t *__cond)
{
OSInitCond(__cond);
}
int
__gthread_cond_broadcast (__gthread_cond_t *__cond)
{
OSSignalCond(__cond);
return 0;
}
int
__gthread_cond_signal (__gthread_cond_t *__cond)
{
OSSignalCond(__cond);
return 0;
}
int
__gthread_cond_wait (__gthread_cond_t *__cond, __gthread_mutex_t *__mutex)
{
OSWaitCond(__cond, __mutex);
return 0;
}
struct TimedWaitData
{
__gthread_cond_t *cond;
bool timed_out;
};
static void
__gthread_timedwait_alarm_callback(OSAlarm *alarm, OSContext *context)
{
TimedWaitData *data = (TimedWaitData *)OSGetAlarmUserData(alarm);
data->timed_out = true;
OSSignalCond(data->cond);
}
int
__gthread_cond_timedwait (__gthread_cond_t *__cond, __gthread_mutex_t *__mutex,
const __gthread_time_t *__abs_timeout)
{
auto time = std::chrono::system_clock::now();
auto timeout = std::chrono::system_clock::time_point(
std::chrono::seconds(__abs_timeout->tv_sec) +
std::chrono::nanoseconds(__abs_timeout->tv_nsec));
// Already timed out!
if (timeout <= time) {
return ETIMEDOUT;
}
auto duration =
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout - time);
// Set an alarm
OSAlarm alarm;
TimedWaitData data;
data.timed_out = false;
data.cond = __cond;
OSCreateAlarm(&alarm);
OSSetAlarmUserData(&alarm, &data);
OSSetAlarm(&alarm, OSNanoseconds(duration.count()),
&__gthread_timedwait_alarm_callback);
// Wait on the condition
OSWaitCond(__cond, __mutex);
OSCancelAlarm(&alarm);
return data.timed_out ? ETIMEDOUT : 0;
}
int
__gthread_cond_wait_recursive (__gthread_cond_t *__cond,
__gthread_recursive_mutex_t *__mutex)
{
OSWaitCond(__cond, __mutex);
return 0;
}
int
__gthread_cond_destroy (__gthread_cond_t* __cond)
{
return 0;
}

View File

@ -1,98 +0,0 @@
#include "include/bits/gthr-default.h"
struct gthread_key
{
bool in_use;
void (*dtor) (void *);
};
static gthread_key key_table[__GTHREAD_MAX_KEYS];
static __gthread_mutex_t key_mutex;
static __gthread_once_t init_once_control = __GTHREAD_ONCE_INIT;
static void init()
{
__GTHREAD_MUTEX_INIT_FUNCTION(&key_mutex);
memset(key_table, 0, sizeof(key_table));
}
int
__gthread_key_create (__gthread_key_t *__key, void (*__dtor) (void *))
{
int res = EAGAIN;
__gthread_once(&init_once_control, init);
__gthread_mutex_lock(&key_mutex);
for (int i = 0; i < __GTHREAD_MAX_KEYS; ++i) {
if (key_table[i].in_use) {
continue;
}
key_table[i].in_use = 1;
key_table[i].dtor = __dtor;
res = 0;
*__key = (__gthread_key_t)i;
break;
}
__gthread_mutex_unlock(&key_mutex);
return res;
}
int
__gthread_key_delete (__gthread_key_t __key)
{
__gthread_mutex_lock(&key_mutex);
key_table[__key].in_use = 0;
key_table[__key].dtor = NULL;
__gthread_mutex_unlock(&key_mutex);
return -1;
}
static const void **
__gthread_get_thread_keys()
{
const void **keys = (const void **)OSGetThreadSpecific(__GTHREAD_THREAD_SPECIFIC_ID);
if (!keys) {
MEMExpandedHeap *heap = (MEMExpandedHeap *)MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM2);
keys = (const void **)MEMAllocFromExpHeapEx(heap, sizeof(void *) * sizeof(__GTHREAD_MAX_KEYS), 4);
memset(keys, 0, sizeof(void *) * sizeof(__GTHREAD_MAX_KEYS));
OSSetThreadSpecific(__GTHREAD_THREAD_SPECIFIC_ID, keys);
}
return keys;
}
void *
__gthread_getspecific (__gthread_key_t __key)
{
return (void *)__gthread_get_thread_keys()[__key];
}
int
__gthread_setspecific (__gthread_key_t __key, const void *__ptr)
{
__gthread_get_thread_keys()[__key] = __ptr;
return 0;
}
void
__gthread_key_cleanup (OSThread *thread)
{
void **keys = (void **)OSGetThreadSpecific(__GTHREAD_THREAD_SPECIFIC_ID);
if (!keys) {
return;
}
__gthread_mutex_lock(&key_mutex);
for (int i = 0; i < __GTHREAD_MAX_KEYS; ++i) {
if (key_table[i].in_use && key_table[i].dtor && keys[i]) {
key_table[i].dtor(keys[i]);
}
}
__gthread_mutex_unlock(&key_mutex);
}

View File

@ -1,37 +0,0 @@
#include "include/bits/gthr-default.h"
void
__gthread_mutex_init_function (__gthread_mutex_t *__mutex)
{
OSInitMutex(__mutex);
}
int
__gthread_mutex_lock (__gthread_mutex_t *__mutex)
{
OSLockMutex(__mutex);
return 0;
}
int
__gthread_mutex_trylock (__gthread_mutex_t *__mutex)
{
if (!OSTryLockMutex(__mutex)) {
return -1;
}
return 0;
}
int
__gthread_mutex_unlock (__gthread_mutex_t *__mutex)
{
OSUnlockMutex(__mutex);
return 0;
}
int
__gthread_mutex_destroy (__gthread_mutex_t *__mutex)
{
return 0;
}

View File

@ -1,23 +0,0 @@
#include "include/bits/gthr-default.h"
int
__gthread_once (__gthread_once_t *__once, void (*__func) (void))
{
uint32_t value = 0;
if (OSCompareAndSwapAtomicEx(__once,
__GTHREAD_ONCE_VALUE_INIT,
__GTHREAD_ONCE_VALUE_STARTED,
&value)) {
__func();
OSCompareAndSwapAtomic(__once,
__GTHREAD_ONCE_VALUE_STARTED,
__GTHREAD_ONCE_VALUE_DONE);
} else if (value != __GTHREAD_ONCE_VALUE_DONE) {
while (!OSCompareAndSwapAtomic(__once,
__GTHREAD_ONCE_VALUE_DONE,
__GTHREAD_ONCE_VALUE_DONE));
}
return 0;
}

View File

@ -1,38 +0,0 @@
#include "include/bits/gthr-default.h"
int
__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *__mutex)
{
OSInitMutex(__mutex);
return 0;
}
int
__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *__mutex)
{
OSLockMutex(__mutex);
return 0;
}
int
__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex)
{
if (!OSTryLockMutex(__mutex)) {
return -1;
}
return 0;
}
int
__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *__mutex)
{
OSUnlockMutex(__mutex);
return 0;
}
int
__gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t *__mutex)
{
return 0;
}

View File

@ -1,165 +0,0 @@
/* Threads compatibility routines for libgcc2 and libobjc. */
/* Compile this one with gcc. */
/* Copyright (C) 1997-2016 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.
You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
#ifndef _GLIBCXX_GCC_GTHR_SINGLE_H
#define _GLIBCXX_GCC_GTHR_SINGLE_H
#define __GTHREADS 1
#define __GTHREADS_CXX0X 1
#include <coreinit/atomic.h>
#include <coreinit/condition.h>
#include <coreinit/thread.h>
#include <coreinit/mutex.h>
#include <coreinit/baseheap.h>
#include <coreinit/expandedheap.h>
#include <string.h>
#include <sys/errno.h>
#define _GTHREAD_USE_MUTEX_TIMEDLOCK 0
typedef OSThread *__gthread_t;
typedef volatile uint32_t __gthread_once_t;
typedef OSMutex __gthread_mutex_t;
typedef OSMutex __gthread_recursive_mutex_t;
typedef OSCondition __gthread_cond_t;
typedef struct timespec __gthread_time_t;
typedef uint32_t __gthread_key_t;
#define __GTHREAD_HAS_COND 1
#define __GTHREAD_MAX_KEYS (128)
#define __GTHREAD_ONCE_VALUE_INIT (0)
#define __GTHREAD_ONCE_VALUE_STARTED (1)
#define __GTHREAD_ONCE_VALUE_DONE (2)
#define __GTHREAD_ONCE_INIT __GTHREAD_ONCE_VALUE_INIT
#define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function
#define __GTHREAD_COND_INIT_FUNCTION __gthread_cond_init_function
#define __GTHREAD_TIME_INIT { 0, 0 }
#define __GTHREAD_STACK_SIZE (4096*1024)
#define __GTHREAD_THREAD_SPECIFIC_ID (0)
static inline int
__gthread_active_p (void)
{
return 1;
}
int
__gthread_create (__gthread_t *__threadid, void *(*__func) (void*),
void *__args);
int
__gthread_join (__gthread_t __threadid, void **__value_ptr);
int
__gthread_detach (__gthread_t __threadid);
int
__gthread_equal (__gthread_t __t1, __gthread_t __t2);
__gthread_t
__gthread_self (void);
int
__gthread_yield (void);
int
__gthread_once (__gthread_once_t *__once, void (*__func) (void));
void
__gthread_key_cleanup (OSThread *thread);
int
__gthread_key_create (__gthread_key_t *__key, void (*__dtor) (void *));
int
__gthread_key_delete (__gthread_key_t __key);
void *
__gthread_getspecific (__gthread_key_t __key);
int
__gthread_setspecific (__gthread_key_t __key, const void *__ptr);
void
__gthread_mutex_init_function (__gthread_mutex_t *__mutex);
int
__gthread_mutex_destroy (__gthread_mutex_t *__mutex);
int
__gthread_mutex_lock (__gthread_mutex_t *__mutex);
int
__gthread_mutex_trylock (__gthread_mutex_t *__mutex);
int
__gthread_mutex_unlock (__gthread_mutex_t *__mutex);
int
__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *__mutex);
int
__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *__mutex);
int
__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex);
int
__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *__mutex);
int
__gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t *__mutex);
void
__gthread_cond_init_function (__gthread_cond_t *__cond);
int
__gthread_cond_broadcast (__gthread_cond_t *__cond);
int
__gthread_cond_signal (__gthread_cond_t *__cond);
int
__gthread_cond_wait (__gthread_cond_t *__cond, __gthread_mutex_t *__mutex);
int
__gthread_cond_timedwait (__gthread_cond_t *__cond, __gthread_mutex_t *__mutex,
const __gthread_time_t *__abs_timeout);
int
__gthread_cond_wait_recursive (__gthread_cond_t *__cond,
__gthread_recursive_mutex_t *__mutex);
int
__gthread_cond_destroy (__gthread_cond_t* __cond);
#endif /* ! _GLIBCXX_GCC_GTHR_SINGLE_H */

View File

@ -1,97 +0,0 @@
// mutex -*- C++ -*-
// Copyright (C) 2008-2018 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.
// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <http://www.gnu.org/licenses/>.
#include <mutex>
#if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
#ifndef _GLIBCXX_HAVE_TLS
namespace
{
inline std::unique_lock<std::mutex>*&
__get_once_functor_lock_ptr()
{
static std::unique_lock<std::mutex>* __once_functor_lock_ptr = 0;
return __once_functor_lock_ptr;
}
}
#endif
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
#ifdef _GLIBCXX_HAVE_TLS
__thread void* __once_callable;
__thread void (*__once_call)();
#else
// Explicit instantiation due to -fno-implicit-instantiation.
template class function<void()>;
function<void()> __once_functor;
mutex&
__get_once_mutex()
{
static mutex once_mutex;
return once_mutex;
}
// code linked against ABI 3.4.12 and later uses this
void
__set_once_functor_lock_ptr(unique_lock<mutex>* __ptr)
{
__get_once_functor_lock_ptr() = __ptr;
}
// unsafe - retained for compatibility with ABI 3.4.11
unique_lock<mutex>&
__get_once_functor_lock()
{
static unique_lock<mutex> once_functor_lock(__get_once_mutex(), defer_lock);
return once_functor_lock;
}
#endif
extern "C"
{
void __once_proxy()
{
#ifndef _GLIBCXX_HAVE_TLS
function<void()> __once_call = std::move(__once_functor);
if (unique_lock<mutex>* __lock = __get_once_functor_lock_ptr())
{
// caller is using new ABI and provided lock ptr
__get_once_functor_lock_ptr() = 0;
__lock->unlock();
}
else
__get_once_functor_lock().unlock(); // global lock
#endif
__once_call();
}
}
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1

View File

@ -1,88 +0,0 @@
// Support for pointer abstractions -*- C++ -*-
// Copyright (C) 2011-2018 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.
// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <http://www.gnu.org/licenses/>.
#include <memory>
namespace __gnu_internal _GLIBCXX_VISIBILITY(hidden)
{
const unsigned char mask = 0xf;
const unsigned char invalid = mask + 1;
/* Returns different instances of __mutex depending on the passed index
* in order to limit contention.
*/
__gnu_cxx::__mutex& get_mutex(unsigned char i);
}
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
#ifdef __GTHREADS
namespace
{
inline unsigned char key(const void* addr)
{ return _Hash_impl::hash(addr) & __gnu_internal::mask; }
}
_Sp_locker::_Sp_locker(const void* p) noexcept
{
if (__gthread_active_p())
{
_M_key1 = _M_key2 = key(p);
__gnu_internal::get_mutex(_M_key1).lock();
}
else
_M_key1 = _M_key2 = __gnu_internal::invalid;
}
_Sp_locker::_Sp_locker(const void* p1, const void* p2) noexcept
{
if (__gthread_active_p())
{
_M_key1 = key(p1);
_M_key2 = key(p2);
if (_M_key2 < _M_key1)
__gnu_internal::get_mutex(_M_key2).lock();
__gnu_internal::get_mutex(_M_key1).lock();
if (_M_key2 > _M_key1)
__gnu_internal::get_mutex(_M_key2).lock();
}
else
_M_key1 = _M_key2 = __gnu_internal::invalid;
}
_Sp_locker::~_Sp_locker()
{
if (_M_key1 != __gnu_internal::invalid)
{
__gnu_internal::get_mutex(_M_key1).unlock();
if (_M_key2 != _M_key1)
__gnu_internal::get_mutex(_M_key2).unlock();
}
}
#endif
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace

View File

@ -1,218 +0,0 @@
// thread -*- C++ -*-
// Copyright (C) 2008-2018 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.
// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <http://www.gnu.org/licenses/>.
#define _GLIBCXX_THREAD_ABI_COMPAT 1
#include <thread>
#include <system_error>
#include <cerrno>
#include <bits/cxxabi_forced.h>
#if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
#if defined(_GLIBCXX_USE_GET_NPROCS)
# include <sys/sysinfo.h>
# define _GLIBCXX_NPROCS get_nprocs()
#elif defined(_GLIBCXX_USE_PTHREADS_NUM_PROCESSORS_NP)
# define _GLIBCXX_NPROCS pthread_num_processors_np()
#elif defined(_GLIBCXX_USE_SYSCTL_HW_NCPU)
# include <stddef.h>
# include <sys/sysctl.h>
static inline int get_nprocs()
{
int count;
size_t size = sizeof(count);
int mib[] = { CTL_HW, HW_NCPU };
if (!sysctl(mib, 2, &count, &size, NULL, 0))
return count;
return 0;
}
# define _GLIBCXX_NPROCS get_nprocs()
#elif defined(_GLIBCXX_USE_SC_NPROCESSORS_ONLN)
# include <unistd.h>
# define _GLIBCXX_NPROCS sysconf(_SC_NPROCESSORS_ONLN)
#elif defined(_GLIBCXX_USE_SC_NPROC_ONLN)
# include <unistd.h>
# define _GLIBCXX_NPROCS sysconf(_SC_NPROC_ONLN)
#else
# define _GLIBCXX_NPROCS 0
#endif
#ifndef _GLIBCXX_USE_NANOSLEEP
# ifdef _GLIBCXX_HAVE_SLEEP
# include <unistd.h>
# elif defined(_GLIBCXX_HAVE_WIN32_SLEEP)
# include <windows.h>
# else
# error "No sleep function known for this target"
# endif
#endif
namespace std _GLIBCXX_VISIBILITY(default)
{
extern "C"
{
static void*
execute_native_thread_routine(void* __p)
{
thread::_State_ptr __t{ static_cast<thread::_State*>(__p) };
__t->_M_run();
return nullptr;
}
#if _GLIBCXX_THREAD_ABI_COMPAT
static void*
execute_native_thread_routine_compat(void* __p)
{
thread::_Impl_base* __t = static_cast<thread::_Impl_base*>(__p);
thread::__shared_base_type __local;
// Now that a new thread has been created we can transfer ownership of
// the thread state to a local object, breaking the reference cycle
// created in thread::_M_start_thread.
__local.swap(__t->_M_this_ptr);
__t->_M_run();
return nullptr;
}
#endif
} // extern "C"
_GLIBCXX_BEGIN_NAMESPACE_VERSION
thread::_State::~_State() = default;
void
thread::join()
{
int __e = EINVAL;
if (_M_id != id())
__e = __gthread_join(_M_id._M_thread, 0);
if (__e)
__throw_system_error(__e);
_M_id = id();
}
void
thread::detach()
{
int __e = EINVAL;
if (_M_id != id())
__e = __gthread_detach(_M_id._M_thread);
if (__e)
__throw_system_error(__e);
_M_id = id();
}
void
thread::_M_start_thread(_State_ptr state, void (*)())
{
const int err = __gthread_create(&_M_id._M_thread,
&execute_native_thread_routine,
state.get());
if (err)
__throw_system_error(err);
state.release();
}
#if _GLIBCXX_THREAD_ABI_COMPAT
void
thread::_M_start_thread(__shared_base_type __b)
{
if (!__gthread_active_p())
#if __cpp_exceptions
throw system_error(make_error_code(errc::operation_not_permitted),
"Enable multithreading to use std::thread");
#else
__throw_system_error(int(errc::operation_not_permitted));
#endif
_M_start_thread(std::move(__b), nullptr);
}
void
thread::_M_start_thread(__shared_base_type __b, void (*)())
{
auto ptr = __b.get();
// Create a reference cycle that will be broken in the new thread.
ptr->_M_this_ptr = std::move(__b);
int __e = __gthread_create(&_M_id._M_thread,
&execute_native_thread_routine_compat, ptr);
if (__e)
{
ptr->_M_this_ptr.reset(); // break reference cycle, destroying *ptr.
__throw_system_error(__e);
}
}
#endif
unsigned int
thread::hardware_concurrency() noexcept
{
return 3;
}
namespace this_thread
{
void
__sleep_for(chrono::seconds __s, chrono::nanoseconds __ns)
{
#ifdef _GLIBCXX_USE_NANOSLEEP
__gthread_time_t __ts =
{
static_cast<std::time_t>(__s.count()),
static_cast<long>(__ns.count())
};
while (::nanosleep(&__ts, &__ts) == -1 && errno == EINTR)
{ }
#elif defined(_GLIBCXX_HAVE_SLEEP)
# ifdef _GLIBCXX_HAVE_USLEEP
::sleep(__s.count());
if (__ns.count() > 0)
{
long __us = __ns.count() / 1000;
if (__us == 0)
__us = 1;
::usleep(__us);
}
# else
::sleep(__s.count() + (__ns.count() >= 1000000));
# endif
#elif defined(_GLIBCXX_HAVE_WIN32_SLEEP)
unsigned long ms = __ns.count() / 1000000;
if (__ns.count() > 0 && ms == 0)
ms = 1;
::Sleep(chrono::milliseconds(__s).count() + ms);
#endif
}
}
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1

View File

@ -0,0 +1,78 @@
#include "wut_gthread.h"
#include <bits/gthr-default.h>
typedef int (* __gthread_fn_active) (void);
typedef int (* __gthread_fn_create) (__gthread_t *__threadid, void *(*__func) (void*), void *__args);
typedef int (* __gthread_fn_join) (__gthread_t __threadid, void **__value_ptr);
typedef int (* __gthread_fn_detach) (__gthread_t __threadid);
typedef int (* __gthread_fn_equal) (__gthread_t __t1, __gthread_t __t2);
typedef __gthread_t (* __gthread_fn_self) (void);
typedef int (* __gthread_fn_yield) (void);
typedef int (* __gthread_fn_once) (__gthread_once_t *__once, void (*__func) (void));
typedef int (* __gthread_fn_key_create) (__gthread_key_t *__key, void (*__dtor) (void *));
typedef int (* __gthread_fn_key_delete) (__gthread_key_t __key);
typedef void *(* __gthread_fn_getspecific) (__gthread_key_t __key);
typedef int (* __gthread_fn_setspecific) (__gthread_key_t __key, const void *__ptr);
typedef void (* __gthread_fn_mutex_init_function) (__gthread_mutex_t *__mutex);
typedef int (* __gthread_fn_mutex_destroy) (__gthread_mutex_t *__mutex);
typedef int (* __gthread_fn_mutex_lock) (__gthread_mutex_t *__mutex);
typedef int (* __gthread_fn_mutex_trylock) (__gthread_mutex_t *__mutex);
typedef int (* __gthread_fn_mutex_unlock) (__gthread_mutex_t *__mutex);
typedef int (* __gthread_fn_recursive_mutex_init_function) (__gthread_recursive_mutex_t *__mutex);
typedef int (* __gthread_fn_recursive_mutex_lock) (__gthread_recursive_mutex_t *__mutex);
typedef int (* __gthread_fn_recursive_mutex_trylock) (__gthread_recursive_mutex_t *__mutex);
typedef int (* __gthread_fn_recursive_mutex_unlock) (__gthread_recursive_mutex_t *__mutex);
typedef int (* __gthread_fn_recursive_mutex_destroy) (__gthread_recursive_mutex_t *__mutex);
typedef void (* __gthread_fn_cond_init_function) (__gthread_cond_t *__cond);
typedef int (* __gthread_fn_cond_broadcast) (__gthread_cond_t *__cond);
typedef int (* __gthread_fn_cond_signal) (__gthread_cond_t *__cond);
typedef int (* __gthread_fn_cond_wait) (__gthread_cond_t *__cond, __gthread_mutex_t *__mutex);
typedef int (* __gthread_fn_cond_timedwait) (__gthread_cond_t *__cond, __gthread_mutex_t *__mutex, const __gthread_time_t *__abs_timeout);
typedef int (* __gthread_fn_cond_wait_recursive) (__gthread_cond_t *__cond, __gthread_recursive_mutex_t *__mutex);
typedef int (* __gthread_fn_cond_destroy) (__gthread_cond_t* __cond);
int
__wut_active_p()
{
return 1;
}
extern "C"
{
void
__init_wut_gthread()
{
__gthread_impl.active = &__wut_active_p;
__gthread_impl.active = (__gthread_fn_active)__wut_active_p;
__gthread_impl.create = (__gthread_fn_create)__wut_thread_create;
__gthread_impl.join = (__gthread_fn_join)__wut_thread_join;
__gthread_impl.detach = (__gthread_fn_detach)__wut_thread_detach;
__gthread_impl.equal = (__gthread_fn_equal)__wut_thread_equal;
__gthread_impl.self = (__gthread_fn_self)__wut_thread_self;
__gthread_impl.yield = (__gthread_fn_yield)__wut_thread_yield;
__gthread_impl.once = (__gthread_fn_once)__wut_once;
__gthread_impl.key_create = (__gthread_fn_key_create)__wut_key_create;
__gthread_impl.key_delete = (__gthread_fn_key_delete)__wut_key_delete;
__gthread_impl.getspecific = (__gthread_fn_getspecific)__wut_getspecific;
__gthread_impl.setspecific = (__gthread_fn_setspecific)__wut_setspecific;
__gthread_impl.mutex_init_function = (__gthread_fn_mutex_init_function)__wut_mutex_init_function;
__gthread_impl.mutex_destroy = (__gthread_fn_mutex_destroy)__wut_mutex_destroy;
__gthread_impl.mutex_lock = (__gthread_fn_mutex_lock)__wut_mutex_lock;
__gthread_impl.mutex_trylock = (__gthread_fn_mutex_trylock)__wut_mutex_trylock;
__gthread_impl.mutex_unlock = (__gthread_fn_mutex_unlock)__wut_mutex_unlock;
__gthread_impl.recursive_mutex_init_function = (__gthread_fn_recursive_mutex_init_function)__wut_recursive_mutex_init_function;
__gthread_impl.recursive_mutex_lock = (__gthread_fn_recursive_mutex_lock)__wut_recursive_mutex_lock;
__gthread_impl.recursive_mutex_trylock = (__gthread_fn_recursive_mutex_trylock)__wut_recursive_mutex_trylock;
__gthread_impl.recursive_mutex_unlock = (__gthread_fn_recursive_mutex_unlock)__wut_recursive_mutex_unlock;
__gthread_impl.recursive_mutex_destroy = (__gthread_fn_recursive_mutex_destroy)__wut_recursive_mutex_destroy;
__gthread_impl.cond_init_function = (__gthread_fn_cond_init_function)__wut_cond_init_function;
__gthread_impl.cond_broadcast = (__gthread_fn_cond_broadcast)__wut_cond_broadcast;
__gthread_impl.cond_signal = (__gthread_fn_cond_signal)__wut_cond_signal;
__gthread_impl.cond_wait = (__gthread_fn_cond_wait)__wut_cond_wait;
__gthread_impl.cond_timedwait = (__gthread_fn_cond_timedwait)__wut_cond_timedwait;
__gthread_impl.cond_wait_recursive = (__gthread_fn_cond_wait_recursive)__wut_cond_wait_recursive;
__gthread_impl.cond_destroy = (__gthread_fn_cond_destroy)__wut_cond_destroy;
}
} // extern "c"

View File

@ -0,0 +1,122 @@
#pragma once
#include <bits/gthr-default.h>
#include <coreinit/atomic.h>
#include <coreinit/condition.h>
#include <coreinit/thread.h>
#include <coreinit/mutex.h>
#include <coreinit/baseheap.h>
#include <coreinit/expandedheap.h>
#define __WUT_MAX_KEYS (128)
#define __WUT_STACK_SIZE (4096*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 (0)
typedef volatile uint32_t __wut_once_t;
typedef uint32_t __wut_key_t;
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);

View File

@ -0,0 +1,100 @@
#include "wut_gthread.h"
#include <sys/errno.h>
#include <coreinit/alarm.h>
#include <coreinit/systeminfo.h>
#include <coreinit/time.h>
#include <chrono>
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;
auto time = std::chrono::system_clock::now();
auto timeout = std::chrono::system_clock::time_point(
std::chrono::seconds(abs_timeout->tv_sec) +
std::chrono::nanoseconds(abs_timeout->tv_nsec));
// Already timed out!
if (timeout <= time) {
return ETIMEDOUT;
}
auto duration =
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout - time);
// Set an alarm
OSAlarm alarm;
OSCreateAlarm(&alarm);
OSSetAlarmUserData(&alarm, &data);
OSSetAlarm(&alarm, OSNanoseconds(duration.count()),
&__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;
}

View File

@ -0,0 +1,102 @@
#include "wut_gthread.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 (int 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 = (__wut_key_t)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].in_use = 0;
key_table[key].dtor = NULL;
__wut_mutex_unlock(&key_mutex);
return -1;
}
static const void **
__wut_get_thread_keys()
{
const void **keys = (const void **)OSGetThreadSpecific(__WUT_KEY_THREAD_SPECIFIC_ID);
if (!keys) {
MEMExpandedHeap *heap = (MEMExpandedHeap *)MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM2);
keys = (const void **)MEMAllocFromExpHeapEx(heap, sizeof(void *) * sizeof(__WUT_MAX_KEYS), 4);
memset(keys, 0, sizeof(void *) * sizeof(__WUT_MAX_KEYS));
OSSetThreadSpecific(__WUT_KEY_THREAD_SPECIFIC_ID, keys);
}
return keys;
}
void *
__wut_getspecific(__wut_key_t key)
{
return (void *)__wut_get_thread_keys()[key];
}
int
__wut_setspecific(__wut_key_t key,
const void *ptr)
{
__wut_get_thread_keys()[key] = ptr;
return 0;
}
void
__wut_key_cleanup(OSThread *thread)
{
void **keys = (void **)OSGetThreadSpecific(__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);
}

View File

@ -0,0 +1,37 @@
#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;
}

View File

@ -0,0 +1,24 @@
#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();
OSCompareAndSwapAtomic(once,
__WUT_ONCE_VALUE_STARTED,
__WUT_ONCE_VALUE_DONE);
} else if (value != __WUT_ONCE_VALUE_DONE) {
while (!OSCompareAndSwapAtomic(once,
__WUT_ONCE_VALUE_DONE,
__WUT_ONCE_VALUE_DONE));
}
return 0;
}

View File

@ -0,0 +1,38 @@
#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;
}

View File

@ -0,0 +1,86 @@
#include "wut_gthread.h"
#include <string.h>
#include <sys/errno.h>
static void
__wut_thread_deallocator(OSThread *thread,
void *stack)
{
MEMExpandedHeap *heap = (MEMExpandedHeap *)MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM2);
MEMFreeToExpHeap(heap, thread);
MEMFreeToExpHeap(heap, 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)
{
MEMExpandedHeap *heap = (MEMExpandedHeap *)MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM2);
OSThread *thread = (OSThread *)MEMAllocFromExpHeapEx(heap, sizeof(OSThread), 8);
char *stack = (char *)MEMAllocFromExpHeapEx(heap, __WUT_STACK_SIZE, 8);
memset(thread, 0, sizeof(OSThread));
if (!OSCreateThread(thread,
(OSThreadEntryPointFn)entryPoint,
(int)entryArgs,
NULL,
stack + __WUT_STACK_SIZE,
__WUT_STACK_SIZE,
16,
OS_THREAD_ATTRIB_AFFINITY_ANY)) {
MEMFreeToExpHeap((MEMExpandedHeap*)MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM2), thread);
return EINVAL;
}
*outThread = thread;
OSSetThreadDeallocator(thread, &__wut_thread_deallocator);
OSSetThreadCleanupCallback(thread, &__wut_thread_cleanup);
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;
}

View File

@ -2,13 +2,12 @@ cmake_minimum_required(VERSION 3.2)
macro(wut_enable_stdcpp target)
target_link_libraries(${target}
wutstdc++)
target_compile_definitions(${target}
PRIVATE _GLIBCXX_HAS_GTHREADS)
wutnewlib
stdc++)
set_target_properties(${target} PROPERTIES
COMPILE_FLAGS "-std=c++17")
COMPILE_FLAGS "-std=c++17"
LINK_FLAGS "-Wl,--whole-archive -lwutstdc++ -Wl,--no-whole-archive")
endmacro(wut_enable_stdcpp)
macro(wut_create_rpx target source)