From f48f8405a49cb355ea1b52f0137800488ad1ed75 Mon Sep 17 00:00:00 2001 From: Themaister Date: Sun, 10 Jun 2012 00:46:41 +0200 Subject: [PATCH] Use sthread abstraction for threads. --- Makefile | 51 ++++++++-- libretro.cpp | 2 + stubs.cpp | 68 +++++++------ thread.cpp | 277 +++++++++++++++++++++++++++++++++++++++++++++++++++ thread.h | 46 +++++++++ 5 files changed, 404 insertions(+), 40 deletions(-) create mode 100644 thread.cpp create mode 100644 thread.h diff --git a/Makefile b/Makefile index bbc09d2..2821cc4 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,39 @@ -TARGET := libretro.so + +ifeq ($(platform),) +platform = unix +ifeq ($(shell uname -a),) + platform = win +else ifneq ($(findstring Darwin,$(shell uname -a)),) + platform = osx +else ifneq ($(findstring MINGW,$(shell uname -a)),) + platform = win +endif +endif + +ifeq ($(platform), unix) + TARGET := libretro.so + fpic := -fPIC + SHARED := -shared -Wl,-no-undefined -Wl,--version-script=link.T + ENDIANNESS_DEFINES := -DLSB_FIRST + LDFLAGS += -pthread + FLAGS += -pthread -DHAVE_MKDIR +else ifeq ($(platform), osx) + TARGET := libretro.dylib + fpic := -fPIC + SHARED := -dynamiclib + ENDIANNESS_DEFINES := -DLSB_FIRST + LDFLAGS += -pthread + FLAGS += -pthread -DHAVE_MKDIR +else + TARGET := retro.dll + CC = gcc + CXX = g++ + SHARED := -shared -Wl,-no-undefined -Wl,--version-script=link.T + LDFLAGS += -static-libgcc -static-libstdc++ -lwinmm + ENDIANNESS_DEFINES := -DLSB_FIRST + FLAGS += -DHAVE__MKDIR +endif + MEDNAFEN_DIR := mednafen PSX_DIR := $(MEDNAFEN_DIR)/psx @@ -74,9 +109,12 @@ MEDNAFEN_SOURCES := $(MEDNAFEN_DIR)/cdrom/cdromif.cpp \ MPC_SRC := $(wildcard $(MEDNAFEN_DIR)/mpcdec/*.c) TREMOR_SRC := $(wildcard $(MEDNAFEN_DIR)/tremor/*.c) +LIBRETRO_SOURCES := libretro.cpp stubs.cpp thread.cpp + SOURCES_C := $(MEDNAFEN_DIR)/trio/trio.c \ $(MPC_SRC) \ $(TREMOR_SRC) \ + $(LIBRETRO_SOURCES_C) \ $(MEDNAFEN_DIR)/trio/trionan.c \ $(MEDNAFEN_DIR)/trio/triostr.c \ $(MEDNAFEN_DIR)/string/world_strtod.c \ @@ -87,17 +125,14 @@ SOURCES_C := $(MEDNAFEN_DIR)/trio/trio.c \ $(MEDNAFEN_DIR)/compress/ioapi.c \ $(MEDNAFEN_DIR)/resampler/resample.c -LIBRETRO_SOURCES := libretro.cpp stubs.cpp - SOURCES := $(LIBRETRO_SOURCES) $(PSX_SOURCES) $(MEDNAFEN_SOURCES) OBJECTS := $(SOURCES:.cpp=.o) $(SOURCES_C:.c=.o) all: $(TARGET) - -LDFLAGS += -Wl,--no-undefined -fPIC -shared -lz -Wl,--version-script=link.T -pthread -FLAGS += -ffast-math -msse -msse2 -funroll-loops -O3 -g -Wall -fPIC -fno-strict-overflow -FLAGS += -I. -Imednafen -Imednafen/include -Imednafen/intl -pthread +LDFLAGS += $(fpic) -lz +FLAGS += -ffast-math -msse -msse2 -funroll-loops -O3 -g -Wall $(fpic) -fno-strict-overflow +FLAGS += -I. -Imednafen -Imednafen/include -Imednafen/intl WARNINGS := -Wall \ -Wno-narrowing \ @@ -110,7 +145,7 @@ WARNINGS := -Wall \ -Wno-strict-aliasing \ -Wno-overflow -FLAGS += -DLSB_FIRST -DHAVE_MKDIR -DSIZEOF_DOUBLE=8 $(WARNINGS) \ +FLAGS += $(ENDIANNESS_DEFINES) -DSIZEOF_DOUBLE=8 $(WARNINGS) \ -DMEDNAFEN_VERSION=\"0.9.22\" -DMEDNAFEN_VERSION_NUMERIC=922 -DPSS_STYLE=1 -DMPC_FIXED_POINT -DARCH_X86 \ -DWANT_PSX_EMU -DSTDC_HEADERS diff --git a/libretro.cpp b/libretro.cpp index 9b73533..a3c62c1 100644 --- a/libretro.cpp +++ b/libretro.cpp @@ -27,6 +27,8 @@ void retro_init() MDFNI_InitializeModules(ext); std::vector settings; + + // FIXME: This will not work on Windows ... std::string home = getenv("HOME"); home += "/.mednafen"; MDFNI_Initialize(home.c_str(), settings); diff --git a/stubs.cpp b/stubs.cpp index bdf7bef..3ea8beb 100644 --- a/stubs.cpp +++ b/stubs.cpp @@ -4,17 +4,25 @@ #include "mednafen/general.h" #include "mednafen/mednafen-driver.h" #include "mednafen/netplay-driver.h" +#include "thread.h" #include -#include -#include + +#ifdef _WIN32 +#include +#else #include +#endif // Stubs void MDFND_Sleep(unsigned int time) { +#ifdef _WIN32 + Sleep(time); +#else usleep(time * 1000); +#endif } void MDFND_DispMessage(unsigned char *str) @@ -37,11 +45,7 @@ void MDFND_PrintError(const char* err) MDFN_Thread *MDFND_CreateThread(int (*fn)(void *), void *data) { - pthread_t *thread = new pthread_t; - - pthread_create(thread, NULL, (void* (*)(void *))fn, data); - - return (MDFN_Thread*)thread; + return (MDFN_Thread*)sthread_create((void (*)(void*))fn, data); } void MDFND_SetMovieStatus(StateStatusStruct *) {} @@ -49,49 +53,39 @@ void MDFND_SetStateStatus(StateStatusStruct *) {} void MDFND_WaitThread(MDFN_Thread *thr, int *val) { - pthread_t *thread = (pthread_t*)thr; - void *data; - pthread_join(*thread, &data); + sthread_join((sthread_t*)thr); if (val) - *val = (intptr_t)data; - - delete thread; + { + *val = 0; + std::cerr << "WaitThread relies on return value." << std::endl; + } } -void MDFND_KillThread(MDFN_Thread *thr) +void MDFND_KillThread(MDFN_Thread *) { - pthread_t *thread = (pthread_t*)thr; - pthread_cancel(*thread); - pthread_join(*thread, NULL); - delete thread; + std::cerr << "Killing a thread is a BAD IDEA!" << std::endl; } MDFN_Mutex *MDFND_CreateMutex() { - pthread_mutex_t *mutex = new pthread_mutex_t; - pthread_mutex_init(mutex, NULL); - return (MDFN_Mutex*)mutex; + return (MDFN_Mutex*)slock_new(); } void MDFND_DestroyMutex(MDFN_Mutex *lock) { - pthread_mutex_t *mutex = (pthread_mutex_t*)lock; - pthread_mutex_destroy(mutex); - delete mutex; + slock_free((slock_t*)lock); } int MDFND_LockMutex(MDFN_Mutex *lock) { - pthread_mutex_t *mutex = (pthread_mutex_t*)lock; - pthread_mutex_lock(mutex); + slock_lock((slock_t*)lock); return 0; } int MDFND_UnlockMutex(MDFN_Mutex *lock) { - pthread_mutex_t *mutex = (pthread_mutex_t*)lock; - pthread_mutex_unlock(mutex); + slock_unlock((slock_t*)lock); return 0; } @@ -102,17 +96,27 @@ void MDFND_NetworkClose() {} uint32 MDFND_GetTime() { - struct timeval val; - gettimeofday(&val, NULL); - uint32_t ms = val.tv_sec * 1000 + val.tv_usec / 1000; - static bool first = true; static uint32_t start_ms; + +#ifdef _WIN32 + DWORD ms = timeGetTime(); if (first) { start_ms = ms; first = false; } +#else + struct timeval val; + gettimeofday(&val, NULL); + uint32_t ms = val.tv_sec * 1000 + val.tv_usec / 1000; + + if (first) + { + start_ms = ms; + first = false; + } +#endif return ms - start_ms; } diff --git a/thread.cpp b/thread.cpp new file mode 100644 index 0000000..af9d068 --- /dev/null +++ b/thread.cpp @@ -0,0 +1,277 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2012 - Hans-Kristian Arntzen + * + * RetroArch 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch 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 RetroArch. + * If not, see . + */ + +#include "thread.h" +#include + +#if defined(_WIN32) && !defined(_XBOX) +#define WIN32_LEAN_AND_MEAN +#include +#elif defined(_XBOX) +#include +#else +#include +#include +#endif + +struct thread_data +{ + void (*func)(void*); + void *userdata; +}; + +#ifdef _WIN32 + +struct sthread +{ + HANDLE thread; +}; + +static DWORD CALLBACK thread_wrap(void *data_) +{ + struct thread_data *data = (struct thread_data*)data_; + data->func(data->userdata); + free(data); + return 0; +} + +sthread_t *sthread_create(void (*thread_func)(void*), void *userdata) +{ + sthread_t *thread = (sthread_t*)calloc(1, sizeof(*thread)); + if (!thread) + return NULL; + + struct thread_data *data = (struct thread_data*)calloc(1, sizeof(*data)); + if (!data) + { + free(thread); + return NULL; + } + + data->func = thread_func; + data->userdata = userdata; + + thread->thread = CreateThread(NULL, 0, thread_wrap, data, 0, NULL); + if (!thread->thread) + { + free(data); + free(thread); + return NULL; + } + + return thread; +} + +void sthread_join(sthread_t *thread) +{ + WaitForSingleObject(thread->thread, INFINITE); + CloseHandle(thread->thread); + free(thread); +} + +struct slock +{ + CRITICAL_SECTION lock; +}; + +slock_t *slock_new(void) +{ + slock_t *lock = (slock_t*)calloc(1, sizeof(*lock)); + if (!lock) + return NULL; + + InitializeCriticalSection(&lock->lock); + return lock; +} + +void slock_free(slock_t *lock) +{ + DeleteCriticalSection(&lock->lock); + free(lock); +} + +void slock_lock(slock_t *lock) +{ + EnterCriticalSection(&lock->lock); +} + +void slock_unlock(slock_t *lock) +{ + LeaveCriticalSection(&lock->lock); +} + +struct scond +{ + HANDLE event; +}; + +scond_t *scond_new(void) +{ + scond_t *cond = (scond_t*)calloc(1, sizeof(*cond)); + if (!cond) + return NULL; + + cond->event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!cond->event) + { + free(cond); + return NULL; + } + + return cond; +} + +void scond_wait(scond_t *cond, slock_t *lock) +{ + WaitForSingleObject(cond->event, 0); + slock_unlock(lock); + + WaitForSingleObject(cond->event, INFINITE); + + slock_lock(lock); +} + +void scond_signal(scond_t *cond) +{ + SetEvent(cond->event); +} + +void scond_free(scond_t *cond) +{ + CloseHandle(cond->event); + free(cond); +} + +#else + +struct sthread +{ + pthread_t id; +}; + +static void *thread_wrap(void *data_) +{ + struct thread_data *data = (struct thread_data*)data_; + data->func(data->userdata); + free(data); + return NULL; +} + +sthread_t *sthread_create(void (*thread_func)(void*), void *userdata) +{ + sthread_t *thr = (sthread_t*)calloc(1, sizeof(*thr)); + if (!thr) + return NULL; + + struct thread_data *data = (struct thread_data*)calloc(1, sizeof(*data)); + if (!data) + { + free(thr); + return NULL; + } + + data->func = thread_func; + data->userdata = userdata; + + if (pthread_create(&thr->id, NULL, thread_wrap, data) < 0) + { + free(data); + free(thr); + return NULL; + } + + return thr; +} + +void sthread_join(sthread_t *thread) +{ + pthread_join(thread->id, NULL); + free(thread); +} + +struct slock +{ + pthread_mutex_t lock; +}; + +slock_t *slock_new(void) +{ + slock_t *lock = (slock_t*)calloc(1, sizeof(*lock)); + if (!lock) + return NULL; + + if (pthread_mutex_init(&lock->lock, NULL) < 0) + { + free(lock); + return NULL; + } + + return lock; +} + +void slock_free(slock_t *lock) +{ + pthread_mutex_destroy(&lock->lock); + free(lock); +} + +void slock_lock(slock_t *lock) +{ + pthread_mutex_lock(&lock->lock); +} + +void slock_unlock(slock_t *lock) +{ + pthread_mutex_unlock(&lock->lock); +} + +struct scond +{ + pthread_cond_t cond; +}; + +scond_t *scond_new(void) +{ + scond_t *cond = (scond_t*)calloc(1, sizeof(*cond)); + if (!cond) + return NULL; + + if (pthread_cond_init(&cond->cond, NULL) < 0) + { + free(cond); + return NULL; + } + + return cond; +} + +void scond_free(scond_t *cond) +{ + pthread_cond_destroy(&cond->cond); + free(cond); +} + +void scond_wait(scond_t *cond, slock_t *lock) +{ + pthread_cond_wait(&cond->cond, &lock->lock); +} + +void scond_signal(scond_t *cond) +{ + pthread_cond_signal(&cond->cond); +} + +#endif + diff --git a/thread.h b/thread.h new file mode 100644 index 0000000..96b1606 --- /dev/null +++ b/thread.h @@ -0,0 +1,46 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2012 - Hans-Kristian Arntzen + * + * RetroArch 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch 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 RetroArch. + * If not, see . + */ + +#ifndef THREAD_H__ +#define THREAD_H__ + +// Implements the bare minimum needed for RetroArch. :) + +typedef struct sthread sthread_t; + +// Threading +sthread_t *sthread_create(void (*thread_func)(void*), void *userdata); +void sthread_join(sthread_t *thread); + +// Mutexes +typedef struct slock slock_t; + +slock_t *slock_new(void); +void slock_free(slock_t *lock); + +void slock_lock(slock_t *lock); +void slock_unlock(slock_t *lock); + +// Condition variables. +typedef struct scond scond_t; + +scond_t *scond_new(void); +void scond_free(scond_t *cond); + +void scond_wait(scond_t *cond, slock_t *lock); +void scond_signal(scond_t *cond); + +#endif +