mirror of https://github.com/sm64pc/sm64pc.git
threads: style fixes, cross-platform crap
This commit is contained in:
parent
39cfae663f
commit
2b67eb4012
6
Makefile
6
Makefile
|
@ -573,16 +573,16 @@ endif
|
|||
|
||||
ifeq ($(WINDOWS_BUILD),1)
|
||||
CC_CHECK := $(CC) -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(INCLUDE_CFLAGS) -Wall -Wextra -Wno-format-security $(VERSION_CFLAGS) $(GRUCODE_CFLAGS)
|
||||
CFLAGS := $(OPT_FLAGS) $(INCLUDE_CFLAGS) $(BACKEND_CFLAGS) $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -fno-strict-aliasing -fwrapv
|
||||
CFLAGS := $(OPT_FLAGS) $(INCLUDE_CFLAGS) $(BACKEND_CFLAGS) $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -fno-strict-aliasing -fwrapv -pthread
|
||||
|
||||
else ifeq ($(TARGET_WEB),1)
|
||||
CC_CHECK := $(CC) -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(INCLUDE_CFLAGS) -Wall -Wextra -Wno-format-security $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -s USE_SDL=2
|
||||
CFLAGS := $(OPT_FLAGS) $(INCLUDE_CFLAGS) $(BACKEND_CFLAGS) $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -fno-strict-aliasing -fwrapv -s USE_SDL=2
|
||||
CFLAGS := $(OPT_FLAGS) $(INCLUDE_CFLAGS) $(BACKEND_CFLAGS) $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -fno-strict-aliasing -fwrapv -pthread -s USE_SDL=2
|
||||
|
||||
# Linux / Other builds below
|
||||
else
|
||||
CC_CHECK := $(CC) -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(PLATFORM_CFLAGS) $(INCLUDE_CFLAGS) -Wall -Wextra -Wno-format-security $(VERSION_CFLAGS) $(GRUCODE_CFLAGS)
|
||||
CFLAGS := $(OPT_FLAGS) $(PLATFORM_CFLAGS) $(INCLUDE_CFLAGS) $(BACKEND_CFLAGS) $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -fno-strict-aliasing -fwrapv
|
||||
CFLAGS := $(OPT_FLAGS) $(PLATFORM_CFLAGS) $(INCLUDE_CFLAGS) $(BACKEND_CFLAGS) $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -fno-strict-aliasing -fwrapv -pthread
|
||||
endif
|
||||
|
||||
# Check for enhancement options
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
#include <stdio.h>
|
||||
#include <unistd.h> //Header file for sleep(). man 3 sleep for details.
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef TARGET_WEB
|
||||
#include <emscripten.h>
|
||||
|
@ -38,6 +39,7 @@
|
|||
#include "game/game_init.h"
|
||||
#include "game/main.h"
|
||||
#include "game/thread6.h"
|
||||
#include "game/display.h"
|
||||
|
||||
#ifdef DISCORDRPC
|
||||
#include "pc/discord/discordrpc.h"
|
||||
|
@ -60,17 +62,17 @@ static struct AudioAPI *audio_api;
|
|||
static struct GfxWindowManagerAPI *wm_api;
|
||||
static struct GfxRenderingAPI *rendering_api;
|
||||
|
||||
pthread_t pcthread_audio_id;
|
||||
pthread_mutex_t pcthread_audio_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
sys_thread_t pcthread_audio_id;
|
||||
sys_mutex_t pcthread_audio_mutex = SYS_MUTEX_INITIALIZER;
|
||||
bool pcthread_audio_init = false;
|
||||
bool pcthread_audio_rendering = false;
|
||||
sem_t pcthread_audio_sema;
|
||||
sys_sem_t pcthread_audio_sema;
|
||||
|
||||
pthread_mutex_t pcthread_game_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
sys_mutex_t pcthread_game_mutex = SYS_MUTEX_INITIALIZER;
|
||||
bool pcthread_game_loop_iterating = false;
|
||||
bool pcthread_game_reset_sound = false;
|
||||
bool pcthread_wait_for_gameloop = false;
|
||||
sem_t pcthread_game_sema;
|
||||
sys_sem_t pcthread_game_sema;
|
||||
|
||||
extern void gfx_run(Gfx *commands);
|
||||
extern void thread5_game_loop(void *arg);
|
||||
|
@ -87,29 +89,34 @@ void set_vblank_handler(s32 index, struct VblankHandler *handler, OSMesgQueue *q
|
|||
|
||||
// Send a request for non-game threads to wait for the game thread to finish
|
||||
void pc_request_gameloop_wait(void) {
|
||||
pcthread_mutex_lock(&pcthread_game_mutex); pcthread_wait_for_gameloop = true; pcthread_mutex_unlock(&pcthread_game_mutex);
|
||||
sys_mutex_lock(&pcthread_game_mutex);
|
||||
pcthread_wait_for_gameloop = true;
|
||||
sys_mutex_unlock(&pcthread_game_mutex);
|
||||
}
|
||||
|
||||
// Wait for the audio thread to finish rendering audio
|
||||
void pc_wait_for_audio(void) {
|
||||
pcthread_semaphore_wait(&pcthread_audio_sema);
|
||||
sys_semaphore_wait(&pcthread_audio_sema);
|
||||
}
|
||||
|
||||
// Check if the audio thread is currently rendering audio
|
||||
bool pc_check_audio_rendering(void) {
|
||||
pcthread_mutex_lock(&pcthread_audio_mutex); bool rendering = pcthread_audio_rendering; pcthread_mutex_unlock(&pcthread_audio_mutex);
|
||||
sys_mutex_lock(&pcthread_audio_mutex);
|
||||
bool rendering = pcthread_audio_rendering;
|
||||
sys_mutex_unlock(&pcthread_audio_mutex);
|
||||
return rendering;
|
||||
}
|
||||
|
||||
// Check if the game thread should finish before continuing
|
||||
bool pc_check_gameloop_wait(void) {
|
||||
pcthread_mutex_lock(&pcthread_game_mutex); bool waiting = pcthread_wait_for_gameloop; pcthread_mutex_unlock(&pcthread_game_mutex);
|
||||
sys_mutex_lock(&pcthread_game_mutex);
|
||||
bool waiting = pcthread_wait_for_gameloop;
|
||||
sys_mutex_unlock(&pcthread_game_mutex);
|
||||
return waiting;
|
||||
}
|
||||
|
||||
static bool inited = false;
|
||||
|
||||
#include "game/display.h" // for gGlobalTimer
|
||||
void send_display_list(struct SPTask *spTask) {
|
||||
if (!inited) return;
|
||||
gfx_run((Gfx *)spTask->task.t.data_ptr);
|
||||
|
@ -129,12 +136,12 @@ void produce_one_frame(void) {
|
|||
game_loop_one_iteration();
|
||||
|
||||
// Post the game thread semaphore if the game thread requested it
|
||||
pcthread_mutex_lock(&pcthread_game_mutex);
|
||||
sys_mutex_lock(&pcthread_game_mutex);
|
||||
if (pcthread_wait_for_gameloop) {
|
||||
pcthread_semaphore_post(&pcthread_game_sema);
|
||||
sys_semaphore_post(&pcthread_game_sema);
|
||||
pcthread_wait_for_gameloop = false;
|
||||
}
|
||||
pcthread_mutex_unlock(&pcthread_game_mutex);
|
||||
sys_mutex_unlock(&pcthread_game_mutex);
|
||||
|
||||
thread6_rumble_loop(NULL);
|
||||
|
||||
|
@ -142,14 +149,13 @@ void produce_one_frame(void) {
|
|||
}
|
||||
|
||||
// Seperate the audio thread from the main thread so that your ears won't bleed at a low framerate
|
||||
// RACE CONDITION:
|
||||
void* audio_thread() {
|
||||
// Keep track of the time in microseconds
|
||||
const f64 frametime_micro = 16666.666; // 16.666666 ms = 60Hz; run this thread 60 times a second like the original game
|
||||
f64 start_time;
|
||||
f64 end_time;
|
||||
bool doloop = true;
|
||||
pcthread_semaphore_wait(&pcthread_game_sema);
|
||||
sys_semaphore_wait(&pcthread_game_sema);
|
||||
while(doloop) {
|
||||
start_time = sys_profile_time();
|
||||
const f32 master_mod = (f32)configMasterVolume / 127.0f;
|
||||
|
@ -167,10 +173,14 @@ void* audio_thread() {
|
|||
u32 num_audio_samples = audio_cnt < 2 ? 528 : 544;*/
|
||||
|
||||
if (!pc_check_gameloop_wait()) {
|
||||
pcthread_mutex_lock(&pcthread_audio_mutex); pcthread_audio_rendering = true; pcthread_mutex_unlock(&pcthread_audio_mutex);
|
||||
sys_mutex_lock(&pcthread_audio_mutex);
|
||||
pcthread_audio_rendering = true;
|
||||
sys_mutex_unlock(&pcthread_audio_mutex);
|
||||
create_next_audio_buffer(audio_buffer, num_audio_samples);
|
||||
pcthread_semaphore_post(&pcthread_audio_sema);
|
||||
pcthread_mutex_lock(&pcthread_audio_mutex); pcthread_audio_rendering = false; pcthread_mutex_unlock(&pcthread_audio_mutex);
|
||||
sys_semaphore_post(&pcthread_audio_sema);
|
||||
sys_mutex_lock(&pcthread_audio_mutex);
|
||||
pcthread_audio_rendering = false;
|
||||
sys_mutex_unlock(&pcthread_audio_mutex);
|
||||
} /* else {
|
||||
printf("Audio thread: dropped frame\n");
|
||||
} */
|
||||
|
@ -186,23 +196,27 @@ void* audio_thread() {
|
|||
if (nap_time > 0.0) sys_sleep(nap_time);
|
||||
|
||||
// Check if the game thread is still running
|
||||
pcthread_mutex_lock(&pcthread_audio_mutex); doloop = pcthread_audio_init; pcthread_mutex_unlock(&pcthread_audio_mutex);
|
||||
sys_mutex_lock(&pcthread_audio_mutex);
|
||||
doloop = pcthread_audio_init;
|
||||
sys_mutex_unlock(&pcthread_audio_mutex);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void audio_thread_init() {
|
||||
pcthread_audio_init = true;
|
||||
pcthread_semaphore_init(&pcthread_audio_sema, 0, 1);
|
||||
pthread_create(&pcthread_audio_id, NULL, audio_thread, NULL);
|
||||
}
|
||||
sys_semaphore_init(&pcthread_audio_sema, 0, 1);
|
||||
sys_thread_create(&pcthread_audio_id, audio_thread, NULL);
|
||||
}
|
||||
|
||||
void audio_shutdown(void) {
|
||||
// Tell the audio thread to stop
|
||||
pcthread_mutex_lock(&pcthread_audio_mutex); pcthread_audio_init = false; pcthread_mutex_unlock(&pcthread_audio_mutex);
|
||||
pcthread_semaphore_wait(&pcthread_audio_sema); // Wait for the audio thread to finish rendering audio, then destroy it all
|
||||
pthread_join(pcthread_audio_id, NULL);
|
||||
pcthread_semaphore_destroy(&pcthread_audio_sema);
|
||||
sys_mutex_lock(&pcthread_audio_mutex);
|
||||
pcthread_audio_init = false;
|
||||
sys_mutex_unlock(&pcthread_audio_mutex);
|
||||
sys_semaphore_wait(&pcthread_audio_sema); // Wait for the audio thread to finish rendering audio, then destroy it all
|
||||
sys_thread_join(&pcthread_audio_id, NULL);
|
||||
sys_semaphore_destroy(&pcthread_audio_sema);
|
||||
|
||||
if (audio_api) {
|
||||
if (audio_api->shutdown) audio_api->shutdown();
|
||||
|
@ -218,7 +232,7 @@ void game_deinit(void) {
|
|||
controller_shutdown();
|
||||
audio_shutdown();
|
||||
gfx_shutdown();
|
||||
pcthread_semaphore_destroy(&pcthread_game_sema);
|
||||
sys_semaphore_destroy(&pcthread_game_sema);
|
||||
inited = false;
|
||||
}
|
||||
|
||||
|
@ -350,7 +364,7 @@ void main_func(void) {
|
|||
request_anim_frame(on_anim_frame);
|
||||
#else
|
||||
// initialize multithreading
|
||||
pcthread_semaphore_init(&pcthread_game_sema, 0, 0);
|
||||
sys_semaphore_init(&pcthread_game_sema, 0, 0);
|
||||
audio_thread_init();
|
||||
|
||||
while (true) {
|
||||
|
|
|
@ -11,6 +11,13 @@
|
|||
#include "configfile.h"
|
||||
#include "platform.h"
|
||||
|
||||
#if !defined(HAVE_SDL2) && !defined(CLOCK_MONOTONIC)
|
||||
#include <sys/time.h>
|
||||
#elif defined(HAVE_SDL2)
|
||||
// we can just ask SDL for most of this shit if we have it
|
||||
#include <SDL2/SDL.h>
|
||||
#endif
|
||||
|
||||
/* NULL terminated list of platform specific read-only data paths */
|
||||
/* priority is top first */
|
||||
const char *sys_ropaths[] = {
|
||||
|
@ -75,10 +82,20 @@ void sys_sleep(const uint64_t us) {
|
|||
|
||||
// A high-resolution profiling timer. Returns the current time in microseconds.
|
||||
double sys_profile_time(void) {
|
||||
// TODO: Platform specific stuff
|
||||
#if defined(HAVE_SDL2)
|
||||
static double freq = 0.0;
|
||||
if (freq == 0.0)
|
||||
freq = (double)SDL_GetPerformanceFrequency() / 1000000.0;
|
||||
return (double)SDL_GetPerformanceCounter() / freq;
|
||||
#elif defined(CLOCK_MONOTONIC)
|
||||
struct timespec tv;
|
||||
clock_gettime(CLOCK_MONOTONIC, &tv);
|
||||
return (double)(tv.tv_nsec) / 1000.0 + (double)(tv.tv_sec) * 1000000.0;
|
||||
return (double)tv.tv_nsec / 1000.0 + (double)tv.tv_sec * 1000000.0;
|
||||
#else
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return (double)tv.tv_usec + (double)tv.tv_sec * 1000000.0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* this calls a platform-specific impl function after forming the error message */
|
||||
|
@ -97,9 +114,6 @@ void sys_fatal(const char *fmt, ...) {
|
|||
|
||||
#ifdef HAVE_SDL2
|
||||
|
||||
// we can just ask SDL for most of this shit if we have it
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
// TEMPORARY: check the old save folder and copy contents to the new path
|
||||
// this will be removed after a while
|
||||
static inline bool copy_userdata(const char *userdir) {
|
||||
|
|
|
@ -1,26 +1,44 @@
|
|||
#include "thread.h"
|
||||
|
||||
// TODO: Cross-platform stuff
|
||||
#ifdef HAVE_POSIX_THREADS
|
||||
|
||||
void pcthread_mutex_lock(pthread_mutex_t *mutex) {
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
int sys_thread_create(sys_thread_t *thread, sys_thread_func_t func, void *arg) {
|
||||
return pthread_create(thread, NULL, func, arg);
|
||||
}
|
||||
|
||||
int sys_thread_join(sys_thread_t *thread, void **result) {
|
||||
return pthread_join(*thread, result);
|
||||
}
|
||||
|
||||
void sys_mutex_lock(sys_mutex_t *mutex) {
|
||||
pthread_mutex_lock(mutex);
|
||||
}
|
||||
|
||||
void pcthread_mutex_unlock(pthread_mutex_t *mutex) {
|
||||
void sys_mutex_unlock(sys_mutex_t *mutex) {
|
||||
pthread_mutex_unlock(mutex);
|
||||
}
|
||||
void pcthread_semaphore_init(sem_t *sem, int pshared, unsigned int value) {
|
||||
|
||||
void sys_semaphore_init(sys_sem_t *sem, int pshared, unsigned int value) {
|
||||
sem_init(sem, pshared, value);
|
||||
}
|
||||
|
||||
void pcthread_semaphore_wait(sem_t *sem) {
|
||||
void sys_semaphore_wait(sys_sem_t *sem) {
|
||||
sem_wait(sem);
|
||||
}
|
||||
|
||||
void pcthread_semaphore_post(sem_t *sem) {
|
||||
void sys_semaphore_post(sys_sem_t *sem) {
|
||||
sem_post(sem);
|
||||
}
|
||||
|
||||
void pcthread_semaphore_destroy(sem_t *sem) {
|
||||
void sys_semaphore_destroy(sys_sem_t *sem) {
|
||||
sem_destroy(sem);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error "Implement thread.c for your platform."
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,15 +1,30 @@
|
|||
#ifndef _PC_THREAD_H
|
||||
#define _PC_THREAD_H
|
||||
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <stdbool.h>
|
||||
// TODO: add other backends if required
|
||||
#define HAVE_POSIX_THREADS 1
|
||||
|
||||
void pcthread_mutex_lock(pthread_mutex_t *mutex);
|
||||
void pcthread_mutex_unlock(pthread_mutex_t *mutex);
|
||||
void pcthread_semaphore_init(sem_t *sem, int pshared, unsigned int value);
|
||||
void pcthread_semaphore_wait(sem_t *sem);
|
||||
void pcthread_semaphore_post(sem_t *sem);
|
||||
void pcthread_semaphore_destroy(sem_t *sem);
|
||||
#ifdef HAVE_POSIX_THREADS
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
typedef pthread_t sys_thread_t;
|
||||
typedef void *(*sys_thread_func_t)(void *);
|
||||
typedef pthread_mutex_t sys_mutex_t;
|
||||
typedef sem_t sys_sem_t;
|
||||
#define SYS_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
|
||||
#else
|
||||
#error "Implement thread.c for your platform."
|
||||
#endif
|
||||
|
||||
#endif // _PC_THREAD_H
|
||||
int sys_thread_create(sys_thread_t *thread, sys_thread_func_t func, void *arg);
|
||||
int sys_thread_join(sys_thread_t *thread, void **result);
|
||||
|
||||
void sys_mutex_lock(sys_mutex_t *mutex);
|
||||
void sys_mutex_unlock(sys_mutex_t *mutex);
|
||||
|
||||
void sys_semaphore_init(sys_sem_t *sem, int pshared, unsigned int value);
|
||||
void sys_semaphore_wait(sys_sem_t *sem);
|
||||
void sys_semaphore_post(sys_sem_t *sem);
|
||||
void sys_semaphore_destroy(sys_sem_t *sem);
|
||||
|
||||
#endif // _PC_THREAD_H
|
||||
|
|
Loading…
Reference in New Issue