all repos — mgba @ 51c3fca3bf79d1c4d200fcb1fd48d24dc03e5d7a

mGBA Game Boy Advance Emulator

include/mgba-util/platform/psp2/threading.h (view raw)

  1/* Copyright (c) 2013-2015 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 SCE_THREADING_H
  7#define SCE_THREADING_H
  8
  9#include <psp2/kernel/threadmgr.h>
 10
 11typedef SceUID Thread;
 12typedef SceUID Mutex;
 13typedef struct {
 14	Mutex mutex;
 15	SceUID semaphore;
 16	int waiting;
 17} Condition;
 18#define THREAD_ENTRY int
 19typedef THREAD_ENTRY (*ThreadEntry)(void*);
 20typedef int ThreadLocal;
 21
 22static inline int MutexInit(Mutex* mutex) {
 23	Mutex id = sceKernelCreateMutex("mutex", 0, 0, 0);
 24	if (id < 0) {
 25		return id;
 26	}
 27	*mutex = id;
 28	return 0;
 29}
 30
 31static inline int MutexDeinit(Mutex* mutex) {
 32	return sceKernelDeleteMutex(*mutex);
 33}
 34
 35static inline int MutexLock(Mutex* mutex) {
 36	return sceKernelLockMutex(*mutex, 1, 0);
 37}
 38
 39static inline int MutexTryLock(Mutex* mutex) {
 40	return sceKernelTryLockMutex(*mutex, 1);
 41}
 42
 43static inline int MutexUnlock(Mutex* mutex) {
 44	return sceKernelUnlockMutex(*mutex, 1);
 45}
 46
 47static inline int ConditionInit(Condition* cond) {
 48	int res = MutexInit(&cond->mutex);
 49	if (res < 0) {
 50		return res;
 51	}
 52	cond->semaphore = sceKernelCreateSema("SceCondSema", 0, 0, 1, 0);
 53	if (cond->semaphore < 0) {
 54		MutexDeinit(&cond->mutex);
 55		res = cond->semaphore;
 56	}
 57	cond->waiting = 0;
 58	return res;
 59}
 60
 61static inline int ConditionDeinit(Condition* cond) {
 62	MutexDeinit(&cond->mutex);
 63	return sceKernelDeleteSema(cond->semaphore);
 64}
 65
 66static inline int ConditionWait(Condition* cond, Mutex* mutex) {
 67	int ret = MutexLock(&cond->mutex);
 68	if (ret < 0) {
 69		return ret;
 70	}
 71	++cond->waiting;
 72	MutexUnlock(mutex);
 73	MutexUnlock(&cond->mutex);
 74	ret = sceKernelWaitSema(cond->semaphore, 1, 0);
 75	if (ret < 0) {
 76		printf("Premature wakeup: %08X", ret);
 77	}
 78	MutexLock(mutex);
 79	return ret;
 80}
 81
 82static inline int ConditionWaitTimed(Condition* cond, Mutex* mutex, int32_t timeoutMs) {
 83	int ret = MutexLock(&cond->mutex);
 84	if (ret < 0) {
 85		return ret;
 86	}
 87	++cond->waiting;
 88	MutexUnlock(mutex);
 89	MutexUnlock(&cond->mutex);
 90	SceUInt timeout = 0;
 91	if (timeoutMs > 0) {
 92		timeout = timeoutMs;
 93	}
 94	ret = sceKernelWaitSema(cond->semaphore, 1, &timeout);
 95	if (ret < 0) {
 96		printf("Premature wakeup: %08X", ret);
 97	}
 98	MutexLock(mutex);
 99	return ret;
100}
101
102static inline int ConditionWake(Condition* cond) {
103	MutexLock(&cond->mutex);
104	if (cond->waiting) {
105		--cond->waiting;
106		sceKernelSignalSema(cond->semaphore, 1);
107	}
108	MutexUnlock(&cond->mutex);
109	return 0;
110}
111
112struct SceThreadEntryArgs {
113	void* context;
114	ThreadEntry entry;
115};
116
117static inline int _sceThreadEntry(SceSize args, void* argp) {
118	UNUSED(args);
119	struct SceThreadEntryArgs* arg = argp;
120	return arg->entry(arg->context);
121}
122
123static inline int ThreadCreate(Thread* thread, ThreadEntry entry, void* context) {
124	Thread id = sceKernelCreateThread("SceThread", _sceThreadEntry, 0x10000100, 0x10000, 0, 0, 0);
125	if (id < 0) {
126		*thread = 0;
127		return id;
128	}
129	*thread = id;
130	struct SceThreadEntryArgs args = { context, entry };
131	sceKernelStartThread(id, sizeof(args), &args);
132	return 0;
133}
134
135static inline int ThreadJoin(Thread* thread) {
136	int res = sceKernelWaitThreadEnd(*thread, 0, 0);
137	if (res < 0) {
138		return res;
139	}
140	return sceKernelDeleteThread(*thread);
141}
142
143static inline int ThreadSetName(const char* name) {
144	UNUSED(name);
145	return -1;
146}
147
148static inline void ThreadLocalInitKey(ThreadLocal* key) {
149	static int base = 0x90;
150	*key = __atomic_fetch_add(&base, 1, __ATOMIC_SEQ_CST);
151}
152
153static inline void ThreadLocalSetKey(ThreadLocal key, void* value) {
154	void** tls = sceKernelGetTLSAddr(key);
155	*tls = value;
156}
157
158static inline void* ThreadLocalGetValue(ThreadLocal key) {
159	void** tls = sceKernelGetTLSAddr(key);
160	return *tls;
161}
162#endif