From a855d6202536ff28e5aae4f22a0f31d8f5b325d0 Mon Sep 17 00:00:00 2001 From: Franklin Wei Date: Sat, 21 Jan 2017 15:18:31 -0500 Subject: Port of Duke Nukem 3D This ports Fabien Sanglard's Chocolate Duke to run on a version of SDL for Rockbox. Change-Id: I8f2c4c78af19de10c1633ed7bb7a997b43256dd9 --- apps/plugins/sdl/src/thread/os2/SDL_syscond.c | 215 ++++++++++++++++++++++ apps/plugins/sdl/src/thread/os2/SDL_syscond_c.h | 23 +++ apps/plugins/sdl/src/thread/os2/SDL_sysmutex.c | 108 +++++++++++ apps/plugins/sdl/src/thread/os2/SDL_syssem.c | 192 +++++++++++++++++++ apps/plugins/sdl/src/thread/os2/SDL_systhread.c | 108 +++++++++++ apps/plugins/sdl/src/thread/os2/SDL_systhread_c.h | 28 +++ 6 files changed, 674 insertions(+) create mode 100644 apps/plugins/sdl/src/thread/os2/SDL_syscond.c create mode 100644 apps/plugins/sdl/src/thread/os2/SDL_syscond_c.h create mode 100644 apps/plugins/sdl/src/thread/os2/SDL_sysmutex.c create mode 100644 apps/plugins/sdl/src/thread/os2/SDL_syssem.c create mode 100644 apps/plugins/sdl/src/thread/os2/SDL_systhread.c create mode 100644 apps/plugins/sdl/src/thread/os2/SDL_systhread_c.h (limited to 'apps/plugins/sdl/src/thread/os2') diff --git a/apps/plugins/sdl/src/thread/os2/SDL_syscond.c b/apps/plugins/sdl/src/thread/os2/SDL_syscond.c new file mode 100644 index 0000000000..3e80594c2a --- /dev/null +++ b/apps/plugins/sdl/src/thread/os2/SDL_syscond.c @@ -0,0 +1,215 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +/* An implementation of condition variables using semaphores and mutexes */ +/* + This implementation borrows heavily from the BeOS condition variable + implementation, written by Christopher Tate and Owen Smith. Thanks! + */ + +#include "SDL_thread.h" + +struct SDL_cond +{ + SDL_mutex *lock; + int waiting; + int signals; + SDL_sem *wait_sem; + SDL_sem *wait_done; +}; + +/* Create a condition variable */ +DECLSPEC SDL_cond * SDLCALL SDL_CreateCond(void) +{ + SDL_cond *cond; + + cond = (SDL_cond *) SDL_malloc(sizeof(SDL_cond)); + if ( cond ) { + cond->lock = SDL_CreateMutex(); + cond->wait_sem = SDL_CreateSemaphore(0); + cond->wait_done = SDL_CreateSemaphore(0); + cond->waiting = cond->signals = 0; + if ( ! cond->lock || ! cond->wait_sem || ! cond->wait_done ) { + SDL_DestroyCond(cond); + cond = NULL; + } + } else { + SDL_OutOfMemory(); + } + return(cond); +} + +/* Destroy a condition variable */ +DECLSPEC void SDLCALL SDL_DestroyCond(SDL_cond *cond) +{ + if ( cond ) { + if ( cond->wait_sem ) { + SDL_DestroySemaphore(cond->wait_sem); + } + if ( cond->wait_done ) { + SDL_DestroySemaphore(cond->wait_done); + } + if ( cond->lock ) { + SDL_DestroyMutex(cond->lock); + } + SDL_free(cond); + } +} + +/* Restart one of the threads that are waiting on the condition variable */ +DECLSPEC int SDLCALL SDL_CondSignal(SDL_cond *cond) +{ + if ( ! cond ) { + SDL_SetError("Passed a NULL condition variable"); + return -1; + } + + /* If there are waiting threads not already signalled, then + signal the condition and wait for the thread to respond. + */ + SDL_LockMutex(cond->lock); + if ( cond->waiting > cond->signals ) { + ++cond->signals; + SDL_SemPost(cond->wait_sem); + SDL_UnlockMutex(cond->lock); + SDL_SemWait(cond->wait_done); + } else { + SDL_UnlockMutex(cond->lock); + } + + return 0; +} + +/* Restart all threads that are waiting on the condition variable */ +DECLSPEC int SDLCALL SDL_CondBroadcast(SDL_cond *cond) +{ + if ( ! cond ) { + SDL_SetError("Passed a NULL condition variable"); + return -1; + } + + /* If there are waiting threads not already signalled, then + signal the condition and wait for the thread to respond. + */ + SDL_LockMutex(cond->lock); + if ( cond->waiting > cond->signals ) { + int i, num_waiting; + + num_waiting = (cond->waiting - cond->signals); + cond->signals = cond->waiting; + for ( i=0; iwait_sem); + } + /* Now all released threads are blocked here, waiting for us. + Collect them all (and win fabulous prizes!) :-) + */ + SDL_UnlockMutex(cond->lock); + for ( i=0; iwait_done); + } + } else { + SDL_UnlockMutex(cond->lock); + } + + return 0; +} + +/* Wait on the condition variable for at most 'ms' milliseconds. + The mutex must be locked before entering this function! + The mutex is unlocked during the wait, and locked again after the wait. + +Typical use: + +Thread A: + SDL_LockMutex(lock); + while ( ! condition ) { + SDL_CondWait(cond); + } + SDL_UnlockMutex(lock); + +Thread B: + SDL_LockMutex(lock); + ... + condition = true; + ... + SDL_UnlockMutex(lock); + */ +DECLSPEC int SDLCALL SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, Uint32 ms) +{ + int retval; + + if ( ! cond ) { + SDL_SetError("Passed a NULL condition variable"); + return -1; + } + + /* Obtain the protection mutex, and increment the number of waiters. + This allows the signal mechanism to only perform a signal if there + are waiting threads. + */ + SDL_LockMutex(cond->lock); + ++cond->waiting; + SDL_UnlockMutex(cond->lock); + + /* Unlock the mutex, as is required by condition variable semantics */ + SDL_UnlockMutex(mutex); + + /* Wait for a signal */ + if ( ms == SDL_MUTEX_MAXWAIT ) { + retval = SDL_SemWait(cond->wait_sem); + } else { + retval = SDL_SemWaitTimeout(cond->wait_sem, ms); + } + + /* Let the signaler know we have completed the wait, otherwise + the signaler can race ahead and get the condition semaphore + if we are stopped between the mutex unlock and semaphore wait, + giving a deadlock. See the following URL for details: + http://www-classic.be.com/aboutbe/benewsletter/volume_III/Issue40.html + */ + SDL_LockMutex(cond->lock); + if ( cond->signals > 0 ) { + /* If we timed out, we need to eat a condition signal */ + if ( retval > 0 ) { + SDL_SemWait(cond->wait_sem); + } + /* We always notify the signal thread that we are done */ + SDL_SemPost(cond->wait_done); + + /* Signal handshake complete */ + --cond->signals; + } + --cond->waiting; + SDL_UnlockMutex(cond->lock); + + /* Lock the mutex, as is required by condition variable semantics */ + SDL_LockMutex(mutex); + + return retval; +} + +/* Wait on the condition variable forever */ +DECLSPEC int SDLCALL SDL_CondWait(SDL_cond *cond, SDL_mutex *mutex) +{ + return SDL_CondWaitTimeout(cond, mutex, SDL_MUTEX_MAXWAIT); +} diff --git a/apps/plugins/sdl/src/thread/os2/SDL_syscond_c.h b/apps/plugins/sdl/src/thread/os2/SDL_syscond_c.h new file mode 100644 index 0000000000..1120b2d80d --- /dev/null +++ b/apps/plugins/sdl/src/thread/os2/SDL_syscond_c.h @@ -0,0 +1,23 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + diff --git a/apps/plugins/sdl/src/thread/os2/SDL_sysmutex.c b/apps/plugins/sdl/src/thread/os2/SDL_sysmutex.c new file mode 100644 index 0000000000..1e21897656 --- /dev/null +++ b/apps/plugins/sdl/src/thread/os2/SDL_sysmutex.c @@ -0,0 +1,108 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +/* Mutex functions using the OS/2 API */ + +#define INCL_DOSERRORS +#define INCL_DOSSEMAPHORES +#include + +#include "SDL_mutex.h" + + +struct SDL_mutex { + HMTX hmtxID; +}; + +/* Create a mutex */ +DECLSPEC SDL_mutex * SDLCALL SDL_CreateMutex(void) +{ + SDL_mutex *mutex; + APIRET ulrc; + + /* Allocate mutex memory */ + mutex = (SDL_mutex *)SDL_malloc(sizeof(*mutex)); + if (mutex) + { + /* Create the mutex, with initial value signaled */ + ulrc = DosCreateMutexSem(NULL, // Create unnamed semaphore + &(mutex->hmtxID), // Pointer to handle + 0L, // Flags: create it private (not shared) + FALSE); // Initial value: unowned + if (ulrc!=NO_ERROR) + { + SDL_SetError("Couldn't create mutex"); + SDL_free(mutex); + mutex = NULL; + } + } else { + SDL_OutOfMemory(); + } + return(mutex); +} + +/* Free the mutex */ +DECLSPEC void SDLCALL SDL_DestroyMutex(SDL_mutex *mutex) +{ + if ( mutex ) + { + if ( mutex->hmtxID ) + { + DosCloseMutexSem(mutex->hmtxID); + mutex->hmtxID = 0; + } + SDL_free(mutex); + } +} + +/* Lock the mutex */ +DECLSPEC int SDLCALL SDL_mutexP(SDL_mutex *mutex) +{ + if ( mutex == NULL ) + { + SDL_SetError("Passed a NULL mutex"); + return -1; + } + if ( DosRequestMutexSem(mutex->hmtxID, SEM_INDEFINITE_WAIT) != NO_ERROR ) + { + SDL_SetError("Couldn't wait on mutex"); + return -1; + } + return(0); +} + +/* Unlock the mutex */ +DECLSPEC int SDLCALL SDL_mutexV(SDL_mutex *mutex) +{ + if ( mutex == NULL ) + { + SDL_SetError("Passed a NULL mutex"); + return -1; + } + if ( DosReleaseMutexSem(mutex->hmtxID) != NO_ERROR ) + { + SDL_SetError("Couldn't release mutex"); + return -1; + } + return(0); +} diff --git a/apps/plugins/sdl/src/thread/os2/SDL_syssem.c b/apps/plugins/sdl/src/thread/os2/SDL_syssem.c new file mode 100644 index 0000000000..d6dfba67bb --- /dev/null +++ b/apps/plugins/sdl/src/thread/os2/SDL_syssem.c @@ -0,0 +1,192 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +/* Semaphore functions using the OS/2 API */ + +#define INCL_DOS +#define INCL_DOSERRORS +#define INCL_DOSSEMAPHORES +#include + +#include "SDL_thread.h" +#include "SDL_timer.h" + + +struct SDL_semaphore { + HMTX id; + HEV changed; + Uint32 value; +}; + + +/* Create a semaphore */ +DECLSPEC SDL_sem * SDLCALL SDL_CreateSemaphore(Uint32 initial_value) +{ + SDL_sem *sem; + ULONG ulrc; + + /* Allocate sem memory */ + sem = (SDL_sem *)SDL_malloc(sizeof(*sem)); + if ( sem ) { + /* Create the mutex semaphore */ + ulrc = DosCreateMutexSem(NULL,&(sem->id),0,TRUE); + if ( ulrc ) { + SDL_SetError("Couldn't create semaphore"); + SDL_free(sem); + sem = NULL; + } else + { + DosCreateEventSem(NULL, &(sem->changed), 0, FALSE); + sem->value = initial_value; + DosReleaseMutexSem(sem->id); + } + } else { + SDL_OutOfMemory(); + } + return(sem); +} + +/* Free the semaphore */ +DECLSPEC void SDLCALL SDL_DestroySemaphore(SDL_sem *sem) +{ + if ( sem ) { + if ( sem->id ) { + DosCloseEventSem(sem->changed); + DosCloseMutexSem(sem->id); + sem->id = 0; + } + SDL_free(sem); + } +} + +DECLSPEC int SDLCALL SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout) +{ + ULONG ulrc; + + if ( ! sem ) { + SDL_SetError("Passed a NULL sem"); + return -1; + } + + if ( timeout == SDL_MUTEX_MAXWAIT ) { + while (1) { + ulrc = DosRequestMutexSem(sem->id, SEM_INDEFINITE_WAIT); + if (ulrc) { + /* if error waiting mutex */ + SDL_SetError("DosRequestMutexSem() failed"); + return -1; + } else if (sem->value) { + sem->value--; + DosReleaseMutexSem(sem->id); + return 0; + } else { + ULONG ulPostCount; + DosResetEventSem(sem->changed, &ulPostCount); + DosReleaseMutexSem(sem->id); + /* continue waiting until somebody posts the semaphore */ + DosWaitEventSem(sem->changed, SEM_INDEFINITE_WAIT); + } + } + } else + if ( timeout == 0 ) + { + ulrc = DosRequestMutexSem(sem->id, SEM_INDEFINITE_WAIT); + if (ulrc==NO_ERROR) + { + if (sem->value) + { + sem->value--; + DosReleaseMutexSem(sem->id); + return 0; + } else + { + DosReleaseMutexSem(sem->id); + return SDL_MUTEX_TIMEDOUT; + } + } else + { + SDL_SetError("DosRequestMutexSem() failed"); + return -1; + } + } else { + ulrc = DosRequestMutexSem(sem->id, SEM_INDEFINITE_WAIT); + if (ulrc) { + /* if error waiting mutex */ + SDL_SetError("DosRequestMutexSem() failed"); + return -1; + } else + if (sem->value) { + sem->value--; + DosReleaseMutexSem(sem->id); + return 0; + } else { + ULONG ulPostCount; + DosResetEventSem(sem->changed, &ulPostCount); + DosReleaseMutexSem(sem->id); + /* continue waiting until somebody posts the semaphore */ + ulrc = DosWaitEventSem(sem->changed, timeout); + if (ulrc==NO_ERROR) + return 0; + else + return SDL_MUTEX_TIMEDOUT; + } + } + /* never reached */ + return -1; +} + +DECLSPEC int SDLCALL SDL_SemTryWait(SDL_sem *sem) +{ + return SDL_SemWaitTimeout(sem, 0); +} + +DECLSPEC int SDLCALL SDL_SemWait(SDL_sem *sem) +{ + return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT); +} + +/* Returns the current count of the semaphore */ +DECLSPEC Uint32 SDLCALL SDL_SemValue(SDL_sem *sem) +{ + if ( ! sem ) { + SDL_SetError("Passed a NULL sem"); + return 0; + } + return sem->value; +} + +DECLSPEC int SDLCALL SDL_SemPost(SDL_sem *sem) +{ + if ( ! sem ) { + SDL_SetError("Passed a NULL sem"); + return -1; + } + if ( DosRequestMutexSem(sem->id,SEM_INDEFINITE_WAIT) ) { + SDL_SetError("DosRequestMutexSem() failed"); + return -1; + } + sem->value++; + DosPostEventSem(sem->changed); + DosReleaseMutexSem(sem->id); + return 0; +} diff --git a/apps/plugins/sdl/src/thread/os2/SDL_systhread.c b/apps/plugins/sdl/src/thread/os2/SDL_systhread.c new file mode 100644 index 0000000000..33f815a5fb --- /dev/null +++ b/apps/plugins/sdl/src/thread/os2/SDL_systhread.c @@ -0,0 +1,108 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +/* OS/2 thread management routines for SDL */ + +#include +#define INCL_DOSERRORS +#define INCL_DOSPROCESS +#include + +#include "SDL_thread.h" +#include "../SDL_systhread.h" +#include "../SDL_thread_c.h" + +typedef struct ThreadStartParms +{ + void *args; + pfnSDL_CurrentEndThread pfnCurrentEndThread; +} tThreadStartParms, *pThreadStartParms; + +static void threadfunc(void *pparm) +{ + pThreadStartParms pThreadParms = pparm; + pfnSDL_CurrentEndThread pfnCurrentEndThread = NULL; + + // Call the thread function! + SDL_RunThread(pThreadParms->args); + + // Get the current endthread we have to use! + if (pThreadParms) + { + pfnCurrentEndThread = pThreadParms->pfnCurrentEndThread; + SDL_free(pThreadParms); + } + // Call endthread! + if (pfnCurrentEndThread) + (*pfnCurrentEndThread)(); +} + +int SDL_SYS_CreateThread(SDL_Thread *thread, void *args, pfnSDL_CurrentBeginThread pfnBeginThread, pfnSDL_CurrentEndThread pfnEndThread) +{ + pThreadStartParms pThreadParms = SDL_malloc(sizeof(tThreadStartParms)); + if (!pThreadParms) + { + SDL_SetError("Not enough memory to create thread"); + return(-1); + } + + // Save the function which we will have to call to clear the RTL of calling app! + pThreadParms->pfnCurrentEndThread = pfnEndThread; + // Also save the real parameters we have to pass to thread function + pThreadParms->args = args; + // Start the thread using the runtime library of calling app! + thread->threadid = thread->handle = (*pfnBeginThread)(threadfunc, NULL, 512*1024, pThreadParms); + if ((int)thread->threadid <= 0) + { + SDL_SetError("Not enough resources to create thread"); + return(-1); + } + return(0); +} + +void SDL_SYS_SetupThread(void) +{ + return; +} + +DECLSPEC Uint32 SDLCALL SDL_ThreadID(void) +{ + PTIB tib; + DosGetInfoBlocks(&tib, NULL); + return((Uint32) (tib->tib_ptib2->tib2_ultid)); +} + +void SDL_SYS_WaitThread(SDL_Thread *thread) +{ + TID tid = thread->handle; + DosWaitThread(&tid, DCWW_WAIT); +} + +/* WARNING: This function is really a last resort. + * Threads should be signaled and then exit by themselves. + * TerminateThread() doesn't perform stack and DLL cleanup. + */ +void SDL_SYS_KillThread(SDL_Thread *thread) +{ + DosKillThread(thread->handle); +} diff --git a/apps/plugins/sdl/src/thread/os2/SDL_systhread_c.h b/apps/plugins/sdl/src/thread/os2/SDL_systhread_c.h new file mode 100644 index 0000000000..3b94dfed53 --- /dev/null +++ b/apps/plugins/sdl/src/thread/os2/SDL_systhread_c.h @@ -0,0 +1,28 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#define INCL_DOSPROCESS +#include + +typedef TID SYS_ThreadHandle; + -- cgit v1.2.3