Use sthread abstraction for threads.

This commit is contained in:
Themaister 2012-06-10 00:46:41 +02:00
parent d3924ab7d6
commit f48f8405a4
5 changed files with 404 additions and 40 deletions

View File

@ -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

View File

@ -27,6 +27,8 @@ void retro_init()
MDFNI_InitializeModules(ext);
std::vector<MDFNSetting> settings;
// FIXME: This will not work on Windows ...
std::string home = getenv("HOME");
home += "/.mednafen";
MDFNI_Initialize(home.c_str(), settings);

View File

@ -4,17 +4,25 @@
#include "mednafen/general.h"
#include "mednafen/mednafen-driver.h"
#include "mednafen/netplay-driver.h"
#include "thread.h"
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/time.h>
#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;
}

277
thread.cpp Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include "thread.h"
#include <stdlib.h>
#if defined(_WIN32) && !defined(_XBOX)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#elif defined(_XBOX)
#include <xtl.h>
#else
#include <pthread.h>
#include <time.h>
#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

46
thread.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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