all repos — mgba @ 21cdbf6438df622019fd1429cb56195974cdd4bf

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