src/util/threading.h (view raw)
1/* Copyright (c) 2013-2014 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#ifndef THREADING_H
7#define THREADING_H
8
9#include "util/common.h"
10
11#ifdef USE_PTHREADS
12#include <pthread.h>
13#include <sys/time.h>
14
15#define THREAD_ENTRY void*
16typedef THREAD_ENTRY (*ThreadEntry)(void*);
17
18typedef pthread_t Thread;
19typedef pthread_mutex_t Mutex;
20typedef pthread_cond_t Condition;
21
22static inline int MutexInit(Mutex* mutex) {
23 return pthread_mutex_init(mutex, 0);
24}
25
26static inline int MutexDeinit(Mutex* mutex) {
27 return pthread_mutex_destroy(mutex);
28}
29
30static inline int MutexLock(Mutex* mutex) {
31 return pthread_mutex_lock(mutex);
32}
33
34static inline int MutexUnlock(Mutex* mutex) {
35 return pthread_mutex_unlock(mutex);
36}
37
38static inline int ConditionInit(Condition* cond) {
39 return pthread_cond_init(cond, 0);
40}
41
42static inline int ConditionDeinit(Condition* cond) {
43 return pthread_cond_destroy(cond);
44}
45
46static inline int ConditionWait(Condition* cond, Mutex* mutex) {
47 return pthread_cond_wait(cond, mutex);
48}
49
50static inline int ConditionWaitTimed(Condition* cond, Mutex* mutex, int32_t timeoutMs) {
51 struct timespec ts;
52 struct timeval tv;
53
54 gettimeofday(&tv, 0);
55 ts.tv_sec = tv.tv_sec;
56 ts.tv_nsec = (tv.tv_usec + timeoutMs * 1000L) * 1000L;
57 if (ts.tv_nsec >= 1000000000L) {
58 ts.tv_nsec -= 1000000000L;
59 ++ts.tv_sec;
60 }
61
62 return pthread_cond_timedwait(cond, mutex, &ts);
63}
64
65static inline int ConditionWake(Condition* cond) {
66 return pthread_cond_broadcast(cond);
67}
68
69static inline int ThreadCreate(Thread* thread, ThreadEntry entry, void* context) {
70 return pthread_create(thread, 0, entry, context);
71}
72
73static inline int ThreadJoin(Thread thread) {
74 return pthread_join(thread, 0);
75}
76
77#elif _WIN32
78#define _WIN32_WINNT 0x0600
79#include <windows.h>
80#define THREAD_ENTRY DWORD WINAPI
81typedef THREAD_ENTRY ThreadEntry(LPVOID);
82
83typedef HANDLE Thread;
84typedef CRITICAL_SECTION Mutex;
85typedef CONDITION_VARIABLE Condition;
86
87static inline int MutexInit(Mutex* mutex) {
88 InitializeCriticalSection(mutex);
89 return GetLastError();
90}
91
92static inline int MutexDeinit(Mutex* mutex) {
93 DeleteCriticalSection(mutex);
94 return GetLastError();
95}
96
97static inline int MutexLock(Mutex* mutex) {
98 EnterCriticalSection(mutex);
99 return GetLastError();
100}
101
102static inline int MutexUnlock(Mutex* mutex) {
103 LeaveCriticalSection(mutex);
104 return GetLastError();
105}
106
107static inline int ConditionInit(Condition* cond) {
108 InitializeConditionVariable(cond);
109 return GetLastError();
110}
111
112static inline int ConditionDeinit(Condition* cond) {
113 // This is a no-op on Windows
114 UNUSED(cond);
115 return 0;
116}
117
118static inline int ConditionWait(Condition* cond, Mutex* mutex) {
119 SleepConditionVariableCS(cond, mutex, INFINITE);
120 return GetLastError();
121}
122
123static inline int ConditionWaitTimed(Condition* cond, Mutex* mutex, int32_t timeoutMs) {
124 SleepConditionVariableCS(cond, mutex, timeoutMs);
125 return GetLastError();
126}
127
128static inline int ConditionWake(Condition* cond) {
129 WakeAllConditionVariable(cond);
130 return GetLastError();
131}
132
133static inline int ThreadCreate(Thread* thread, ThreadEntry entry, void* context) {
134 *thread = CreateThread(NULL, 0, entry, context, 0, 0);
135 return GetLastError();
136}
137
138static inline int ThreadJoin(Thread thread) {
139 DWORD error = WaitForSingleObject(thread, INFINITE);
140 if (error == WAIT_FAILED) {
141 return GetLastError();
142 }
143 return 0;
144}
145#elif defined(_3DS)
146// Threading primitives are implemented, but untested. Turn them off for now.
147#define DISABLE_THREADING
148
149#include <3ds.h>
150#include <malloc.h>
151
152#define THREAD_ENTRY void
153typedef ThreadFunc ThreadEntry;
154
155typedef struct {
156 Handle handle;
157 void* stack;
158} Thread;
159typedef Handle Mutex;
160typedef struct {
161 Mutex mutex;
162 Handle semaphore;
163 u32 waiting;
164} Condition;
165
166static inline int MutexInit(Mutex* mutex) {
167 return svcCreateMutex(mutex, false);
168}
169
170static inline int MutexDeinit(Mutex* mutex) {
171 return svcCloseHandle(*mutex);
172}
173
174static inline int MutexLock(Mutex* mutex) {
175 return svcWaitSynchronization(*mutex, U64_MAX);
176}
177
178static inline int MutexUnlock(Mutex* mutex) {
179 return svcReleaseMutex(*mutex);
180}
181
182static inline int ConditionInit(Condition* cond) {
183 Result res = svcCreateMutex(&cond->mutex, false);
184 if (res) {
185 return res;
186 }
187 res = svcCreateSemaphore(&cond->semaphore, 0, 1);
188 if (res) {
189 svcCloseHandle(cond->mutex);
190 }
191 cond->waiting = 0;
192 return res;
193}
194
195static inline int ConditionDeinit(Condition* cond) {
196 svcCloseHandle(cond->mutex);
197 return svcCloseHandle(cond->semaphore);
198}
199
200static inline int ConditionWait(Condition* cond, Mutex* mutex) {
201 MutexLock(&cond->mutex);
202 ++cond->waiting;
203 MutexUnlock(mutex);
204 MutexUnlock(&cond->mutex);
205 svcWaitSynchronization(cond->semaphore, U64_MAX);
206 MutexLock(mutex);
207 return 0;
208}
209
210static inline int ConditionWaitTimed(Condition* cond, Mutex* mutex, int32_t timeoutMs) {
211 MutexLock(&cond->mutex);
212 ++cond->waiting;
213 MutexUnlock(mutex);
214 MutexUnlock(&cond->mutex);
215 svcWaitSynchronization(cond->semaphore, timeoutMs * 10000000LL);
216 MutexLock(mutex);
217 return 0;
218}
219
220static inline int ConditionWake(Condition* cond) {
221 MutexLock(&cond->mutex);
222 if (cond->waiting) {
223 --cond->waiting;
224 s32 count = 0;
225 svcReleaseSemaphore(&count, cond->semaphore, 1);
226 }
227 MutexUnlock(&cond->mutex);
228 return 0;
229}
230
231static inline int ThreadCreate(Thread* thread, ThreadEntry entry, void* context) {
232 thread->stack = memalign(8, 0x800000);
233 return svcCreateThread(&thread->handle, entry, (u32) context, thread->stack, 0x1F, 0);
234}
235
236static inline int ThreadJoin(Thread thread) {
237 return svcWaitSynchronization(thread.handle, U64_MAX);
238}
239
240#else
241#define DISABLE_THREADING
242typedef void* Thread;
243typedef void* Mutex;
244typedef void* Condition;
245
246static inline int MutexInit(Mutex* mutex) {
247 UNUSED(mutex);
248 return 0;
249}
250
251static inline int MutexDeinit(Mutex* mutex) {
252 UNUSED(mutex);
253 return 0;
254}
255
256static inline int MutexLock(Mutex* mutex) {
257 UNUSED(mutex);
258 return 0;
259}
260
261static inline int MutexUnlock(Mutex* mutex) {
262 UNUSED(mutex);
263 return 0;
264}
265
266static inline int ConditionInit(Condition* cond) {
267 UNUSED(cond);
268 return 0;
269}
270
271static inline int ConditionDeinit(Condition* cond) {
272 UNUSED(cond);
273 return 0;
274}
275
276static inline int ConditionWait(Condition* cond, Mutex* mutex) {
277 UNUSED(cond);
278 UNUSED(mutex);
279 return 0;
280}
281
282static inline int ConditionWaitTimed(Condition* cond, Mutex* mutex, int32_t timeoutMs) {
283 UNUSED(cond);
284 UNUSED(mutex);
285 UNUSED(timeoutMs);
286 return 0;
287}
288
289static inline int ConditionWake(Condition* cond) {
290 UNUSED(cond);
291 return 0;
292}
293#endif
294
295#endif