diff --git a/Makefile b/Makefile index 234a7ae941..2cd6a18c0e 100644 --- a/Makefile +++ b/Makefile @@ -2,11 +2,11 @@ include config.mk TARGET = ssnes tools/ssnes-joyconfig -OBJ = ssnes.o file.o driver.o settings.o dynamic.o message.o rewind.o movie.o autosave.o gfx/gfx_common.o ups.o bps.o strl.o screenshot.o +OBJ = ssnes.o file.o driver.o settings.o dynamic.o message.o rewind.o movie.o autosave.o gfx/gfx_common.o ups.o bps.o strl.o screenshot.o thread.o JOYCONFIG_OBJ = tools/ssnes-joyconfig.o conf/config_file.o strl.o HEADERS = $(wildcard */*.h) $(wildcard *.h) -LIBS = -lm +LIBS = -lm -lpthread DEFINES = -DHAVE_CONFIG_H ifneq ($(findstring Darwin,$(OS)),) diff --git a/Makefile.win b/Makefile.win index 22549eceeb..6c6af51a78 100644 --- a/Makefile.win +++ b/Makefile.win @@ -1,6 +1,6 @@ TARGET = ssnes.exe JTARGET = ssnes-joyconfig.exe -OBJ = ssnes.o file.o driver.o conf/config_file.o settings.o dynamic.o message.o rewind.o movie.o autosave.o gfx/gfx_common.o bps.o ups.o strl.o screenshot.o audio/hermite.o +OBJ = ssnes.o file.o driver.o conf/config_file.o settings.o dynamic.o message.o rewind.o movie.o autosave.o gfx/gfx_common.o bps.o ups.o strl.o screenshot.o audio/hermite.o thread.o JOBJ = conf/config_file.o tools/main-stub.o tools/ssnes-joyconfig.o strl.o CC = gcc diff --git a/autosave.c b/autosave.c index 7ac93edf3b..323cef60ee 100644 --- a/autosave.c +++ b/autosave.c @@ -16,7 +16,7 @@ */ #include "autosave.h" -#include "SDL.h" +#include "thread.h" #include #include #include @@ -26,11 +26,11 @@ struct autosave { volatile bool quit; - SDL_mutex *lock; + slock_t *lock; - SDL_mutex *cond_lock; - SDL_cond *cond; - SDL_Thread *thread; + slock_t *cond_lock; + scond_t *cond; + sthread_t *thread; void *buffer; const void *snes_buffer; @@ -39,7 +39,7 @@ struct autosave unsigned interval; }; -static int autosave_thread(void *data) +static void autosave_thread(void *data) { autosave_t *save = data; @@ -77,13 +77,11 @@ static int autosave_thread(void *data) } } - SDL_mutexP(save->cond_lock); + slock_lock(save->cond_lock); if (!save->quit) - SDL_CondWaitTimeout(save->cond, save->cond_lock, save->interval * 1000); - SDL_mutexV(save->cond_lock); + scond_wait_timeout(save->cond, save->cond_lock, save->interval * 1000); + slock_unlock(save->cond_lock); } - - return 0; } autosave_t *autosave_new(const char *path, const void *data, size_t size, unsigned interval) @@ -105,36 +103,36 @@ autosave_t *autosave_new(const char *path, const void *data, size_t size, unsign } memcpy(handle->buffer, handle->snes_buffer, handle->bufsize); - handle->lock = SDL_CreateMutex(); - handle->cond_lock = SDL_CreateMutex(); - handle->cond = SDL_CreateCond(); + handle->lock = slock_new(); + handle->cond_lock = slock_new(); + handle->cond = scond_new(); - handle->thread = SDL_CreateThread(autosave_thread, handle); + handle->thread = sthread_create(autosave_thread, handle); return handle; } void autosave_lock(autosave_t *handle) { - SDL_mutexP(handle->lock); + slock_lock(handle->lock); } void autosave_unlock(autosave_t *handle) { - SDL_mutexV(handle->lock); + slock_unlock(handle->lock); } void autosave_free(autosave_t *handle) { - SDL_mutexP(handle->cond_lock); + slock_lock(handle->cond_lock); handle->quit = true; - SDL_mutexV(handle->cond_lock); - SDL_CondSignal(handle->cond); - SDL_WaitThread(handle->thread, NULL); + slock_unlock(handle->cond_lock); + scond_signal(handle->cond); + sthread_join(handle->thread); - SDL_DestroyMutex(handle->lock); - SDL_DestroyMutex(handle->cond_lock); - SDL_DestroyCond(handle->cond); + slock_free(handle->lock); + slock_free(handle->cond_lock); + scond_free(handle->cond); free(handle->buffer); free(handle); diff --git a/record/ffemu.c b/record/ffemu.c index 51d72447cc..d8f3aee9e9 100644 --- a/record/ffemu.c +++ b/record/ffemu.c @@ -13,7 +13,7 @@ #include #include "ffemu.h" #include "fifo_buffer.h" -#include "SDL_thread.h" +#include "thread.h" #ifdef HAVE_CONFIG_H #include "../config.h" @@ -66,13 +66,14 @@ struct ffemu struct ffemu_params params; - SDL_cond *cond; - SDL_mutex *cond_lock; - SDL_mutex *lock; + scond_t *cond; + slock_t *cond_lock; + slock_t *lock; fifo_buffer_t *audio_fifo; fifo_buffer_t *video_fifo; fifo_buffer_t *attr_fifo; - SDL_Thread *thread; + sthread_t *thread; + volatile bool alive; volatile bool can_sleep; }; @@ -229,13 +230,13 @@ static bool init_muxer(ffemu_t *handle) #define MAX_FRAMES 64 -static int SDLCALL ffemu_thread(void *data); +static void ffemu_thread(void *data); static bool init_thread(ffemu_t *handle) { - assert(handle->lock = SDL_CreateMutex()); - assert(handle->cond_lock = SDL_CreateMutex()); - assert(handle->cond = SDL_CreateCond()); + assert(handle->lock = slock_new()); + assert(handle->cond_lock = slock_new()); + assert(handle->cond = scond_new()); assert(handle->audio_fifo = fifo_new(32000 * sizeof(int16_t) * handle->params.channels * MAX_FRAMES / 60)); assert(handle->attr_fifo = fifo_new(sizeof(struct ffemu_video_data) * MAX_FRAMES)); assert(handle->video_fifo = fifo_new(handle->params.fb_width * handle->params.fb_height * @@ -243,7 +244,7 @@ static bool init_thread(ffemu_t *handle) handle->alive = true; handle->can_sleep = true; - assert(handle->thread = SDL_CreateThread(ffemu_thread, handle)); + assert(handle->thread = sthread_create(ffemu_thread, handle)); return true; } @@ -252,17 +253,17 @@ static void deinit_thread(ffemu_t *handle) { if (handle->thread) { - SDL_mutexP(handle->cond_lock); + slock_lock(handle->cond_lock); handle->alive = false; handle->can_sleep = false; - SDL_mutexV(handle->cond_lock); + slock_unlock(handle->cond_lock); - SDL_CondSignal(handle->cond); - SDL_WaitThread(handle->thread, NULL); + scond_signal(handle->cond); + sthread_join(handle->thread); - SDL_DestroyMutex(handle->lock); - SDL_DestroyMutex(handle->cond_lock); - SDL_DestroyCond(handle->cond); + slock_free(handle->lock); + slock_free(handle->cond_lock); + scond_free(handle->cond); handle->thread = NULL; } @@ -357,9 +358,9 @@ int ffemu_push_video(ffemu_t *handle, const struct ffemu_video_data *data) { for (;;) { - SDL_mutexP(handle->lock); + slock_lock(handle->lock); unsigned avail = fifo_write_avail(handle->attr_fifo); - SDL_mutexV(handle->lock); + slock_unlock(handle->lock); if (!handle->alive) return -1; @@ -367,24 +368,24 @@ int ffemu_push_video(ffemu_t *handle, const struct ffemu_video_data *data) if (avail >= sizeof(*data)) break; - SDL_mutexP(handle->cond_lock); + slock_lock(handle->cond_lock); if (handle->can_sleep) { handle->can_sleep = false; - SDL_CondWait(handle->cond, handle->cond_lock); + scond_wait(handle->cond, handle->cond_lock); handle->can_sleep = true; } else - SDL_CondSignal(handle->cond); + scond_signal(handle->cond); - SDL_mutexV(handle->cond_lock); + slock_unlock(handle->cond_lock); } - SDL_mutexP(handle->lock); + slock_lock(handle->lock); fifo_write(handle->attr_fifo, data, sizeof(*data)); fifo_write(handle->video_fifo, data->data, data->pitch * data->height); - SDL_mutexV(handle->lock); - SDL_CondSignal(handle->cond); + slock_unlock(handle->lock); + scond_signal(handle->cond); return 0; } @@ -393,9 +394,9 @@ int ffemu_push_audio(ffemu_t *handle, const struct ffemu_audio_data *data) { for (;;) { - SDL_mutexP(handle->lock); + slock_lock(handle->lock); unsigned avail = fifo_write_avail(handle->audio_fifo); - SDL_mutexV(handle->lock); + slock_unlock(handle->lock); if (!handle->alive) return -1; @@ -403,23 +404,23 @@ int ffemu_push_audio(ffemu_t *handle, const struct ffemu_audio_data *data) if (avail >= data->frames * handle->params.channels * sizeof(int16_t)) break; - SDL_mutexP(handle->cond_lock); + slock_lock(handle->cond_lock); if (handle->can_sleep) { handle->can_sleep = false; - SDL_CondWait(handle->cond, handle->cond_lock); + scond_wait(handle->cond, handle->cond_lock); handle->can_sleep = true; } else - SDL_CondSignal(handle->cond); + scond_signal(handle->cond); - SDL_mutexV(handle->cond_lock); + slock_unlock(handle->cond_lock); } - SDL_mutexP(handle->lock); + slock_lock(handle->lock); fifo_write(handle->audio_fifo, data->data, data->frames * handle->params.channels * sizeof(int16_t)); - SDL_mutexV(handle->lock); - SDL_CondSignal(handle->cond); + slock_unlock(handle->lock); + scond_signal(handle->cond); return 0; } @@ -584,7 +585,7 @@ int ffemu_finalize(ffemu_t *handle) return 0; } -static int SDLCALL ffemu_thread(void *data) +static void ffemu_thread(void *data) { ffemu_t *ff = data; @@ -603,36 +604,36 @@ static int SDLCALL ffemu_thread(void *data) bool avail_video = false; bool avail_audio = false; - SDL_mutexP(ff->lock); + slock_lock(ff->lock); if (fifo_read_avail(ff->attr_fifo) >= sizeof(attr_buf)) avail_video = true; if (fifo_read_avail(ff->audio_fifo) >= audio_buf_size) avail_audio = true; - SDL_mutexV(ff->lock); + slock_unlock(ff->lock); if (!avail_video && !avail_audio) { - SDL_mutexP(ff->cond_lock); + slock_lock(ff->cond_lock); if (ff->can_sleep) { ff->can_sleep = false; - SDL_CondWait(ff->cond, ff->cond_lock); + scond_wait(ff->cond, ff->cond_lock); ff->can_sleep = true; } else - SDL_CondSignal(ff->cond); + scond_signal(ff->cond); - SDL_mutexV(ff->cond_lock); + slock_unlock(ff->cond_lock); } if (avail_video) { - SDL_mutexP(ff->lock); + slock_lock(ff->lock); fifo_read(ff->attr_fifo, &attr_buf, sizeof(attr_buf)); fifo_read(ff->video_fifo, video_buf, attr_buf.height * attr_buf.pitch); - SDL_mutexV(ff->lock); - SDL_CondSignal(ff->cond); + slock_unlock(ff->lock); + scond_signal(ff->cond); attr_buf.data = video_buf; ffemu_push_video_thread(ff, &attr_buf); @@ -640,10 +641,10 @@ static int SDLCALL ffemu_thread(void *data) if (avail_audio) { - SDL_mutexP(ff->lock); + slock_lock(ff->lock); fifo_read(ff->audio_fifo, audio_buf, audio_buf_size); - SDL_mutexV(ff->lock); - SDL_CondSignal(ff->cond); + slock_unlock(ff->lock); + scond_signal(ff->cond); struct ffemu_audio_data aud = { .frames = 128, @@ -656,6 +657,5 @@ static int SDLCALL ffemu_thread(void *data) av_free(video_buf); av_free(audio_buf); - - return 0; } + diff --git a/thread.c b/thread.c new file mode 100644 index 0000000000..5c17419af5 --- /dev/null +++ b/thread.c @@ -0,0 +1,187 @@ +/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes. + * Copyright (C) 2010-2011 - Hans-Kristian Arntzen + * + * Some code herein may be based on code found in BSNES. + * + * SSNES 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. + * + * SSNES 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 SSNES. + * If not, see . + */ + +#include "thread.h" +#include + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#else +#include +#include +#endif + +#ifdef _WIN32 + +struct slock +{ + CRITICAL_SECTION crit; +}; + +slock_t *slock_new(void) +{ + slock_t *lock = calloc(1, sizeof(*lock)); + if (!lock) + return NULL; + + Initiali +} + + +#else + +struct thread_data +{ + void (*func)(void*); + void *userdata; +}; + +struct sthread +{ + pthread_t id; +}; + +static void *thread_wrap(void *data_) +{ + struct thread_data *data = data_; + data->func(data->userdata); + free(data); + pthread_exit(NULL); +} + +sthread_t *sthread_create(void (*thread_func)(void*), void *userdata) +{ + sthread_t *thr = calloc(1, sizeof(*thr)); + if (!thr) + return NULL; + + struct thread_data *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 = 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 = 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); +} + +bool scond_wait_timeout(scond_t *cond, slock_t *lock, unsigned timeout_ms) +{ + struct timespec now; + clock_gettime(CLOCK_REALTIME, &now); + + now.tv_sec += timeout_ms / 1000; + now.tv_nsec += timeout_ms * 1000000L; + + now.tv_sec += now.tv_nsec / 1000000000L; + now.tv_nsec = now.tv_nsec % 1000000000L; + + int ret = pthread_cond_timedwait(&cond->cond, &lock->lock, &now); + return ret == 0; +} + +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 0000000000..d44e0a6bcc --- /dev/null +++ b/thread.h @@ -0,0 +1,52 @@ +/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes. + * Copyright (C) 2010-2011 - Hans-Kristian Arntzen + * + * Some code herein may be based on code found in BSNES. + * + * SSNES 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. + * + * SSNES 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 SSNES. + * If not, see . + */ + +#ifndef THREAD_H__ +#define THREAD_H__ + +#include + +// Implements the bare minimum needed for SSNES. :) + +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); +bool scond_wait_timeout(scond_t *cond, slock_t *lock, unsigned timeout_ms); +void scond_signal(scond_t *cond); + + +#endif +