gpsp/retro_emu_thread.c

176 lines
4.1 KiB
C

// This is copyrighted software. More information is at the end of this file.
#include "retro_emu_thread.h"
#include <pthread.h>
static pthread_t main_thread;
static pthread_t emu_thread;
static pthread_mutex_t emu_mutex;
static pthread_mutex_t main_mutex;
static pthread_cond_t emu_cv;
static pthread_cond_t main_cv;
static bool emu_keep_waiting = true;
static bool main_keep_waiting = true;
static bool emu_has_exited = false;
static bool emu_thread_canceled = false;
static bool emu_thread_initialized = false;
static void* retro_run_emulator(void *args)
{
char *args_str = (char *)args;
bool dynarec = (*args_str++ == 1) ? true : false;
u32 cycles = strtol(args_str, NULL, 10);
emu_has_exited = false;
emu_thread_canceled = false;
#if defined(HAVE_DYNAREC)
if (dynarec)
execute_arm_translate(cycles);
#endif
execute_arm(cycles);
emu_has_exited = true;
return NULL;
}
static void retro_switch_to_emu_thread()
{
pthread_mutex_lock(&emu_mutex);
emu_keep_waiting = false;
pthread_mutex_unlock(&emu_mutex);
pthread_mutex_lock(&main_mutex);
pthread_cond_signal(&emu_cv);
main_keep_waiting = true;
while (main_keep_waiting)
{
pthread_cond_wait(&main_cv, &main_mutex);
}
pthread_mutex_unlock(&main_mutex);
}
static void retro_switch_to_main_thread()
{
pthread_mutex_lock(&main_mutex);
main_keep_waiting = false;
pthread_mutex_unlock(&main_mutex);
pthread_mutex_lock(&emu_mutex);
pthread_cond_signal(&main_cv);
emu_keep_waiting = true;
while (emu_keep_waiting)
{
pthread_cond_wait(&emu_cv, &emu_mutex);
}
pthread_mutex_unlock(&emu_mutex);
}
void retro_switch_thread()
{
if (pthread_self() == main_thread)
retro_switch_to_emu_thread();
else
retro_switch_to_main_thread();
}
bool retro_init_emu_thread(bool dynarec, u32 cycles)
{
char args[256];
args[0] = '\0';
if (emu_thread_initialized)
return true;
/* Keep this very simple:
* - First character: dynarec, 0/1
* - Remaining characters: cycles */
snprintf(args, sizeof(args), " %u", cycles);
args[0] = dynarec ? 1 : 0;
main_thread = pthread_self();
if (pthread_mutex_init(&main_mutex, NULL))
goto main_mutex_error;
if (pthread_mutex_init(&emu_mutex, NULL))
goto emu_mutex_error;
if (pthread_cond_init(&main_cv, NULL))
goto main_cv_error;
if (pthread_cond_init(&emu_cv, NULL))
goto emu_cv_error;
if (pthread_create(&emu_thread, NULL, retro_run_emulator, args))
goto emu_thread_error;
emu_thread_initialized = true;
return true;
emu_thread_error:
pthread_cond_destroy(&emu_cv);
emu_cv_error:
pthread_cond_destroy(&main_cv);
main_cv_error:
pthread_mutex_destroy(&emu_mutex);
emu_mutex_error:
pthread_mutex_destroy(&main_mutex);
main_mutex_error:
return false;
}
void retro_deinit_emu_thread()
{
if (!emu_thread_initialized)
return;
pthread_mutex_destroy(&main_mutex);
pthread_mutex_destroy(&emu_mutex);
pthread_cond_destroy(&main_cv);
pthread_cond_destroy(&emu_cv);
emu_thread_initialized = false;
}
bool retro_is_emu_thread_initialized()
{
return emu_thread_initialized;
}
void retro_join_emu_thread()
{
static bool is_joined = false;
if (is_joined)
return;
pthread_join(emu_thread, NULL);
is_joined = true;
}
void retro_cancel_emu_thread()
{
if (emu_thread_canceled)
return;
pthread_cancel(emu_thread);
emu_thread_canceled = true;
}
bool retro_emu_thread_exited()
{
return emu_has_exited;
}
/*
Copyright (C) 2020 Nikos Chantziaras <realnc@gmail.com>
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <https://www.gnu.org/licenses/>.
*/