1 // This is copyrighted software. More information is at the end of this file.
2 #include "retro_emu_thread.h"
3
4 #include <pthread.h>
5
6 static pthread_t main_thread;
7 static pthread_t emu_thread;
8 static pthread_mutex_t emu_mutex;
9 static pthread_mutex_t main_mutex;
10 static pthread_cond_t emu_cv;
11 static pthread_cond_t main_cv;
12 static bool emu_keep_waiting = true;
13 static bool main_keep_waiting = true;
14 static bool emu_has_exited = false;
15 static bool emu_thread_canceled = false;
16 static bool emu_thread_initialized = false;
17
retro_run_emulator(void * args)18 static void* retro_run_emulator(void *args)
19 {
20 char *args_str = (char *)args;
21 bool dynarec = (*args_str++ == 1) ? true : false;
22 u32 cycles = strtol(args_str, NULL, 10);
23
24 emu_has_exited = false;
25 emu_thread_canceled = false;
26
27 #if defined(HAVE_DYNAREC)
28 if (dynarec)
29 execute_arm_translate(cycles);
30 #endif
31 execute_arm(cycles);
32
33 emu_has_exited = true;
34 return NULL;
35 }
36
retro_switch_to_emu_thread()37 static void retro_switch_to_emu_thread()
38 {
39 pthread_mutex_lock(&emu_mutex);
40 emu_keep_waiting = false;
41 pthread_mutex_unlock(&emu_mutex);
42 pthread_mutex_lock(&main_mutex);
43 pthread_cond_signal(&emu_cv);
44
45 main_keep_waiting = true;
46 while (main_keep_waiting)
47 {
48 pthread_cond_wait(&main_cv, &main_mutex);
49 }
50 pthread_mutex_unlock(&main_mutex);
51 }
52
retro_switch_to_main_thread()53 static void retro_switch_to_main_thread()
54 {
55 pthread_mutex_lock(&main_mutex);
56 main_keep_waiting = false;
57 pthread_mutex_unlock(&main_mutex);
58 pthread_mutex_lock(&emu_mutex);
59 pthread_cond_signal(&main_cv);
60
61 emu_keep_waiting = true;
62 while (emu_keep_waiting)
63 {
64 pthread_cond_wait(&emu_cv, &emu_mutex);
65 }
66 pthread_mutex_unlock(&emu_mutex);
67 }
68
retro_switch_thread()69 void retro_switch_thread()
70 {
71 if (pthread_self() == main_thread)
72 retro_switch_to_emu_thread();
73 else
74 retro_switch_to_main_thread();
75 }
76
retro_init_emu_thread(bool dynarec,u32 cycles)77 bool retro_init_emu_thread(bool dynarec, u32 cycles)
78 {
79 char args[256];
80 args[0] = '\0';
81
82 if (emu_thread_initialized)
83 return true;
84
85 /* Keep this very simple:
86 * - First character: dynarec, 0/1
87 * - Remaining characters: cycles */
88 snprintf(args, sizeof(args), " %u", cycles);
89 args[0] = dynarec ? 1 : 0;
90
91 main_thread = pthread_self();
92 if (pthread_mutex_init(&main_mutex, NULL))
93 goto main_mutex_error;
94 if (pthread_mutex_init(&emu_mutex, NULL))
95 goto emu_mutex_error;
96 if (pthread_cond_init(&main_cv, NULL))
97 goto main_cv_error;
98 if (pthread_cond_init(&emu_cv, NULL))
99 goto emu_cv_error;
100 if (pthread_create(&emu_thread, NULL, retro_run_emulator, args))
101 goto emu_thread_error;
102
103 emu_thread_initialized = true;
104 return true;
105
106 emu_thread_error:
107 pthread_cond_destroy(&emu_cv);
108 emu_cv_error:
109 pthread_cond_destroy(&main_cv);
110 main_cv_error:
111 pthread_mutex_destroy(&emu_mutex);
112 emu_mutex_error:
113 pthread_mutex_destroy(&main_mutex);
114 main_mutex_error:
115 return false;
116 }
117
retro_deinit_emu_thread()118 void retro_deinit_emu_thread()
119 {
120 if (!emu_thread_initialized)
121 return;
122
123 pthread_mutex_destroy(&main_mutex);
124 pthread_mutex_destroy(&emu_mutex);
125 pthread_cond_destroy(&main_cv);
126 pthread_cond_destroy(&emu_cv);
127 emu_thread_initialized = false;
128 }
129
retro_is_emu_thread_initialized()130 bool retro_is_emu_thread_initialized()
131 {
132 return emu_thread_initialized;
133 }
134
retro_join_emu_thread()135 void retro_join_emu_thread()
136 {
137 static bool is_joined = false;
138 if (is_joined)
139 return;
140
141 pthread_join(emu_thread, NULL);
142 is_joined = true;
143 }
144
retro_cancel_emu_thread()145 void retro_cancel_emu_thread()
146 {
147 if (emu_thread_canceled)
148 return;
149
150 pthread_cancel(emu_thread);
151 emu_thread_canceled = true;
152 }
153
retro_emu_thread_exited()154 bool retro_emu_thread_exited()
155 {
156 return emu_has_exited;
157 }
158
159 /*
160
161 Copyright (C) 2020 Nikos Chantziaras <realnc@gmail.com>
162
163 This program is free software: you can redistribute it and/or modify it under
164 the terms of the GNU General Public License as published by the Free Software
165 Foundation, either version 2 of the License, or (at your option) any later
166 version.
167
168 This program is distributed in the hope that it will be useful, but WITHOUT
169 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
170 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
171
172 You should have received a copy of the GNU General Public License along with
173 this program. If not, see <https://www.gnu.org/licenses/>.
174
175 */
176