Skip to content

Add support for C++ std::thread and derivatives #217

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ INCLUDES += -I$(BASEDIR)/cube
endif

CFLAGS := $(FALSE_POSITIVES) -g -O2 -fno-strict-aliasing -Wall $(MACHDEP) $(INCLUDES)
CXXFLAGS := $(CFLAGS) -std=gnu++17 -fno-exceptions -fno-rtti
ASFLAGS := $(MACHDEP) -mregnames -D_LANGUAGE_ASSEMBLY $(INCLUDES)

#---------------------------------------------------------------------------------
Expand Down Expand Up @@ -149,7 +150,7 @@ OGCOBJ := \
console_font_8x16.o timesupp.o lock_supp.o usbgecko.o usbmouse.o \
sbrk.o malloc_lock.o kprintf.o stm.o aes.o sha.o ios.o es.o isfs.o usb.o network_common.o \
sdgecko_io.o sdgecko_buf.o gcsd.o argv.o network_wii.o wiisd.o conf.o usbstorage.o \
texconv.o wiilaunch.o sys_report.o
texconv.o wiilaunch.o sys_report.o ogc_gthread.o

#---------------------------------------------------------------------------------
MODOBJ := freqtab.o mixer.o modplay.o semitonetab.o gcmodplay.o
Expand Down
195 changes: 195 additions & 0 deletions libogc/ogc_gthread.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
#include <bits/gthr-default.h>
#include <errno.h>
#include <stdlib.h>
#include <malloc.h>

#include "lwp.h"
#include "mutex.h"
#include "cond.h"

#define __OGC_GTHR_BASE_PRIO (64)

#define __OGC_ONCE_INIT (0)
#define __OGC_ONCE_STARTED (1)
#define __OGC_ONCE_DONE (2)

extern "C" {

typedef struct {
lwpq_t queue;
lwp_t thread;
} gthr_thread_t;

int __gthr_impl_active(void)
{
return 1;
}

int __gthr_impl_create(__gthread_t *__threadid, void *(*__func) (void*), void *__args)
{
gthr_thread_t *th = (gthr_thread_t*)malloc(sizeof(gthr_thread_t));

if (!th) {
return ENOMEM;
}

if (LWP_InitQueue(&th->queue) != LWP_SUCCESSFUL) {
free(th);
return EINVAL;
}

if (LWP_CreateThread(&th->thread, __func, __args, NULL, 0, __OGC_GTHR_BASE_PRIO) != LWP_SUCCESSFUL) {
LWP_CloseQueue(th->queue);
free(th);
return EINVAL;
}

*__threadid = (__gthread_t)th;
return 0;
}

int __gthr_impl_join(__gthread_t __threadid, void **__value_ptr)
{
gthr_thread_t *th = (gthr_thread_t*)__threadid;

int res = LWP_JoinThread(th->thread, __value_ptr);
if (res != LWP_SUCCESSFUL) {
return -1;
}

/* Clean up thread data */
LWP_CloseQueue(th->queue);
free(th);

return 0;
}

int __gthr_impl_detach(__gthread_t __threadid)
{
/* Not supported */
return -1;
}

int __gthr_impl_equal(__gthread_t __t1, __gthread_t __t2)
{
return (gthr_thread_t*)__t1 == (gthr_thread_t*)__t2;
}

__gthread_t __gthr_impl_self(void)
{
/*
HACK: __gthread_self() is only used for std::thread::get_id(), so returning
LWP_GetSelf() works as a unique id even though it's technically not a thread
*/
return (__gthread_t)LWP_GetSelf();
}

int __gthr_impl_yield(void)
{
LWP_YieldThread();
return 0;
}

int __gthr_impl_once(__gthread_once_t *__once, void (*__func) (void))
{
uint32_t expected = __OGC_ONCE_INIT;
if (__atomic_compare_exchange_n((uint32_t *)__once, &expected, __OGC_ONCE_STARTED, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
__func();
__atomic_store_n((uint32_t *)__once, __OGC_ONCE_DONE, __ATOMIC_RELEASE);
} else if (expected != __OGC_ONCE_DONE) {
do {
__atomic_load((uint32_t *)__once, &expected, __ATOMIC_ACQUIRE);
} while (expected != __OGC_ONCE_DONE);
}

return 0;
}

void __gthr_impl_mutex_init_function(__gthread_mutex_t *mutex)
{
LWP_MutexInit(((mutex_t*)mutex), false);
}

int __gthr_impl_mutex_lock(__gthread_mutex_t *mutex)
{
return LWP_MutexLock(*((mutex_t*)mutex));
}

int __gthr_impl_mutex_trylock(__gthread_mutex_t *mutex)
{
return LWP_MutexTryLock(*((mutex_t*)mutex));
}

int __gthr_impl_mutex_unlock(__gthread_mutex_t *mutex)
{
return LWP_MutexUnlock(*((mutex_t*)mutex));
}

int __gthr_impl_mutex_destroy(__gthread_mutex_t *mutex)
{
return LWP_MutexDestroy(*((mutex_t*)mutex));
}

int __gthr_impl_recursive_mutex_init_function(__gthread_recursive_mutex_t *mutex)
{
return LWP_MutexInit(((mutex_t *)mutex), true);
}

int __gthr_impl_recursive_mutex_lock(__gthread_recursive_mutex_t *mutex)
{
return LWP_MutexLock(*((mutex_t*)mutex));
}

int __gthr_impl_recursive_mutex_trylock(__gthread_recursive_mutex_t *mutex)
{
return LWP_MutexTryLock(*((mutex_t*)mutex));
}

int __gthr_impl_recursive_mutex_unlock(__gthread_recursive_mutex_t *mutex)
{
return LWP_MutexUnlock(*((mutex_t*)mutex));
}

int __gthr_impl_recursive_mutex_destroy(__gthread_recursive_mutex_t *mutex)
{
return LWP_MutexDestroy(*((mutex_t*)mutex));
}

void __gthr_impl_cond_init_function(__gthread_cond_t *__cond)
{
LWP_CondInit((cond_t*)__cond);
}

int __gthr_impl_cond_broadcast(__gthread_cond_t *__cond)
{
return LWP_CondBroadcast(*(cond_t*)__cond);
}

int __gthr_impl_cond_signal(__gthread_cond_t *__cond)
{
return LWP_CondSignal(*(cond_t*)__cond);
}

int __gthr_impl_cond_wait(__gthread_cond_t *__cond, __gthread_mutex_t *__mutex)
{
return LWP_CondWait(*(cond_t*)__cond, *(mutex_t*)__mutex);
}

int __gthr_impl_cond_timedwait(__gthread_cond_t *__cond, __gthread_mutex_t *__mutex, const __gthread_time_t *__abs_timeout)
{
return LWP_CondTimedWait(*(cond_t*)__cond, *(mutex_t*)__mutex, __abs_timeout);
}

int __gthr_impl_cond_wait_recursive(__gthread_cond_t *__cond, __gthread_recursive_mutex_t *__mutex)
{
return LWP_CondWait(*(cond_t*)__cond, *(mutex_t*)__mutex);
}

int __gthr_impl_cond_destroy(__gthread_cond_t* __cond)
{
return LWP_CondDestroy(*(cond_t*)__cond);
}

/* Dummy function required so that the linker doesn't strip this module */
void __ogc_gthread_init() {}
}
3 changes: 3 additions & 0 deletions libogc/system.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ extern int __libogc_nanosleep(const struct timespec *tb, struct timespec *rem);
extern u64 gettime(void);
extern void settime(u64);

extern void __ogc_gthread_init();

extern u8 __gxregs[];
extern u8 __text_start[];
extern u8 __isIPL[];
Expand Down Expand Up @@ -1097,6 +1099,7 @@ void SYS_Init(void)
IRQ_Request(IRQ_PI_RSW,__RSWHandler,NULL);
__MaskIrq(IRQMASK(IRQ_PI_RSW));
#endif
__ogc_gthread_init();
__lwp_thread_startmultitasking();
_CPU_ISR_Restore(level);
}
Expand Down