Skip to content

Commit 7d28284

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 7d28284

File tree

3 files changed

+202
-1
lines changed

3 files changed

+202
-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: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
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,
97+
__OGC_ONCE_STARTED, false, __ATOMIC_ACQUIRE,
98+
__ATOMIC_RELAXED)) {
99+
__func();
100+
__atomic_store_n((uint32_t *)__once, __OGC_ONCE_DONE, __ATOMIC_RELEASE);
101+
} else if (expected != __OGC_ONCE_DONE) {
102+
do {
103+
__atomic_load((uint32_t *)__once, &expected, __ATOMIC_ACQUIRE);
104+
} while (expected != __OGC_ONCE_DONE);
105+
}
106+
107+
return 0;
108+
}
109+
110+
void __gthr_impl_mutex_init_function(__gthread_mutex_t *mutex)
111+
{
112+
LWP_MutexInit(((mutex_t*)mutex), false);
113+
}
114+
115+
int __gthr_impl_mutex_lock(__gthread_mutex_t *mutex)
116+
{
117+
return LWP_MutexLock(*((mutex_t*)mutex));
118+
}
119+
120+
int __gthr_impl_mutex_trylock(__gthread_mutex_t *mutex)
121+
{
122+
return LWP_MutexTryLock(*((mutex_t*)mutex));
123+
}
124+
125+
int __gthr_impl_mutex_unlock(__gthread_mutex_t *mutex)
126+
{
127+
return LWP_MutexUnlock(*((mutex_t*)mutex));
128+
}
129+
130+
int __gthr_impl_mutex_destroy(__gthread_mutex_t *mutex)
131+
{
132+
return LWP_MutexDestroy(*((mutex_t*)mutex));
133+
}
134+
135+
int __gthr_impl_recursive_mutex_init_function(__gthread_recursive_mutex_t *mutex)
136+
{
137+
return LWP_MutexInit(((mutex_t *)mutex), true);
138+
}
139+
140+
int __gthr_impl_recursive_mutex_lock(__gthread_recursive_mutex_t *mutex)
141+
{
142+
return LWP_MutexLock(*((mutex_t*)mutex));
143+
}
144+
145+
int __gthr_impl_recursive_mutex_trylock(__gthread_recursive_mutex_t *mutex)
146+
{
147+
return LWP_MutexTryLock(*((mutex_t*)mutex));
148+
}
149+
150+
int __gthr_impl_recursive_mutex_unlock(__gthread_recursive_mutex_t *mutex)
151+
{
152+
return LWP_MutexUnlock(*((mutex_t*)mutex));
153+
}
154+
155+
int __gthr_impl_recursive_mutex_destroy(__gthread_recursive_mutex_t *mutex)
156+
{
157+
return LWP_MutexDestroy(*((mutex_t*)mutex));
158+
}
159+
160+
void __gthr_impl_cond_init_function(__gthread_cond_t *__cond)
161+
{
162+
LWP_CondInit((cond_t*)__cond);
163+
}
164+
165+
int __gthr_impl_cond_broadcast(__gthread_cond_t *__cond)
166+
{
167+
return LWP_CondBroadcast(*(cond_t*)__cond);
168+
}
169+
170+
int __gthr_impl_cond_signal(__gthread_cond_t *__cond)
171+
{
172+
return LWP_CondSignal(*(cond_t*)__cond);
173+
}
174+
175+
int __gthr_impl_cond_wait(__gthread_cond_t *__cond, __gthread_mutex_t *__mutex)
176+
{
177+
return LWP_CondWait(*(cond_t*)__cond, *(mutex_t*)__mutex);
178+
}
179+
180+
int __gthr_impl_cond_timedwait(__gthread_cond_t *__cond, __gthread_mutex_t *__mutex, const __gthread_time_t *__abs_timeout)
181+
{
182+
return LWP_CondTimedWait(*(cond_t*)__cond, *(mutex_t*)__mutex, __abs_timeout);
183+
}
184+
185+
int __gthr_impl_cond_wait_recursive(__gthread_cond_t *__cond, __gthread_recursive_mutex_t *__mutex)
186+
{
187+
return LWP_CondWait(*(cond_t*)__cond, *(mutex_t*)__mutex);
188+
}
189+
190+
int __gthr_impl_cond_destroy(__gthread_cond_t* __cond)
191+
{
192+
return LWP_CondDestroy(*(cond_t*)__cond);
193+
}
194+
195+
/* Dummy function required so that the linker doesn't strip this module */
196+
void __ogc_gthread_init() {}
197+
}

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)