all repos — mgba @ 9dc49df0bca23925cfcc8193a1770463fd9916cf

mGBA Game Boy Advance Emulator

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