libgui 2.01
libgui is a GUI library for the GameCube, Wii, and Wii U
 
Loading...
Searching...
No Matches
OgcThreadDriver.cpp
1/****************************************************************************
2 * Platform Abstraction Layer (OGC driver)
3 * Daryl Borth 2026
4 * OgcThreadDriver.cpp
5 *
6 * Wraps libogc LWP threads/mutexes. lwp_t/mutex_t are opaque integer
7 * handles on this platform, so each is boxed in a small heap struct to
8 * satisfy the void* handle contract used by ThreadDriver.
9 ***************************************************************************/
10#include <ogcsys.h>
11#include <unistd.h>
12#include <ogc/cond.h>
13
14#include "OgcThreadDriver.h"
15
16namespace
17{
18 struct OgcThreadHandle
19 {
20 lwp_t thread = LWP_THREAD_NULL;
21 ThreadEntry entry = nullptr;
22 void * arg = nullptr;
23 };
24
25 void * OgcThreadTrampoline(void * arg)
26 {
27 OgcThreadHandle * handle = static_cast<OgcThreadHandle *>(arg);
28 return handle->entry(handle->arg);
29 }
30
31 int MapOgcPriority(ThreadPriority priority)
32 {
33 switch (priority)
34 {
35 case ThreadPriority::Idle: return LWP_PRIO_IDLE;
36 case ThreadPriority::Low: return LWP_PRIO_LOWEST;
37 case ThreadPriority::Normal: return LWP_PRIO_NORMAL;
38 case ThreadPriority::High: return LWP_PRIO_HIGHEST;
39 case ThreadPriority::TimeCritical: return LWP_PRIO_TIME_CRITICAL;
40 default: return LWP_PRIO_NORMAL;
41 }
42 }
43}
44
46{
47}
48
52
53bool OgcThreadDriver::createThread(ThreadEntry entry, void * arg, uint32_t stackSize, ThreadPriority priority, void ** outHandle)
54{
55 OgcThreadHandle * handle = new OgcThreadHandle();
56 handle->entry = entry;
57 handle->arg = arg;
58
59 // Publish the handle to the caller's storage BEFORE spawning the LWP
60 // thread. entry() may reference *outHandle itself (e.g. Thread::suspend()
61 // called from within its own thread) as its very first action, and LWP
62 // can begin running the new thread before LWP_CreateThread returns here -
63 // so outHandle must already be valid by that point, not assigned by the
64 // caller afterwards.
65 *outHandle = handle;
66
67 int nativePriority = MapOgcPriority(priority);
68 int32_t res = LWP_CreateThread(&handle->thread, OgcThreadTrampoline, handle, nullptr, stackSize, nativePriority);
69 if(res != 0)
70 {
71 *outHandle = nullptr;
72 delete handle;
73 return false;
74 }
75
76 return true;
77}
78
79void OgcThreadDriver::joinThread(void * thread)
80{
81 if(!thread)
82 return;
83
84 OgcThreadHandle * handle = static_cast<OgcThreadHandle *>(thread);
85 LWP_JoinThread(handle->thread, nullptr);
86 delete handle;
87}
88
90{
91 if(!thread)
92 return;
93
94 // libogc/LWP has no true thread-cancel primitive (there is no
95 // LWP_ThreadCancel - even libogc's own pthread shim leaves
96 // pthread_cancel unimplemented). Best effort: permanently suspend the
97 // thread so it stops running. This does NOT reclaim its stack/context,
98 // so callers should prefer signalling the thread to exit cooperatively
99 // and calling joinThread() instead, which does clean up properly.
100 OgcThreadHandle * handle = static_cast<OgcThreadHandle *>(thread);
101 LWP_SuspendThread(handle->thread);
102 delete handle;
103}
104
106{
107 if(!thread)
108 return;
109
110 LWP_SuspendThread(static_cast<OgcThreadHandle *>(thread)->thread);
111}
112
114{
115 if(!thread)
116 return;
117
118 LWP_ResumeThread(static_cast<OgcThreadHandle *>(thread)->thread);
119}
120
122{
123 if(!thread)
124 return false;
125
126 return LWP_ThreadIsSuspended(static_cast<OgcThreadHandle *>(thread)->thread) != 0;
127}
128
130{
131 mutex_t * mutex = new mutex_t;
132 if(LWP_MutexInit(mutex, false) != 0)
133 {
134 delete mutex;
135 return nullptr;
136 }
137
138 return mutex;
139}
140
142{
143 if(!mutex)
144 return;
145
146 mutex_t * m = static_cast<mutex_t *>(mutex);
147 LWP_MutexDestroy(*m);
148 delete m;
149}
150
152{
153 if(!mutex)
154 return;
155
156 LWP_MutexLock(*static_cast<mutex_t *>(mutex));
157}
158
160{
161 if(!mutex)
162 return;
163
164 LWP_MutexUnlock(*static_cast<mutex_t *>(mutex));
165}
166
168{
169 cond_t * cond = new cond_t;
170 if(LWP_CondInit(cond) != 0)
171 {
172 delete cond;
173 return nullptr;
174 }
175
176 return cond;
177}
178
180{
181 if(!cond)
182 return;
183
184 cond_t * c = static_cast<cond_t *>(cond);
185 LWP_CondDestroy(*c);
186 delete c;
187}
188
189void OgcThreadDriver::waitCond(void * cond, void * mutex)
190{
191 if(!cond || !mutex)
192 return;
193
194 LWP_CondWait(*static_cast<cond_t *>(cond), *static_cast<mutex_t *>(mutex));
195}
196
198{
199 if(!cond)
200 return;
201
202 // Broadcast rather than LWP_CondSignal
203 LWP_CondBroadcast(*static_cast<cond_t *>(cond));
204}
205
207{
208 usleep(ms * 1000);
209}
210
212{
213 // lwp_t is an opaque libogc handle that already uniquely identifies
214 // the calling thread (including the app's original/main thread,
215 // which was never created via createThread() above) - just widen it.
216 return (uintptr_t)LWP_GetSelf();
217}
void shutdown() override
Shuts the threading backend down. Every thread must already have been joined.
void * createCond() override
Creates a condition variable.
bool isThreadSuspended(void *thread) override
void unlockMutex(void *mutex) override
Releases a mutex held by the calling thread.
void signalCond(void *cond) override
Wakes every thread currently blocked in waitCond() on this condition variable.
bool createThread(ThreadEntry entry, void *arg, uint32_t stackSize, ThreadPriority priority, void **outHandle) override
Creates and starts a thread running entry(arg).
void * createMutex() override
Creates an unlocked mutex.
void joinThread(void *thread) override
Blocks until the thread exits, then releases the handle.
void suspendThread(void *thread) override
Suspends a running thread until resumeThread() is called.
void sleepMilliseconds(uint32_t ms) override
Sleeps the calling thread for at least the given duration.
uintptr_t getCurrentThreadId() override
Returns an opaque, comparable identifier for the calling thread.
void resumeThread(void *thread) override
Resumes a thread suspended with suspendThread().
void lockMutex(void *mutex) override
Blocks until the mutex is acquired.
void init() override
Initializes the threading backend.
void waitCond(void *cond, void *mutex) override
Atomically unlocks mutex and blocks the calling thread until signalCond() is called,...
void cancelThread(void *thread) override
Requests the thread stop running and releases the handle without blocking on it.
void destroyMutex(void *mutex) override
Destroys a mutex created by createMutex(). It must not be locked.
void destroyCond(void *cond) override
Destroys a condition variable created by createCond(). No thread may be waiting on it.
ThreadPriority
Abstract thread priority, mapped to each platform's native priority scheme.
Definition Thread.h:18