Skip to content

Commit ceb2f45

Browse files
committed
Add support for C++ std::thread and derivatives
Implements dkp's gthread interface using LWP functions. With this, std::{thread,mutex,recursive_mutex,condition_variable} are now supported.
1 parent efb0217 commit ceb2f45

File tree

3 files changed

+200
-1
lines changed

3 files changed

+200
-1
lines changed

Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ INCLUDES += -I$(BASEDIR)/cube
100100
endif
101101

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

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

154155
#---------------------------------------------------------------------------------
155156
MODOBJ := freqtab.o mixer.o modplay.o semitonetab.o gcmodplay.o

libogc/ogc_gthread.cpp

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
#include <bits/gthr-default.h>
2+
#include <errno.h>
3+
#include <stdlib.h>
4+
#include <malloc.h>
5+
6+
#include "lwp.h"
7+
#include "mutex.h"
8+
#include "cond.h"
9+
10+
#define __OGC_GTHR_BASE_PRIO (64)
11+
12+
#define __OGC_ONCE_INIT (0)
13+
#define __OGC_ONCE_STARTED (1)
14+
#define __OGC_ONCE_DONE (2)
15+
16+
extern "C" {
17+
18+
typedef struct {
19+
lwpq_t queue;
20+
lwp_t thread;
21+
} gthr_thread_t;
22+
23+
int __gthr_impl_active(void)
24+
{
25+
return 1;
26+
}
27+
28+
int __gthr_impl_create(__gthread_t *__threadid, void *(*__func) (void*), void *__args)
29+
{
30+
gthr_thread_t *th = (gthr_thread_t*)malloc(sizeof(gthr_thread_t));
31+
32+
if (!th) {
33+
return ENOMEM;
34+
}
35+
36+
if (LWP_InitQueue(&th->queue) != LWP_SUCCESSFUL) {
37+
free(th);
38+
return EINVAL;
39+
}
40+
41+
if (LWP_CreateThread(&th->thread, __func, __args, NULL, 0, __OGC_GTHR_BASE_PRIO) != LWP_SUCCESSFUL) {
42+
LWP_CloseQueue(th->queue);
43+
free(th);
44+
return EINVAL;
45+
}
46+
47+
*__threadid = (__gthread_t)th;
48+
return 0;
49+
}
50+
51+
int __gthr_impl_join(__gthread_t __threadid, void **__value_ptr)
52+
{
53+
gthr_thread_t *th = (gthr_thread_t*)__threadid;
54+
55+
int res = LWP_JoinThread(th->thread, __value_ptr);
56+
if (res != LWP_SUCCESSFUL) {
57+
return -1;
58+
}
59+
60+
/* Clean up thread data */
61+
LWP_CloseQueue(th->queue);
62+
free(th);
63+
64+
return 0;
65+
}
66+
67+
int __gthr_impl_detach(__gthread_t __threadid)
68+
{
69+
/* Not supported */
70+
return -1;
71+
}
72+
73+
int __gthr_impl_equal(__gthread_t __t1, __gthread_t __t2)
74+
{
75+
return (gthr_thread_t*)__t1 == (gthr_thread_t*)__t2;
76+
}
77+
78+
__gthread_t __gthr_impl_self(void)
79+
{
80+
/*
81+
HACK: __gthread_self() is only used for std::thread::get_id(), so returning
82+
LWP_GetSelf() works as a unique id even though it's technically not a thread
83+
*/
84+
return (__gthread_t)LWP_GetSelf();
85+
}
86+
87+
int __gthr_impl_yield(void)
88+
{
89+
LWP_YieldThread();
90+
return 0;
91+
}
92+
93+
int __gthr_impl_once(__gthread_once_t *__once, void (*__func) (void))
94+
{
95+
uint32_t expected = __OGC_ONCE_INIT;
96+
if (__atomic_compare_exchange_n((uint32_t *)__once, &expected, __OGC_ONCE_STARTED, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
97+
__func();
98+
__atomic_store_n((uint32_t *)__once, __OGC_ONCE_DONE, __ATOMIC_RELEASE);
99+
} else if (expected != __OGC_ONCE_DONE) {
100+
do {
101+
__atomic_load((uint32_t *)__once, &expected, __ATOMIC_ACQUIRE);
102+
} while (expected != __OGC_ONCE_DONE);
103+
}
104+
105+
return 0;
106+
}
107+
108+
void __gthr_impl_mutex_init_function(__gthread_mutex_t *mutex)
109+
{
110+
LWP_MutexInit(((mutex_t*)mutex), false);
111+
}
112+
113+
int __gthr_impl_mutex_lock(__gthread_mutex_t *mutex)
114+
{
115+
return LWP_MutexLock(*((mutex_t*)mutex));
116+
}
117+
118+
int __gthr_impl_mutex_trylock(__gthread_mutex_t *mutex)
119+
{
120+
return LWP_MutexTryLock(*((mutex_t*)mutex));
121+
}
122+
123+
int __gthr_impl_mutex_unlock(__gthread_mutex_t *mutex)
124+
{
125+
return LWP_MutexUnlock(*((mutex_t*)mutex));
126+
}
127+
128+
int __gthr_impl_mutex_destroy(__gthread_mutex_t *mutex)
129+
{
130+
return LWP_MutexDestroy(*((mutex_t*)mutex));
131+
}
132+
133+
int __gthr_impl_recursive_mutex_init_function(__gthread_recursive_mutex_t *mutex)
134+
{
135+
return LWP_MutexInit(((mutex_t *)mutex), true);
136+
}
137+
138+
int __gthr_impl_recursive_mutex_lock(__gthread_recursive_mutex_t *mutex)
139+
{
140+
return LWP_MutexLock(*((mutex_t*)mutex));
141+
}
142+
143+
int __gthr_impl_recursive_mutex_trylock(__gthread_recursive_mutex_t *mutex)
144+
{
145+
return LWP_MutexTryLock(*((mutex_t*)mutex));
146+
}
147+
148+
int __gthr_impl_recursive_mutex_unlock(__gthread_recursive_mutex_t *mutex)
149+
{
150+
return LWP_MutexUnlock(*((mutex_t*)mutex));
151+
}
152+
153+
int __gthr_impl_recursive_mutex_destroy(__gthread_recursive_mutex_t *mutex)
154+
{
155+
return LWP_MutexDestroy(*((mutex_t*)mutex));
156+
}
157+
158+
void __gthr_impl_cond_init_function(__gthread_cond_t *__cond)
159+
{
160+
LWP_CondInit((cond_t*)__cond);
161+
}
162+
163+
int __gthr_impl_cond_broadcast(__gthread_cond_t *__cond)
164+
{
165+
return LWP_CondBroadcast(*(cond_t*)__cond);
166+
}
167+
168+
int __gthr_impl_cond_signal(__gthread_cond_t *__cond)
169+
{
170+
return LWP_CondSignal(*(cond_t*)__cond);
171+
}
172+
173+
int __gthr_impl_cond_wait(__gthread_cond_t *__cond, __gthread_mutex_t *__mutex)
174+
{
175+
return LWP_CondWait(*(cond_t*)__cond, *(mutex_t*)__mutex);
176+
}
177+
178+
int __gthr_impl_cond_timedwait(__gthread_cond_t *__cond, __gthread_mutex_t *__mutex, const __gthread_time_t *__abs_timeout)
179+
{
180+
return LWP_CondTimedWait(*(cond_t*)__cond, *(mutex_t*)__mutex, __abs_timeout);
181+
}
182+
183+
int __gthr_impl_cond_wait_recursive(__gthread_cond_t *__cond, __gthread_recursive_mutex_t *__mutex)
184+
{
185+
return LWP_CondWait(*(cond_t*)__cond, *(mutex_t*)__mutex);
186+
}
187+
188+
int __gthr_impl_cond_destroy(__gthread_cond_t* __cond)
189+
{
190+
return LWP_CondDestroy(*(cond_t*)__cond);
191+
}
192+
193+
/* Dummy function required so that the linker doesn't strip this module */
194+
void __ogc_gthread_init() {}
195+
}

libogc/system.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,8 @@ extern int __libogc_nanosleep(const struct timespec *tb, struct timespec *rem);
215215
extern u64 gettime(void);
216216
extern void settime(u64);
217217

218+
extern void __ogc_gthread_init();
219+
218220
extern u8 __gxregs[];
219221
extern u8 __text_start[];
220222
extern u8 __isIPL[];
@@ -1097,6 +1099,7 @@ void SYS_Init(void)
10971099
IRQ_Request(IRQ_PI_RSW,__RSWHandler,NULL);
10981100
__MaskIrq(IRQMASK(IRQ_PI_RSW));
10991101
#endif
1102+
__ogc_gthread_init();
11001103
__lwp_thread_startmultitasking();
11011104
_CPU_ISR_Restore(level);
11021105
}

0 commit comments

Comments
 (0)