all repos — mgba @ aaaafb90a57df651c9bf3ce04afc3057755a4b98

mGBA Game Boy Advance Emulator

src/gba/gba-thread.c (view raw)

  1#include "gba-thread.h"
  2
  3#include "arm.h"
  4#include "debugger.h"
  5#include "gba.h"
  6
  7#include <stdlib.h>
  8#include <signal.h>
  9
 10static pthread_key_t contextKey;
 11
 12static void createTLS(void) {
 13	pthread_key_create(&contextKey, 0);
 14}
 15
 16static void* _GBAThreadRun(void* context) {
 17	static pthread_once_t once = PTHREAD_ONCE_INIT;
 18	pthread_once(&once, createTLS);
 19
 20	struct ARMDebugger debugger;
 21	struct GBA gba;
 22	struct GBAThread* threadContext = context;
 23	char* savedata = 0;
 24
 25	sigset_t signals;
 26	sigfillset(&signals);
 27	pthread_sigmask(SIG_UNBLOCK, &signals, 0);
 28
 29	GBAInit(&gba);
 30	threadContext->gba = &gba;
 31	pthread_setspecific(contextKey, threadContext);
 32	if (threadContext->renderer) {
 33		GBAVideoAssociateRenderer(&gba.video, threadContext->renderer);
 34	}
 35
 36	if (threadContext->fd >= 0) {
 37		if (threadContext->fname) {
 38			char* dotPoint = strrchr(threadContext->fname, '.');
 39			if (dotPoint > strrchr(threadContext->fname, '/') && dotPoint[1] && dotPoint[2] && dotPoint[3]) {
 40				savedata = strdup(threadContext->fname);
 41				dotPoint = strrchr(savedata, '.');
 42				dotPoint[1] = 's';
 43				dotPoint[2] = 'a';
 44				dotPoint[3] = 'v';
 45				dotPoint[4] = '\0';
 46			} else if (dotPoint) {
 47				savedata = malloc((dotPoint - threadContext->fname + 5) * sizeof(char));
 48				strncpy(savedata, threadContext->fname, dotPoint - threadContext->fname + 1);
 49				strcat(savedata, "sav");
 50			} else {
 51				savedata = malloc(strlen(threadContext->fname + 5));
 52				strcpy(savedata, threadContext->fname);
 53				strcat(savedata, "sav");
 54			}
 55		}
 56		GBALoadROM(&gba, threadContext->fd, threadContext->fname);
 57		gba.savefile = savedata;
 58	}
 59	if (threadContext->useDebugger) {
 60		threadContext->debugger = &debugger;
 61		GBAAttachDebugger(&gba, &debugger);
 62	} else {
 63		threadContext->debugger = 0;
 64	}
 65	gba.keySource = &threadContext->activeKeys;
 66
 67	threadContext->started = 1;
 68	pthread_mutex_lock(&threadContext->mutex);
 69	pthread_cond_broadcast(&threadContext->cond);
 70	pthread_mutex_unlock(&threadContext->mutex);
 71
 72	if (threadContext->useDebugger) {
 73		ARMDebuggerRun(&debugger);
 74		threadContext->started = 0;
 75	} else {
 76		while (threadContext->started) {
 77			ARMRun(&gba.cpu);
 78		}
 79	}
 80	GBADeinit(&gba);
 81	free(savedata);
 82
 83	return 0;
 84}
 85
 86int GBAThreadStart(struct GBAThread* threadContext) {
 87	// TODO: error check
 88	{
 89		pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
 90		threadContext->mutex = mutex;
 91		pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
 92		threadContext->cond = cond;
 93	}
 94	pthread_mutex_init(&threadContext->mutex, 0);
 95	pthread_cond_init(&threadContext->cond, 0);
 96
 97	pthread_mutex_lock(&threadContext->mutex);
 98	threadContext->activeKeys = 0;
 99	threadContext->started = 0;
100	pthread_create(&threadContext->thread, 0, _GBAThreadRun, threadContext);
101	pthread_cond_wait(&threadContext->cond, &threadContext->mutex);
102	pthread_mutex_unlock(&threadContext->mutex);
103
104	return 0;
105}
106
107void GBAThreadJoin(struct GBAThread* threadContext) {
108	pthread_join(threadContext->thread, 0);
109
110	pthread_mutex_destroy(&threadContext->mutex);
111	pthread_cond_destroy(&threadContext->cond);
112}
113
114struct GBAThread* GBAThreadGetContext(void) {
115	return pthread_getspecific(contextKey);
116}