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}