OS/2 port!

This was mostly, if not entirely, written by "Doodle" and "Caetano":
    doodle@scenergy.dfmk.hu
    daniel@caetano.eng.br

--ryan.

--HG--
extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/trunk%401193
This commit is contained in:
Ryan C. Gordon 2005-11-23 07:29:56 +00:00
parent c154edb92f
commit b08452cb40
49 changed files with 6571 additions and 8 deletions

36
src/thread/Makefile.wat Normal file
View file

@ -0,0 +1,36 @@
#=============================================================================
# This is a Watcom makefile to build SDL.DLL for OS/2
#
# Makefile for threading
#=============================================================================
object_files=SDL_thread.obj SDL_sysmutex.obj SDL_syssem.obj SDL_systhread.obj SDL_syscond.obj
ExtraCFlags=
#
#==============================================================================
#
!include ..\..\Watcom.mif
.before
set include=$(%os2tk)\h;$(%include);../../include;./os2;../;
all : $(object_files)
SDL_sysmutex.obj: .AUTODEPEND
wcc386 os2\SDL_sysmutex.c $(cflags)
SDL_syssem.obj: .AUTODEPEND
wcc386 os2\SDL_syssem.c $(cflags)
SDL_systhread.obj: .AUTODEPEND
wcc386 os2\SDL_systhread.c $(cflags)
SDL_syscond.obj: .AUTODEPEND
wcc386 os2\SDL_syscond.c $(cflags)
clean : .SYMBOLIC
@if exist *.obj del *.obj
@if exist *.map del *.map
@if exist *.res del *.res
@if exist *.lst del *.lst

View file

@ -33,7 +33,11 @@ static char rcsid =
saves a system-dependent thread id in thread->id, and returns 0
on success.
*/
#ifdef __OS2__
extern int SDL_SYS_CreateThread(SDL_Thread *thread, void *args, pfnSDL_CurrentBeginThread pfnBeginThread, pfnSDL_CurrentEndThread pfnEndThread);
#else
extern int SDL_SYS_CreateThread(SDL_Thread *thread, void *args);
#endif
/* This function does any necessary setup in the child thread */
extern void SDL_SYS_SetupThread(void);

View file

@ -218,7 +218,11 @@ void SDL_RunThread(void *data)
*statusloc = userfunc(userdata);
}
SDL_Thread *SDL_CreateThread(int (*fn)(void *), void *data)
#ifdef __OS2__
DECLSPEC SDL_Thread * SDLCALL SDL_CreateThread_Core(int (*fn)(void *), void *data, pfnSDL_CurrentBeginThread pfnBeginThread, pfnSDL_CurrentEndThread pfnEndThread)
#else
DECLSPEC SDL_Thread * SDLCALL SDL_CreateThread(int (*fn)(void *), void *data)
#endif
{
SDL_Thread *thread;
thread_args *args;
@ -254,7 +258,11 @@ SDL_Thread *SDL_CreateThread(int (*fn)(void *), void *data)
SDL_AddThread(thread);
/* Create the thread and go! */
#ifdef __OS2__
ret = SDL_SYS_CreateThread(thread, args, pfnBeginThread, pfnEndThread);
#else
ret = SDL_SYS_CreateThread(thread, args);
#endif
if ( ret >= 0 ) {
/* Wait for the thread function to use arguments */
SDL_SemWait(args->wait);

View file

@ -0,0 +1,223 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 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
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id$";
#endif
/* 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 <stdio.h>
#include <stdlib.h>
#include "SDL_error.h"
#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 *) 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);
}
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; i<num_waiting; ++i ) {
SDL_SemPost(cond->wait_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; i<num_waiting; ++i ) {
SDL_SemWait(cond->wait_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);
}

View file

@ -0,0 +1,27 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 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
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id$";
#endif

View file

@ -0,0 +1,115 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 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
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id$";
#endif
/* Mutex functions using the OS/2 API */
#include <stdio.h>
#include <stdlib.h>
#define INCL_DOSERRORS
#define INCL_DOSSEMAPHORES
#include <os2.h>
#include "SDL_error.h"
#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 *)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");
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;
}
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);
}

199
src/thread/os2/SDL_syssem.c Normal file
View file

@ -0,0 +1,199 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 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
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id$";
#endif
/* Semaphore functions using the OS/2 API */
#include <stdio.h>
#include <stdlib.h>
#define INCL_DOS
#define INCL_DOSERRORS
#define INCL_DOSSEMAPHORES
#include <os2.h>
#include "SDL_error.h"
#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 *)malloc(sizeof(*sem));
if ( sem ) {
/* Create the mutex semaphore */
ulrc = DosCreateMutexSem(NULL,&(sem->id),0,TRUE);
if ( ulrc ) {
SDL_SetError("Couldn't create semaphore");
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;
}
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;
}

View file

@ -0,0 +1,114 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 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
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id$";
#endif
/* OS/2 thread management routines for SDL */
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#define INCL_DOSERRORS
#define INCL_DOSPROCESS
#include <os2.h>
#include "SDL_error.h"
#include "SDL_thread.h"
#include "SDL_systhread.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;
free(pThreadParms);
}
// Call endthread!
if (pfnCurrentEndThread)
(*pfnCurrentEndThread)();
}
int SDL_SYS_CreateThread(SDL_Thread *thread, void *args, pfnSDL_CurrentBeginThread pfnBeginThread, pfnSDL_CurrentEndThread pfnEndThread)
{
pThreadStartParms pThreadParms = 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, 512*1024, pThreadParms);
if (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);
}

View file

@ -0,0 +1,27 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 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
*/
#define INCL_DOSPROCESS
#include <os2.h>
typedef TID SYS_ThreadHandle;