@@ -5,13 +5,122 @@ package libretro
5
5
#include <stdbool.h>
6
6
#include <stdarg.h>
7
7
#include <stdio.h>
8
+ #include <pthread.h>
9
+
10
+ #ifdef __APPLE__
11
+ #include <mach/semaphore.h>
12
+ #include <mach/task.h>
13
+ #include <mach/mach_init.h>
14
+ #define SEM_T semaphore_t
15
+ #define SEM_INIT(x) semaphore_create(mach_task_self(), &x, SYNC_POLICY_FIFO, 0);
16
+ #define SEM_POST(x) semaphore_signal(x)
17
+ #define SEM_WAIT(x) semaphore_wait(x)
18
+ #else
19
+ #include <semaphore.h>
20
+ #define SEM_T sem_t
21
+ #define SEM_INIT(x) sem_init(&x, 0, 0)
22
+ #define SEM_POST(x) sem_post(&x)
23
+ #define SEM_WAIT(x) sem_wait(&x)
24
+ #endif
25
+
26
+ #if 0
27
+ #define print_sema(...) (printf(__VA_ARGS__))
28
+ #else
29
+ #define print_sema(...) do {} while (0)
30
+ #endif
31
+
32
+ enum {
33
+ CMD_F,
34
+ CMD_SERIALIZE,
35
+ };
36
+
37
+ struct thread_cmd_t {
38
+ int cmd;
39
+ void* f;
40
+ void* arg1;
41
+ void* arg2;
42
+ void* arg3;
43
+ void* arg4;
44
+ void* res;
45
+ };
46
+
47
+ struct thread_cmd_t s_job;
48
+ static pthread_t s_thread;
49
+ static SEM_T s_sem_do;
50
+ static SEM_T s_sem_done;
51
+ static bool s_use_thread = false;
52
+
53
+ void* emu_thread_loop(void *a0) {
54
+ print_sema("begin thread\n");
55
+
56
+ SEM_POST(s_sem_done);
57
+
58
+ print_sema("signal thread\n");
59
+
60
+ while (1) {
61
+ print_sema("wait do\n");
62
+ SEM_WAIT(s_sem_do);
63
+
64
+ print_sema("do\n");
65
+ switch (s_job.cmd) {
66
+ case CMD_F:
67
+ ((void (*)(void))s_job.f)();
68
+ break;
69
+ case CMD_SERIALIZE: {
70
+ bool res = ((bool (*)(void*, size_t))s_job.f)(s_job.arg1, *(size_t*)s_job.arg2);
71
+ *(bool*)s_job.res = res;
72
+ break;
73
+ }
74
+ default:
75
+ break;
76
+ }
77
+
78
+ print_sema("signal done\n");
79
+ SEM_POST(s_sem_done);
80
+ }
81
+ }
82
+
83
+ void thread_sync() {
84
+ // Fire the job
85
+ print_sema("signal do\n");
86
+ SEM_POST(s_sem_do);
87
+
88
+ // Wait the result
89
+ print_sema("wait done\n");
90
+ SEM_WAIT(s_sem_done);
91
+
92
+ print_sema("done\n");
93
+ }
94
+
95
+ void run_wrapper(void *f) {
96
+ if (s_use_thread) {
97
+ s_job.cmd = CMD_F;
98
+ s_job.f = f;
99
+ thread_sync();
100
+ } else {
101
+ ((void (*)(void))f)();
102
+ }
103
+ }
104
+
105
+ void cothread_init() {
106
+ s_use_thread = true;
107
+
108
+ SEM_INIT(s_sem_do);
109
+ SEM_INIT(s_sem_done);
110
+
111
+ print_sema("create thread\n");
112
+ pthread_create(&s_thread, NULL, emu_thread_loop, NULL);
113
+
114
+ print_sema("wait thread\n");
115
+ SEM_WAIT(s_sem_done);
116
+ }
8
117
9
118
void bridge_retro_init(void *f) {
10
- return ((void (*)(void))f)( );
119
+ run_wrapper(f );
11
120
}
12
121
13
122
void bridge_retro_deinit(void *f) {
14
- return ((void (*)(void))f)( );
123
+ run_wrapper(f );
15
124
}
16
125
17
126
unsigned bridge_retro_api_version(void *f) {
@@ -75,23 +184,49 @@ size_t bridge_retro_serialize_size(void *f) {
75
184
}
76
185
77
186
bool bridge_retro_serialize(void *f, void *data, size_t size) {
78
- return ((bool (*)(void*, size_t))f)(data, size);
187
+ if (s_use_thread) {
188
+ bool res;
189
+ s_job.cmd = CMD_SERIALIZE;
190
+ s_job.f = f;
191
+ s_job.arg1 = data;
192
+ s_job.arg2 = &size;
193
+ s_job.res = &res;
194
+
195
+ thread_sync();
196
+
197
+ return s_job.res;
198
+ } else {
199
+ return ((bool (*)(void*, size_t))f)(data, size);
200
+ }
79
201
}
80
202
81
203
bool bridge_retro_unserialize(void *f, void *data, size_t size) {
82
- return ((bool (*)(void*, size_t))f)(data, size);
204
+ if (s_use_thread) {
205
+ bool res;
206
+ s_job.cmd = CMD_SERIALIZE; // Same command format for both serialize & unserialize
207
+ s_job.f = f;
208
+ s_job.arg1 = data;
209
+ s_job.arg2 = &size;
210
+ s_job.res = &res;
211
+
212
+ thread_sync();
213
+
214
+ return s_job.res;
215
+ } else {
216
+ return ((bool (*)(void*, size_t))f)(data, size);
217
+ }
83
218
}
84
219
85
220
void bridge_retro_unload_game(void *f) {
86
- return ((void (*)(void))f)( );
221
+ run_wrapper(f );
87
222
}
88
223
89
224
void bridge_retro_run(void *f) {
90
- return ((void (*)(void))f)( );
225
+ run_wrapper(f );
91
226
}
92
227
93
228
void bridge_retro_reset(void *f) {
94
- return ((void (*)(void))f)( );
229
+ run_wrapper(f );
95
230
}
96
231
97
232
size_t bridge_retro_get_memory_size(void *f, unsigned id) {
0 commit comments