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
14#define THREAD_ENTRY void*
15typedef THREAD_ENTRY (*ThreadEntry)(void*);
16
17typedef pthread_t Thread;
18typedef pthread_mutex_t Mutex;
19typedef pthread_cond_t Condition;
20
21static inline int MutexInit(Mutex* mutex) {
22 return pthread_mutex_init(mutex, 0);
23}
24
25static inline int MutexDeinit(Mutex* mutex) {
26 return pthread_mutex_destroy(mutex);
27}
28
29static inline int MutexLock(Mutex* mutex) {
30 return pthread_mutex_lock(mutex);
31}
32
33static inline int MutexUnlock(Mutex* mutex) {
34 return pthread_mutex_unlock(mutex);
35}
36
37static inline int ConditionInit(Condition* cond) {
38 return pthread_cond_init(cond, 0);
39}
40
41static inline int ConditionDeinit(Condition* cond) {
42 return pthread_cond_destroy(cond);
43}
44
45static inline int ConditionWait(Condition* cond, Mutex* mutex) {
46 return pthread_cond_wait(cond, mutex);
47}
48
49static inline int ConditionWake(Condition* cond) {
50 return pthread_cond_broadcast(cond);
51}
52
53static inline int ThreadCreate(Thread* thread, ThreadEntry entry, void* context) {
54 return pthread_create(thread, 0, entry, context);
55}
56
57static inline int ThreadJoin(Thread thread) {
58 return pthread_join(thread, 0);
59}
60
61#elif _WIN32
62#define _WIN32_WINNT 0x0600
63#include <windows.h>
64#define THREAD_ENTRY DWORD WINAPI
65typedef THREAD_ENTRY ThreadEntry(LPVOID);
66
67typedef HANDLE Thread;
68typedef CRITICAL_SECTION Mutex;
69typedef CONDITION_VARIABLE Condition;
70
71static inline int MutexInit(Mutex* mutex) {
72 InitializeCriticalSection(mutex);
73 return GetLastError();
74}
75
76static inline int MutexDeinit(Mutex* mutex) {
77 DeleteCriticalSection(mutex);
78 return GetLastError();
79}
80
81static inline int MutexLock(Mutex* mutex) {
82 EnterCriticalSection(mutex);
83 return GetLastError();
84}
85
86static inline int MutexUnlock(Mutex* mutex) {
87 LeaveCriticalSection(mutex);
88 return GetLastError();
89}
90
91static inline int ConditionInit(Condition* cond) {
92 InitializeConditionVariable(cond);
93 return GetLastError();
94}
95
96static inline int ConditionDeinit(Condition* cond) {
97 // This is a no-op on Windows
98 UNUSED(cond);
99 return 0;
100}
101
102static inline int ConditionWait(Condition* cond, Mutex* mutex) {
103 SleepConditionVariableCS(cond, mutex, INFINITE);
104 return GetLastError();
105}
106
107static inline int ConditionWake(Condition* cond) {
108 WakeAllConditionVariable(cond);
109 return GetLastError();
110}
111
112static inline int ThreadCreate(Thread* thread, ThreadEntry entry, void* context) {
113 *thread = CreateThread(NULL, 0, entry, context, 0, 0);
114 return GetLastError();
115}
116
117static inline int ThreadJoin(Thread thread) {
118 DWORD error = WaitForSingleObject(thread, INFINITE);
119 if (error == WAIT_FAILED) {
120 return GetLastError();
121 }
122 return 0;
123}
124#elif defined(_3DS)
125// Threading primitives are implemented, but untested. Turn them off for now.
126#define DISABLE_THREADING
127
128#include <3ds.h>
129#include <malloc.h>
130
131#define THREAD_ENTRY void
132typedef ThreadFunc ThreadEntry;
133
134typedef struct {
135 Handle handle;
136 void* stack;
137} Thread;
138typedef Handle Mutex;
139typedef struct {
140 Mutex mutex;
141 Handle semaphore;
142 u32 waiting;
143} Condition;
144
145static inline int MutexInit(Mutex* mutex) {
146 return svcCreateMutex(mutex, false);
147}
148
149static inline int MutexDeinit(Mutex* mutex) {
150 return svcCloseHandle(*mutex);
151}
152
153static inline int MutexLock(Mutex* mutex) {
154 return svcWaitSynchronization(*mutex, U64_MAX);
155}
156
157static inline int MutexUnlock(Mutex* mutex) {
158 return svcReleaseMutex(*mutex);
159}
160
161static inline int ConditionInit(Condition* cond) {
162 Result res = svcCreateMutex(&cond->mutex, false);
163 if (res) {
164 return res;
165 }
166 res = svcCreateSemaphore(&cond->semaphore, 0, 1);
167 if (res) {
168 svcCloseHandle(cond->mutex);
169 }
170 cond->waiting = 0;
171 return res;
172}
173
174static inline int ConditionDeinit(Condition* cond) {
175 svcCloseHandle(cond->mutex);
176 return svcCloseHandle(cond->semaphore);
177}
178
179static inline int ConditionWait(Condition* cond, Mutex* mutex) {
180 MutexLock(&cond->mutex);
181 ++cond->waiting;
182 MutexUnlock(mutex);
183 MutexUnlock(&cond->mutex);
184 svcWaitSynchronization(cond->semaphore, U64_MAX);
185 MutexLock(mutex);
186 return 0;
187}
188
189static inline int ConditionWake(Condition* cond) {
190 MutexLock(&cond->mutex);
191 if (cond->waiting) {
192 --cond->waiting;
193 s32 count = 0;
194 svcReleaseSemaphore(&count, cond->semaphore, 1);
195 }
196 MutexUnlock(&cond->mutex);
197 return 0;
198}
199
200static inline int ThreadCreate(Thread* thread, ThreadEntry entry, void* context) {
201 thread->stack = memalign(8, 0x800000);
202 return svcCreateThread(&thread->handle, entry, (u32) context, thread->stack, 0x1F, 0);
203}
204
205static inline int ThreadJoin(Thread thread) {
206 return svcWaitSynchronization(thread.handle, U64_MAX);
207}
208
209#else
210#define DISABLE_THREADING
211typedef void* Thread;
212typedef void* Mutex;
213typedef void* Condition;
214
215static inline int MutexInit(Mutex* mutex) {
216 UNUSED(mutex);
217 return 0;
218}
219
220static inline int MutexDeinit(Mutex* mutex) {
221 UNUSED(mutex);
222 return 0;
223}
224
225static inline int MutexLock(Mutex* mutex) {
226 UNUSED(mutex);
227 return 0;
228}
229
230static inline int MutexUnlock(Mutex* mutex) {
231 UNUSED(mutex);
232 return 0;
233}
234
235static inline int ConditionInit(Condition* cond) {
236 UNUSED(cond);
237 return 0;
238}
239
240static inline int ConditionDeinit(Condition* cond) {
241 UNUSED(cond);
242 return 0;
243}
244
245static inline int ConditionWait(Condition* cond, Mutex* mutex) {
246 UNUSED(cond);
247 UNUSED(mutex);
248 return 0;
249}
250
251static inline int ConditionWake(Condition* cond) {
252 UNUSED(cond);
253 return 0;
254}
255#endif
256
257#endif