mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-07 08:36:02 -10:00
GameCube/Wii: build os/gekko on every devkitPPC
newlib.c serves all three generations of devkitPPC's newlib system hooks, picked at compile time: r49's lock, condition and thread hooks; newlib 4.3's split plain and recursive lock hooks over int-sized locks; and the older single set that takes the lock kind at init, which also leaves __getreent to the system. On the int-sized locks a plain lock is a gk_mutex_t word and a recursive one a small handle into a table of gk_rmutex_t. rthreads and rcheevos run on os/gekko's own threads and mutexes rather than newlib's pthreads, which only exist from r49.
This commit is contained in:
1 parent
cfb1204314
commit
2c724ff91c
4 files changed
+302
-9
No files matched your search
Vendored
+25
@@ -249,6 +249,31 @@ void rc_mutex_unlock(rc_mutex_t* mutex)
|
||||
sceKernelUnlockMutex(mutex->handle, 1);
|
||||
}
|
||||
|
||||
#elif defined(GEKKO_NATIVE)
|
||||
|
||||
/* RetroArch-local: os/gekko's recursive mutex. */
|
||||
|
||||
void rc_mutex_init(rc_mutex_t* mutex)
|
||||
{
|
||||
mutex->m.word = 0;
|
||||
mutex->depth = 0;
|
||||
}
|
||||
|
||||
void rc_mutex_destroy(rc_mutex_t* mutex)
|
||||
{
|
||||
(void)mutex;
|
||||
}
|
||||
|
||||
void rc_mutex_lock(rc_mutex_t* mutex)
|
||||
{
|
||||
gk_rmutex_lock(mutex);
|
||||
}
|
||||
|
||||
void rc_mutex_unlock(rc_mutex_t* mutex)
|
||||
{
|
||||
gk_rmutex_unlock(mutex);
|
||||
}
|
||||
|
||||
#elif defined(WIIU)
|
||||
|
||||
/* RetroArch-local: OSMutex is recursive, matching the recursive pthread
|
||||
|
||||
Vendored
+5
@@ -102,6 +102,11 @@ RC_BEGIN_C_DECLS
|
||||
typedef struct rc_mutex_t {
|
||||
mutex_t handle;
|
||||
} rc_mutex_t;
|
||||
#elif defined(GEKKO_NATIVE)
|
||||
/* RetroArch-local: os/gekko's recursive mutex, which every devkitPPC
|
||||
* can build; newlib's pthreads only came with r49. */
|
||||
#include <gekko/thread.h>
|
||||
typedef gk_rmutex_t rc_mutex_t;
|
||||
#elif defined(WIIU)
|
||||
/* RetroArch-local: rthreads drives Cafe OS threads natively here, so
|
||||
* rcheevos cannot use the pthread backend -- devkitPPC ships
|
||||
|
||||
@@ -63,6 +63,113 @@
|
||||
#include <ogc/mutex.h>
|
||||
#include <ogc/cond.h>
|
||||
#define STACKSIZE (8 * 1024)
|
||||
#elif defined(GEKKO_NATIVE)
|
||||
/* os/gekko's own threads under the pthread names used below, so this
|
||||
* builds on every devkitPPC: newlib's pthreads only came with r49. */
|
||||
#define USE_GEKKO_THREADS
|
||||
#include <errno.h>
|
||||
#include <gekko/gekko.h>
|
||||
#include <gekko/thread.h>
|
||||
#include <retro_inline.h>
|
||||
|
||||
typedef gk_thread_t *rthreads_gk_thread_t;
|
||||
typedef struct
|
||||
{
|
||||
size_t stack_size;
|
||||
} rthreads_gk_attr_t;
|
||||
|
||||
static INLINE int rthreads_gk_attr_init(rthreads_gk_attr_t *attr)
|
||||
{
|
||||
attr->stack_size = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INLINE int rthreads_gk_attr_setstacksize(rthreads_gk_attr_t *attr,
|
||||
size_t stack_size)
|
||||
{
|
||||
attr->stack_size = stack_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INLINE int rthreads_gk_create(gk_thread_t **t,
|
||||
const rthreads_gk_attr_t *attr, void *(*fn)(void*), void *arg)
|
||||
{
|
||||
*t = gk_thread_create(fn, arg, NULL,
|
||||
(attr && attr->stack_size) ? attr->stack_size : 64 * 1024,
|
||||
GK_PRIO_DEFAULT);
|
||||
return *t ? 0 : EAGAIN;
|
||||
}
|
||||
|
||||
static INLINE int rthreads_gk_join(gk_thread_t *t)
|
||||
{
|
||||
gk_thread_join(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INLINE int rthreads_gk_detach(gk_thread_t *t)
|
||||
{
|
||||
gk_thread_detach(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INLINE int rthreads_gk_mutex_init(gk_mutex_t *m)
|
||||
{
|
||||
m->word = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INLINE int rthreads_gk_mutex_lock(gk_mutex_t *m)
|
||||
{
|
||||
gk_mutex_lock(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INLINE int rthreads_gk_mutex_unlock(gk_mutex_t *m)
|
||||
{
|
||||
gk_mutex_unlock(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INLINE int rthreads_gk_cond_init(gk_cond_t *c)
|
||||
{
|
||||
c->seq = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INLINE int rthreads_gk_cond_signal(gk_cond_t *c)
|
||||
{
|
||||
gk_cond_signal(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INLINE int rthreads_gk_cond_broadcast(gk_cond_t *c)
|
||||
{
|
||||
gk_cond_broadcast(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define pthread_t rthreads_gk_thread_t
|
||||
#define pthread_attr_t rthreads_gk_attr_t
|
||||
#define pthread_mutex_t gk_mutex_t
|
||||
#define pthread_cond_t gk_cond_t
|
||||
#define pthread_attr_init(a) rthreads_gk_attr_init(a)
|
||||
#define pthread_attr_destroy(a) ((void)(a))
|
||||
#define pthread_attr_setstacksize(a, n) rthreads_gk_attr_setstacksize(a, n)
|
||||
#define pthread_create(t, a, fn, arg) rthreads_gk_create(t, a, fn, arg)
|
||||
#define pthread_join(t, r) rthreads_gk_join(t)
|
||||
#define pthread_detach(t) rthreads_gk_detach(t)
|
||||
#define pthread_self() gk_thread_self()
|
||||
#define pthread_equal(a, b) ((a) == (b))
|
||||
#define pthread_mutex_init(m, a) rthreads_gk_mutex_init(m)
|
||||
#define pthread_mutex_destroy(m) ((void)(m))
|
||||
#define pthread_mutex_lock(m) rthreads_gk_mutex_lock(m)
|
||||
#define pthread_mutex_trylock(m) gk_mutex_trylock(m)
|
||||
#define pthread_mutex_unlock(m) rthreads_gk_mutex_unlock(m)
|
||||
#define pthread_cond_init(c, a) rthreads_gk_cond_init(c)
|
||||
#define pthread_cond_destroy(c) ((void)(c))
|
||||
#define pthread_cond_wait(c, m) gk_cond_wait(c, m, GK_WAIT_FOREVER)
|
||||
#define pthread_cond_signal(c) rthreads_gk_cond_signal(c)
|
||||
#define pthread_cond_broadcast(c) rthreads_gk_cond_broadcast(c)
|
||||
#elif defined(_3DS)
|
||||
#define USE_CTR_THREADS
|
||||
#include <3ds/thread.h>
|
||||
@@ -1293,7 +1400,7 @@ static sthread_t *sthread_create_ex(void (*thread_func)(void*),
|
||||
#ifdef HAVE_THREAD_ATTR
|
||||
pthread_attr_init(&thread_attr);
|
||||
|
||||
/* devkitPPC's pthreads have no scheduling policy to set. */
|
||||
/* os/gekko's threads take no scheduling policy. */
|
||||
#ifndef GEKKO_NATIVE
|
||||
if ((thread_priority >= 1) && (thread_priority <= 100))
|
||||
{
|
||||
@@ -2190,6 +2297,8 @@ void sthread_yield(void)
|
||||
RotateThreadReadyQueue(0);
|
||||
#elif defined(USE_PS3_THREADS)
|
||||
rthreads_ps3_thread_yield();
|
||||
#elif defined(USE_GEKKO_THREADS)
|
||||
gk_thread_yield();
|
||||
#else
|
||||
sched_yield();
|
||||
#endif
|
||||
@@ -3572,6 +3681,11 @@ bool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us)
|
||||
}
|
||||
slock_lock(lock);
|
||||
return woken;
|
||||
#elif defined(USE_GEKKO_THREADS)
|
||||
if (timeout_us <= 0)
|
||||
return false;
|
||||
return gk_cond_wait(&cond->cond, &lock->lock,
|
||||
GK_US_TO_TICKS(timeout_us)) != GK_ETIMEDOUT;
|
||||
#elif defined(RTHREADS_FUTEX_SCOND)
|
||||
/* FUTEX_WAIT_BITSET takes an absolute CLOCK_MONOTONIC deadline, so
|
||||
* a spurious wake never shortens or stretches the wait. */
|
||||
@@ -3751,7 +3865,8 @@ bool sthread_is_main_thread(void)
|
||||
&& !defined(USE_CTR_THREADS) && !defined(USE_PSP_THREADS) \
|
||||
&& !defined(USE_VITA_THREADS) && !defined(USE_WIIU_THREADS) \
|
||||
&& !defined(USE_SWITCH_THREADS) && !defined(USE_PS2_THREADS) \
|
||||
&& !defined(USE_PS3_THREADS) && !defined(__ANDROID__)
|
||||
&& !defined(USE_PS3_THREADS) && !defined(USE_GEKKO_THREADS) \
|
||||
&& !defined(__ANDROID__)
|
||||
#define RTHREADS_HAVE_CANCEL 1
|
||||
#endif
|
||||
|
||||
|
||||
+155
-7
@@ -1,11 +1,16 @@
|
||||
/* The C library's system interface: heap, locks, threads, time.
|
||||
*
|
||||
* newlib's locks are the kernel's mutexes outright: _LOCK_T is one
|
||||
* zero-initialised word and _LOCK_RECURSIVE_T a word and a depth,
|
||||
* exactly gk_mutex_t and gk_rmutex_t. */
|
||||
* devkitPPC's newlib has had three sets of system hooks, all served
|
||||
* here. From r49 (sys/lock.h defines __COND_INITIALIZER) the locks are
|
||||
* the kernel's mutexes outright: _LOCK_T is one zero-initialised word
|
||||
* and _LOCK_RECURSIVE_T a word and a depth, exactly gk_mutex_t and
|
||||
* gk_rmutex_t, and conditions and threads are hooks too. From newlib
|
||||
* 4.3 there are separate hooks for plain and recursive locks, both one
|
||||
* int; before it one set of hooks takes the kind at init. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <newlib.h>
|
||||
#include <reent.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -18,14 +23,19 @@
|
||||
|
||||
#include "kernel.h"
|
||||
|
||||
/* newlib's lock, condition and thread hooks came with devkitPPC r49. */
|
||||
#ifndef __COND_INITIALIZER
|
||||
#error "os/gekko needs devkitPPC r49 or later"
|
||||
#if defined(__COND_INITIALIZER)
|
||||
#define GK_NEWLIB_HOOKS 3
|
||||
#elif __NEWLIB__ > 4 || (__NEWLIB__ == 4 && __NEWLIB_MINOR__ >= 3)
|
||||
#define GK_NEWLIB_HOOKS 2
|
||||
#else
|
||||
#define GK_NEWLIB_HOOKS 1
|
||||
#endif
|
||||
|
||||
typedef char assert_lock_size[sizeof(_LOCK_T) == sizeof(gk_mutex_t) ? 1 : -1];
|
||||
#if GK_NEWLIB_HOOKS >= 3
|
||||
typedef char assert_rlock_size[
|
||||
sizeof(_LOCK_RECURSIVE_T) == sizeof(gk_rmutex_t) ? 1 : -1];
|
||||
#endif
|
||||
typedef char assert_ctx_size[sizeof(struct gk_ctx) == CTX_SIZE ? 1 : -1];
|
||||
typedef char assert_fp_off[
|
||||
offsetof(struct gk_thread, fp) == THR_FP ? 1 : -1];
|
||||
@@ -87,7 +97,7 @@ int posix_memalign(void **out, size_t align, size_t size)
|
||||
|
||||
/* ---- per-thread C library state ---- */
|
||||
|
||||
struct _reent *__syscall_getreent(void)
|
||||
static struct _reent *cur_reent(void)
|
||||
{
|
||||
struct gk_thread *t = gk_cur;
|
||||
if (!t || t == gk_sched_main())
|
||||
@@ -95,8 +105,15 @@ struct _reent *__syscall_getreent(void)
|
||||
return &t->reent;
|
||||
}
|
||||
|
||||
#if GK_NEWLIB_HOOKS >= 2
|
||||
struct _reent *__syscall_getreent(void) { return cur_reent(); }
|
||||
#else
|
||||
struct _reent *__getreent(void) { return cur_reent(); }
|
||||
#endif
|
||||
|
||||
/* ---- locks ---- */
|
||||
|
||||
#if GK_NEWLIB_HOOKS >= 3
|
||||
void __syscall_lock_init(_LOCK_T *lock) { *lock = 0; }
|
||||
void __syscall_lock_acquire(_LOCK_T *lock)
|
||||
{
|
||||
@@ -132,6 +149,133 @@ void __syscall_lock_close_recursive(_LOCK_RECURSIVE_T *lock)
|
||||
{
|
||||
(void)lock;
|
||||
}
|
||||
#else
|
||||
/* A plain int lock is a gk_mutex_t word. A recursive one holds 1 + its
|
||||
* slot in rlocks, which no thread pointer is small enough to equal.
|
||||
* newlib initialises a lock it finds zero just before taking it, so init
|
||||
* never clears a word another thread may have taken in between. */
|
||||
#define GK_RLOCKS 128
|
||||
|
||||
static gk_rmutex_t rlocks[GK_RLOCKS];
|
||||
static int *rlock_owner[GK_RLOCKS];
|
||||
|
||||
static gk_rmutex_t *rlock_get(int *lock)
|
||||
{
|
||||
uint32_t i = (uint32_t)*lock - 1u;
|
||||
return (i < GK_RLOCKS && rlock_owner[i] == lock) ? &rlocks[i] : NULL;
|
||||
}
|
||||
|
||||
static gk_rmutex_t *rlock_init(int *lock)
|
||||
{
|
||||
gk_rmutex_t *m;
|
||||
uint32_t i;
|
||||
uint32_t level = gk_irq_disable();
|
||||
if (!(m = rlock_get(lock)))
|
||||
{
|
||||
for (i = 0; i < GK_RLOCKS && rlock_owner[i]; i++);
|
||||
if (i == GK_RLOCKS)
|
||||
gk_panic("out of C library locks");
|
||||
rlock_owner[i] = lock;
|
||||
rlocks[i].m.word = 0;
|
||||
rlocks[i].depth = 0;
|
||||
*lock = (int)(i + 1u);
|
||||
m = &rlocks[i];
|
||||
}
|
||||
gk_irq_restore(level);
|
||||
return m;
|
||||
}
|
||||
|
||||
static void rlock_close(int *lock)
|
||||
{
|
||||
uint32_t level = gk_irq_disable();
|
||||
gk_rmutex_t *m = rlock_get(lock);
|
||||
if (m)
|
||||
{
|
||||
rlock_owner[m - rlocks] = NULL;
|
||||
*lock = 0;
|
||||
}
|
||||
gk_irq_restore(level);
|
||||
}
|
||||
|
||||
static void rlock_release(int *lock)
|
||||
{
|
||||
gk_rmutex_t *m = rlock_get(lock);
|
||||
if (m)
|
||||
gk_rmutex_unlock(m);
|
||||
}
|
||||
|
||||
#if GK_NEWLIB_HOOKS == 2
|
||||
void __syscall_lock_init(_LOCK_T *lock) { (void)lock; }
|
||||
void __syscall_lock_acquire(_LOCK_T *lock)
|
||||
{
|
||||
gk_mutex_lock((gk_mutex_t*)lock);
|
||||
}
|
||||
int __syscall_lock_try_acquire(_LOCK_T *lock)
|
||||
{
|
||||
return gk_mutex_trylock((gk_mutex_t*)lock);
|
||||
}
|
||||
void __syscall_lock_release(_LOCK_T *lock)
|
||||
{
|
||||
gk_mutex_unlock((gk_mutex_t*)lock);
|
||||
}
|
||||
void __syscall_lock_close(_LOCK_T *lock) { (void)lock; }
|
||||
|
||||
void __syscall_lock_init_recursive(_LOCK_RECURSIVE_T *lock)
|
||||
{
|
||||
rlock_init(lock);
|
||||
}
|
||||
void __syscall_lock_acquire_recursive(_LOCK_RECURSIVE_T *lock)
|
||||
{
|
||||
gk_rmutex_lock(rlock_init(lock));
|
||||
}
|
||||
int __syscall_lock_try_acquire_recursive(_LOCK_RECURSIVE_T *lock)
|
||||
{
|
||||
return gk_rmutex_trylock(rlock_init(lock));
|
||||
}
|
||||
void __syscall_lock_release_recursive(_LOCK_RECURSIVE_T *lock)
|
||||
{
|
||||
rlock_release(lock);
|
||||
}
|
||||
void __syscall_lock_close_recursive(_LOCK_RECURSIVE_T *lock)
|
||||
{
|
||||
rlock_close(lock);
|
||||
}
|
||||
#else
|
||||
static int rlock_is_handle(const int *lock)
|
||||
{
|
||||
return (uint32_t)*lock - 1u < GK_RLOCKS;
|
||||
}
|
||||
|
||||
int __syscall_lock_init(int *lock, int recursive)
|
||||
{
|
||||
if (recursive)
|
||||
rlock_init(lock);
|
||||
return 0;
|
||||
}
|
||||
int __syscall_lock_acquire(int *lock)
|
||||
{
|
||||
if (rlock_is_handle(lock))
|
||||
gk_rmutex_lock(rlock_init(lock));
|
||||
else
|
||||
gk_mutex_lock((gk_mutex_t*)lock);
|
||||
return 0;
|
||||
}
|
||||
int __syscall_lock_release(int *lock)
|
||||
{
|
||||
if (rlock_is_handle(lock))
|
||||
rlock_release(lock);
|
||||
else
|
||||
gk_mutex_unlock((gk_mutex_t*)lock);
|
||||
return 0;
|
||||
}
|
||||
int __syscall_lock_close(int *lock)
|
||||
{
|
||||
if (rlock_is_handle(lock))
|
||||
rlock_close(lock);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static uint64_t ns_to_ticks(uint64_t ns)
|
||||
{
|
||||
@@ -140,6 +284,7 @@ static uint64_t ns_to_ticks(uint64_t ns)
|
||||
return ns / 1000u * gk_tb_hz / 1000000u;
|
||||
}
|
||||
|
||||
#if GK_NEWLIB_HOOKS >= 3
|
||||
int __syscall_cond_signal(_COND_T *cond)
|
||||
{
|
||||
gk_cond_signal((gk_cond_t*)cond);
|
||||
@@ -221,6 +366,7 @@ int __syscall_tls_delete(uint32_t key)
|
||||
gk_tls_delete(key);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ---- thread-local slots ---- */
|
||||
|
||||
@@ -375,6 +521,7 @@ void __syscall_exit(int rc)
|
||||
gk_exit_to_loader();
|
||||
}
|
||||
|
||||
#if GK_NEWLIB_HOOKS >= 2
|
||||
void __syscall_abort(void)
|
||||
{
|
||||
gk_panic("abort()");
|
||||
@@ -386,6 +533,7 @@ void __syscall_assert_func(const char *file, int line, const char *func,
|
||||
gk_panic("assertion \"%s\" failed: %s:%d (%s)", expr, file, line,
|
||||
func ? func : "");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ---- stdout and stderr: lines to the debug channel ---- */
|
||||
|
||||
|
||||
Reference in new issue
Block a user