Threadlib refactoring, phase 2.

This is a near-total reorganization.  Full details will appear in
doc/devel/threads when that document is completed.


git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@1257 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
mcmartin
2003-09-23 16:33:50 +00:00
parent c14c2b010d
commit e94b959c9d
27 changed files with 309 additions and 290 deletions
+1
View File
@@ -1,4 +1,5 @@
Changes towards version 0.4:
- Major refactoring of threadlib; see doc/devel/threads -Michael
- Downgraded the GraphicsLock to an ordinary Mutex -Michael
- Added movie player; only movies defined are intro and ending;
only .duk decoder present (.duk audio decoder mostly derived
+33
View File
@@ -0,0 +1,33 @@
The UQM Threading and Synchronization library
This document is woefully incomplete at the moment. It will be filled
in later. It's just that the ChangeLog refers to it so I want the
file to be here. --Michael
#defines
NAMED_SYNCHRO: When #defined, all synchronization objects are named.
This should be kept on all the time, at least until 1.0.
TRACK_CONTENTION: implies NAMED_SYNCHRO. Spits out status messages
whenever a thread goes to sleep because of an object matching
TRACK_CONTENTION_CLASSES.
TRACK_CONTENTION_CLASSES: This is an ORring of enums defined in
threadlib.h.
Constructs
- Task
- Thread
- ThreadLocal
- Mutex
- Semaphore
- CondVar
- RecursiveMutex
-4
View File
@@ -783,10 +783,6 @@ SOURCE=..\sc2code\libs\threads\thrcommon.c
SOURCE=..\sc2code\libs\threads\thrcommon.h
# End Source File
# Begin Source File
SOURCE=..\sc2code\libs\threads\condbank.c
# End Source File
# End Group
# Begin Group "time"
+1 -1
View File
@@ -177,7 +177,7 @@ InitGameClock (void)
{
if (!InitQueue (&GLOBAL (GameClock.event_q), NUM_EVENTS, sizeof (EVENT)))
return (FALSE);
clock_mutex = CreateMutex ();
clock_mutex = CreateMutex ("Clock Mutex", SYNC_CLASS_TOPLEVEL);
GLOBAL (GameClock.month_index) = 2;
GLOBAL (GameClock.day_index) = 17;
GLOBAL (GameClock.year_index) = START_YEAR; /* Feb 17, START_YEAR */
+2 -2
View File
@@ -488,7 +488,7 @@ init_xform_control (void)
{
XFormControl.XFormCurrent = XFormControl.XFormInsertPoint = 0;
XFormControl.XFormsPending = FALSE;
XFormControl.XFormLock = CreateMutex ();
XFormControl.XFormLock = CreateMutex ("Transform Lock", SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO);
}
void
@@ -521,7 +521,7 @@ init_communication (void)
{
TFB_Canvas canvas;
subtitle_mutex = CreateMutex ();
subtitle_mutex = CreateMutex ("Subtitle Lock", SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO);
init_xform_control ();
canvas = TFB_DrawCanvas_New_TrueColor (SIS_SCREEN_WIDTH,
+1 -1
View File
@@ -272,7 +272,7 @@ InitGlobData (void)
// but it is always cleared before set, so it toggled between
// 2 and 1, which doesn't actually do anything.
GLOBAL (GameClock.clock_sem) = CreateSemaphore(0, "Clock");
GLOBAL (GameClock.clock_sem) = CreateSemaphore(0, "Clock", SYNC_CLASS_TOPLEVEL);
}
int
+1 -1
View File
@@ -109,7 +109,7 @@ typedef struct tfb_dc_delimg
typedef struct tfb_dc_signal
{
DWORD thread;
Semaphore sem;
} TFB_DrawCommand_SendSignal;
typedef struct tfb_drawcommand
+1 -4
View File
@@ -130,7 +130,7 @@ Init_DrawCommandQueue (void)
DrawCommandQueue.FullSize = 0;
DrawCommandQueue.Size = 0;
DCQ_Mutex = CreateRecursiveMutex ("DCQ");
DCQ_Mutex = CreateRecursiveMutex ("DCQ", SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO);
}
void
@@ -200,9 +200,6 @@ TFB_EnqueueDrawCommand (TFB_DrawCommand* DrawCommand)
return;
}
if (DrawCommand->Type == TFB_DRAWCOMMANDTYPE_SENDSIGNAL)
DrawCommand->data.sendsignal.thread = CurrentThreadID ();
if (DrawCommand->Type <= TFB_DRAWCOMMANDTYPE_COPYTOIMAGE
&& TYPE_GET (_CurFramePtr->TypeIndexAndFlags) == SCREEN_DRAWABLE)
{
@@ -669,7 +669,7 @@ TFB_FlushGraphics () // Only call from main thread!!
break;
}
case TFB_DRAWCOMMANDTYPE_SENDSIGNAL:
SignalThread (DC.data.sendsignal.thread);
ClearSemaphore (DC.data.sendsignal.sem);
break;
}
}
+5 -4
View File
@@ -197,14 +197,15 @@ void
TFB_DrawScreen_WaitForSignal (void)
{
TFB_DrawCommand DrawCommand;
int channel;
Semaphore s;
s = GetMyThreadLocal ()->flushSem;
DrawCommand.Type = TFB_DRAWCOMMANDTYPE_SENDSIGNAL;
DrawCommand.data.sendsignal.sem = s;
Lock_DCQ (1);
channel = FindSignalChannel ();
TFB_BatchReset ();
TFB_EnqueueDrawCommand(&DrawCommand);
Unlock_DCQ();
WaitForSignal (channel);
SetSemaphore (s);
}
void
@@ -247,7 +248,7 @@ TFB_Image *
TFB_DrawImage_New (TFB_Canvas canvas)
{
TFB_Image *img = HMalloc (sizeof (TFB_Image));
img->mutex = CreateMutex ();
img->mutex = CreateMutex ("image lock", SYNC_CLASS_VIDEO);
img->ScaledImg = NULL;
img->MipmapImg = NULL;
img->colormap_index = -1;
+1 -1
View File
@@ -382,7 +382,7 @@ mem_init (void)
{
int i;
_MemoryLock = CreateMutex ();
_MemoryLock = CreateMutex ("memory lock", SYNC_CLASS_RESOURCE);
LockMutex (_MemoryLock);
freeListHead = &extents[0];
+3 -3
View File
@@ -209,9 +209,9 @@ mixSDL_OpenAudio (uint32 frequency, uint32 format, uint32 samples_buf,
mixer_datasize = samples_buf * mixer_spec.channels * 2;
mixer_data = (sint32 *) HMalloc (sizeof (uint32) * mixer_datasize);
src_mutex = CreateRecursiveMutex("mixSDL_SourceMutex");
buf_mutex = CreateRecursiveMutex("mixSDL_BufferMutex");
act_mutex = CreateRecursiveMutex("mixSDL_ActiveMutex");
src_mutex = CreateRecursiveMutex("mixSDL_SourceMutex", SYNC_CLASS_AUDIO);
buf_mutex = CreateRecursiveMutex("mixSDL_BufferMutex", SYNC_CLASS_AUDIO);
act_mutex = CreateRecursiveMutex("mixSDL_ActiveMutex", SYNC_CLASS_AUDIO);
audio_opened = 1;
mixer_driver->PauseAudio (0);
@@ -129,7 +129,7 @@ TFB_mixSDL_InitSound (int driver, int flags)
soundSource[i].sample = NULL;
soundSource[i].stream_should_be_playing = FALSE;
soundSource[i].stream_mutex = CreateMutex ();
soundSource[i].stream_mutex = CreateMutex ("MixSDL stream mutex", SYNC_CLASS_AUDIO);
soundSource[i].sbuffer = NULL;
soundSource[i].sbuf_start = 0;
soundSource[i].sbuf_size = 0;
@@ -241,7 +241,7 @@ TFB_NoSound_InitSound (int driver, int flags)
soundSource[i].sample = NULL;
soundSource[i].stream_should_be_playing = FALSE;
soundSource[i].stream_mutex = CreateMutex ();
soundSource[i].stream_mutex = CreateMutex ("MixSDL stream mutex", SYNC_CLASS_AUDIO);
soundSource[i].sbuffer = NULL;
soundSource[i].sbuf_start = 0;
soundSource[i].sbuf_size = 0;
@@ -89,7 +89,7 @@ TFB_alInitSound (int driver, int flags)
soundSource[i].sample = NULL;
soundSource[i].stream_should_be_playing = FALSE;
soundSource[i].stream_mutex = CreateMutex ();
soundSource[i].stream_mutex = CreateMutex ("OpenAL stream mutex", SYNC_CLASS_AUDIO);
soundSource[i].sbuffer = NULL;
soundSource[i].sbuf_start = 0;
soundSource[i].sbuf_size = 0;
+1 -1
View File
@@ -583,7 +583,7 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, TFB_Tra
TFB_SoundDecoder *decoder;
TFB_SoundChainData* scd;
track_mutex = CreateMutex();
track_mutex = CreateMutex("trackplayer mutex", SYNC_CLASS_TOPLEVEL | SYNC_CLASS_AUDIO);
sound_sample = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample));
scd = (TFB_SoundChainData *) HCalloc (sizeof (TFB_SoundChainData));
sound_sample->data = scd;
+1 -1
View File
@@ -121,7 +121,7 @@ InitTaskSystem (void)
int i;
for (i = 0; i < TASK_MAX; ++i)
{
task_array[i].state_mutex = CreateMutex ();
task_array[i].state_mutex = CreateMutex ("task manager lock", SYNC_CLASS_TOPLEVEL | SYNC_CLASS_RESOURCE);
}
atexit (CleanupTaskSystem);
}
+40 -47
View File
@@ -25,6 +25,7 @@
#define NAMED_SYNCHRO /* Should synchronizable objects have names? */
// #define TRACK_CONTENTION /* Should we report when a thread sleeps on synchronize? */
/* TRACK_CONTENTION implies NAMED_SYNCHRO. */
#ifdef TRACK_CONTENTION
# ifndef NAMED_SYNCHRO
# define NAMED_SYNCHRO
@@ -38,12 +39,6 @@
#endif /* DEBUG */
#ifdef DEBUG_THREADS
# ifndef THREAD_QUEUE
# define THREAD_QUEUE
# endif
# ifndef THREAD_NAMES
# define THREAD_NAMES
# endif
# ifndef PROFILE_THREADS
# define PROFILE_THREADS
# endif
@@ -56,25 +51,8 @@
#define THREAD_NAMES
#endif
#if defined (PROFILE_THREADS)
# if !defined (THREAD_QUEUE)
# define THREAD_QUEUE
# endif
#endif
#if defined (DEBUG_TRACK_SEM)
# if !defined (THREAD_QUEUE)
# define THREAD_QUEUE
# endif
# if !defined (THREAD_NAMES)
# define THREAD_NAMES
# endif
#endif
void InitThreadSystem (void);
void UnInitThreadSystem (void);
void init_cond_bank (void);
void uninit_cond_bank (void);
typedef int (*ThreadFunction) (void *);
@@ -84,27 +62,45 @@ typedef void *Semaphore;
typedef void *RecursiveMutex;
typedef void *CondVar;
/* Local data associated with each thread */
typedef struct _threadLocal {
Semaphore flushSem;
} ThreadLocal;
/* The classes of synchronization objects */
enum
{
SYNC_CLASS_TOPLEVEL = (1 << 0), /* Exposed to the game logic */
SYNC_CLASS_AUDIO = (1 << 1), /* Involves the audio system */
SYNC_CLASS_VIDEO = (1 << 2), /* Involves the video system. Very noisy because of FlushGraphics(). */
SYNC_CLASS_RESOURCE = (1 << 3) /* Involves system resources (_MemoryLock) */
};
#ifdef NAMED_SYNCHRO
/* Logical OR of all classes we want to track. */
#define TRACK_CONTENTION_CLASSES (SYNC_CLASS_TOPLEVEL)
/* Prototypes with the "name" field */
Thread CreateThread_Core (ThreadFunction func, void *data, SDWORD stackSize, const char *name);
Semaphore CreateSemaphore_Core (DWORD initial, const char *name);
Mutex CreateMutex_Core (void);
RecursiveMutex CreateRecursiveMutex_Core (const char *name);
CondVar CreateCondVar_Core (const char *name);
Semaphore CreateSemaphore_Core (DWORD initial, const char *name, DWORD syncClass);
Mutex CreateMutex_Core (const char *name, DWORD syncClass);
RecursiveMutex CreateRecursiveMutex_Core (const char *name, DWORD syncClass);
CondVar CreateCondVar_Core (const char *name, DWORD syncClass);
/* Preprocessor directives to forward to the appropriate routines */
#define CreateThread(func, data, stackSize, name) \
CreateThread_Core ((func), (data), (stackSize), (name))
#define CreateSemaphore(initial, name) \
CreateSemaphore_Core ((initial), (name))
#define CreateMutex() \
CreateMutex_Core ()
#define CreateRecursiveMutex(name) \
CreateRecursiveMutex_Core((name))
#define CreateCondVar(name) \
CreateCondVar_Core ((name))
#define CreateSemaphore(initial, name, syncClass) \
CreateSemaphore_Core ((initial), (name), (syncClass))
#define CreateMutex(name, syncClass) \
CreateMutex_Core ((name), (syncClass))
#define CreateRecursiveMutex(name, syncClass) \
CreateRecursiveMutex_Core((name), (syncClass))
#define CreateCondVar(name, syncClass) \
CreateCondVar_Core ((name), (syncClass))
#else
@@ -119,19 +115,23 @@ CondVar CreateCondVar_Core (void);
/* Preprocessor directives to forward to the appropriate routines.
The "name" field is stripped away in preprocessing. */
#define CreateThread(func, data, stackSize, name) \
#define CreateThread(func, data, stackSize, name, syncClass) \
CreateThread_Core ((func), (data), (stackSize))
#define CreateSemaphore(initial, name) \
#define CreateSemaphore(initial, name, syncClass) \
CreateSemaphore_Core ((initial))
#define CreateMutex() \
#define CreateMutex(name, syncClass) \
CreateMutex_Core ()
#define CreateRecursiveMutex(name) \
#define CreateRecursiveMutex(name, syncClass) \
CreateRecursiveMutex_Core()
#define CreateCondVar(name) \
#define CreateCondVar(name, syncClass) \
CreateCondVar_Core ()
#endif
ThreadLocal *CreateThreadLocal (void);
void DestroyThreadLocal (ThreadLocal *tl);
ThreadLocal *GetMyThreadLocal (void);
void SleepThread (TimePeriod timePeriod);
void SleepThreadUntil (TimeCount wakeTime);
void TaskSwitch (void);
@@ -157,15 +157,8 @@ int GetRecursiveMutexDepth (RecursiveMutex m);
void DestroyCondVar (CondVar);
void WaitCondVar (CondVar);
void WaitProtectedCondVar (CondVar, Mutex);
void SignalCondVar (CondVar);
void BroadcastCondVar (CondVar);
DWORD CurrentThreadID (void);
int FindSignalChannel ();
void WaitForSignal (int);
void SignalThread (DWORD);
#endif /* _THREADLIB_H */
+1 -1
View File
@@ -1,2 +1,2 @@
uqm_SUBDIRS="sdl"
uqm_CFILES="condbank.c thrcommon.c"
uqm_CFILES="thrcommon.c"
-130
View File
@@ -1,130 +0,0 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program 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 Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* This defines the Condition Variable Bank. Individual threads may
sleep until they are signaled by their Thread ID. If the Condition
Variable Bank is exhausted (unlikely!) it will wait on the DCQ's
condition variable. This may produce stuttering. */
#include <stdio.h>
#include "starcon.h"
#include "libs/threadlib.h"
/* The Condition Variable Bank. */
#define CONDVAR_BANK_SIZE 10
static Mutex bank_mutex;
static struct {
CondVar var;
DWORD id;
int used;
Mutex control;
} bank[CONDVAR_BANK_SIZE];
void
init_cond_bank ()
{
int i;
bank_mutex = CreateMutex ();
for (i = 0; i < CONDVAR_BANK_SIZE; i++)
{
bank[i].var = CreateCondVar ("FlushGraphics Bank");
bank[i].id = bank[i].used = 0;
bank[i].control = CreateMutex ();
}
}
void
uninit_cond_bank ()
{
int i;
for (i = 0; i < CONDVAR_BANK_SIZE; i++)
{
DestroyCondVar (bank[i].var);
DestroyMutex (bank[i].control);
}
DestroyMutex (bank_mutex);
}
int
FindSignalChannel ()
{
int i;
LockMutex (bank_mutex);
for (i = 0; i < CONDVAR_BANK_SIZE; i++)
{
if (!bank[i].used)
{
LockMutex (bank[i].control);
return i;
}
}
return -1;
}
void
WaitForSignal (int i)
{
DWORD me = CurrentThreadID ();
if (i == -1)
{
/* The bank is full! */
fprintf(stderr, "Condvar bank is full, %lu is waiting on DCQ.\n", me);
UnlockMutex (bank_mutex);
WaitCondVar (RenderingCond);
}
else
{
bank[i].used = 1;
bank[i].id = me;
UnlockMutex (bank_mutex);
// fprintf (stderr, "Thread %lu waiting on cond var %d (control: %p)\n", me, i, bank[i].control);
WaitProtectedCondVar (bank[i].var, bank[i].control);
// fprintf (stderr, "Thread %lu signaled via cond var %d\n", me, i);
UnlockMutex (bank[i].control);
LockMutex (bank_mutex);
bank[i].used = bank[i].id = 0;
UnlockMutex (bank_mutex);
}
}
void
SignalThread (DWORD id)
{
int i;
LockMutex (bank_mutex);
for (i = 0; i < CONDVAR_BANK_SIZE; i++)
{
if (bank[i].used && bank[i].id == id)
{
UnlockMutex (bank_mutex);
// fprintf (stderr, "Blocking on var %d's control: %p\n", i, bank[i].control);
LockMutex (bank[i].control);
// fprintf (stderr, "Signaling var %d, thread %lu, control %p\n", i, id, bank[i].control);
SignalCondVar (bank[i].var);
UnlockMutex (bank[i].control);
return;
}
}
fprintf (stderr, "Warning: Couldn't find thread to signal!\n");
UnlockMutex (bank_mutex);
}
+155 -30
View File
@@ -38,6 +38,7 @@ typedef struct _thread {
#ifdef PROFILE_THREADS
int startTime;
#endif /* PROFILE_THREADS */
ThreadLocal *localData;
struct _thread *next;
} *TrueThread;
@@ -117,13 +118,11 @@ InitThreadSystem_SDL (void)
#ifdef PROFILE_THREADS
signal(SIGUSR1, SigUSR1Handler);
#endif
init_cond_bank ();
}
void
UnInitThreadSystem_SDL (void)
{
uninit_cond_bank ();
#ifdef PROFILE_THREADS
signal(SIGUSR1, SIG_DFL);
#endif
@@ -220,7 +219,7 @@ ThreadHelper (void *startInfo) {
#endif
UnQueueThread (thread);
DestroyThreadLocal (thread->localData);
HFree (thread);
return result;
}
@@ -243,6 +242,8 @@ CreateThread_SDL (ThreadFunction func, void *data, SDWORD stackSize
thread->startTime = GetTimeCounter ();
#endif
thread->localData = CreateThreadLocal ();
startInfo = (struct ThreadStartInfo *) HMalloc (sizeof (*startInfo));
startInfo->func = func;
startInfo->data = data;
@@ -252,6 +253,7 @@ CreateThread_SDL (ThreadFunction func, void *data, SDWORD stackSize
thread->native = SDL_CreateThread (ThreadHelper, (void *) startInfo);
if (!(thread->native))
{
DestroyThreadLocal (thread->localData);
HFree (startInfo);
HFree (thread);
return NULL;
@@ -301,13 +303,112 @@ WaitThread_SDL (Thread thread, int *status) {
SDL_WaitThread (((TrueThread)thread)->native, status);
}
ThreadLocal *
GetMyThreadLocal_SDL (void)
{
TrueThread t = FindThreadInfo (SDL_ThreadID ());
return t ? t->localData : NULL;
}
/* These are the SDL implementations of the UQM synchronization objects. */
/* TODO: Remove the names of the following data types when compiling
* under release mode. */
/* Mutexes. */
/* TODO. The w_memlib uses Mutexes right now, so we can't use HMalloc
* or HFree. */
* or HFree. Once that goes, this needs to change. */
typedef struct _mutex {
SDL_mutex *mutex;
#ifdef TRACK_CONTENTION
Uint32 owner;
#endif
#ifdef NAMED_SYNCHRO
const char *name;
DWORD syncClass;
#endif
} Mut;
Mutex
#ifdef NAMED_SYNCHRO
CreateMutex_SDL (const char *name, DWORD syncClass)
#else
CreateMutex_SDL (void)
#endif
{
Mut *mutex = malloc (sizeof (Mut));
if (mutex != NULL)
{
mutex->mutex = SDL_CreateMutex();
#ifdef TRACK_CONTENTION
mutex->owner = 0;
#endif
#ifdef NAMED_SYNCHRO
mutex->name = name;
mutex->syncClass = syncClass;
#endif
}
if ((mutex == NULL) || (mutex->mutex == NULL))
{
#ifdef NAMED_SYNCHRO
fprintf (stderr, "Could not initialize mutex '%s': aborting.\n", name);
#else
fprintf (stderr, "Could not initialize mutex: aborting.\n");
#endif
abort ();
}
return mutex;
}
void
DestroyMutex_SDL (Mutex m)
{
Mut *mutex = (Mut *)m;
SDL_DestroyMutex (mutex->mutex);
free (mutex);
}
void
LockMutex_SDL (Mutex m)
{
Mut *mutex = (Mut *)m;
#ifdef TRACK_CONTENTION
/* This code isn't really quite right; race conditions between
* check and lock remain and can produce reports of contention
* where the thread never sleeps, or fail to report in
* situations where it does. If tracking with perfect
* accuracy becomes important, the TRACK_CONTENTION mutex will
* need to handle its own wake/sleep cycles with condition
* variables (check the history of this file for the
* CrossThreadMutex code). This almost-measure is being added
* because for the most part it should suffice. */
if (mutex->owner && (mutex->syncClass & TRACK_CONTENTION_CLASSES))
{
fprintf (stderr, "Thread '%s' blocking on mutex '%s'\n", MyThreadName (), mutex->name);
}
#endif
while (SDL_mutexP (mutex->mutex) != 0)
{
TaskSwitch_SDL ();
}
#ifdef TRACK_CONTENTION
mutex->owner = SDL_ThreadID ();
#endif
}
void
UnlockMutex_SDL (Mutex m)
{
Mut *mutex = (Mut *)m;
#ifdef TRACK_CONTENTION
mutex->owner = 0;
#endif
while (SDL_mutexV (mutex->mutex) != 0)
{
TaskSwitch_SDL ();
}
}
/* Semaphores. */
@@ -315,21 +416,32 @@ typedef struct _sem {
SDL_sem *sem;
#ifdef NAMED_SYNCHRO
const char *name;
DWORD syncClass;
#endif
} Sem;
Semaphore
CreateSemaphore_SDL (DWORD initial
#ifdef NAMED_SYNCHRO
, const char *name
, const char *name, DWORD syncClass
#endif
)
{
Sem *sem = (Sem *) HMalloc (sizeof (struct _sem));
#ifdef NAMED_SYNCHRO
sem->name = name;
sem->syncClass = syncClass;
#endif
sem->sem = SDL_CreateSemaphore (initial);
if (sem->sem == NULL)
{
#ifdef NAMED_SYNCHRO
fprintf (stderr, "Could not initialize semaphore '%s': aborting.\n", name);
#else
fprintf (stderr, "Could not initialize semaphore: aborting.\n");
#endif
abort ();
}
return sem;
}
@@ -347,9 +459,9 @@ SetSemaphore_SDL (Semaphore s)
Sem *sem = (Sem *)s;
#ifdef TRACK_CONTENTION
BOOLEAN contention = !(SDL_SemValue (sem->sem));
if (contention)
if (contention && (sem->syncClass & TRACK_CONTENTION_CLASSES))
{
fprintf (stderr, "Thread '%s' goes to sleep, waiting on semaphore '%s'\n", MyThreadName (), sem->name);
fprintf (stderr, "Thread '%s' blocking on semaphore '%s'\n", MyThreadName (), sem->name);
}
#endif
while (SDL_SemWait (sem->sem) == -1)
@@ -357,7 +469,7 @@ SetSemaphore_SDL (Semaphore s)
TaskSwitch_SDL ();
}
#ifdef TRACK_CONTENTION
if (contention)
if (contention && (sem->syncClass & TRACK_CONTENTION_CLASSES))
{
fprintf (stderr, "Thread '%s' awakens, released from semaphore '%s'\n", MyThreadName (), sem->name);
}
@@ -383,12 +495,13 @@ typedef struct _recm {
Uint32 locks;
#ifdef NAMED_SYNCHRO
const char *name;
DWORD syncClass;
#endif
} RecM;
RecursiveMutex
#ifdef NAMED_SYNCHRO
CreateRecursiveMutex_SDL (const char *name)
CreateRecursiveMutex_SDL (const char *name, DWORD syncClass)
#else
CreateRecursiveMutex_SDL (void)
#endif
@@ -397,8 +510,18 @@ CreateRecursiveMutex_SDL (void)
mtx->thread_id = 0;
mtx->mutex = SDL_CreateMutex ();
if (mtx->mutex == NULL)
{
#ifdef NAMED_SYNCHRO
fprintf (stderr, "Could not initialize recursive mutex '%s': aborting.\n", name);
#else
fprintf (stderr, "Could not initialize recursive mutex: aborting.\n");
#endif
abort ();
}
#ifdef NAMED_SYNCHRO
mtx->name = name;
mtx->syncClass = syncClass;
#endif
mtx->locks = 0;
return (RecursiveMutex) mtx;
@@ -420,7 +543,7 @@ LockRecursiveMutex_SDL (RecursiveMutex val)
if (mtx->thread_id != thread_id)
{
#ifdef TRACK_CONTENTION
if (mtx->thread_id)
if (mtx->thread_id && (mtx->syncClass & TRACK_CONTENTION_CLASSES))
{
fprintf (stderr, "Thread '%s' blocking on '%s'\n", MyThreadName (), mtx->name);
}
@@ -466,12 +589,13 @@ typedef struct _cond {
SDL_mutex *mutex;
#ifdef NAMED_SYNCHRO
const char *name;
DWORD syncClass;
#endif
} cvar;
CondVar
#ifdef NAMED_SYNCHRO
CreateCondVar_SDL (const char *name)
CreateCondVar_SDL (const char *name, DWORD syncClass)
#else
CreateCondVar_SDL (void)
#endif
@@ -479,8 +603,18 @@ CreateCondVar_SDL (void)
cvar *cv = (cvar *) HMalloc (sizeof (cvar));
cv->cond = SDL_CreateCond ();
cv->mutex = SDL_CreateMutex ();
if ((cv->cond == NULL) || (cv->mutex == NULL))
{
#ifdef NAMED_SYNCHRO
fprintf (stderr, "Could not initialize condition variable '%s': aborting.\n", name);
#else
fprintf (stderr, "Could not initialize condition variable: aborting.\n");
#endif
abort ();
}
#ifdef NAMED_SYNCHRO
cv->name = name;
cv->syncClass = syncClass;
#endif
return cv;
}
@@ -500,33 +634,24 @@ WaitCondVar_SDL (CondVar c)
cvar *cv = (cvar *) c;
SDL_mutexP (cv->mutex);
#ifdef TRACK_CONTENTION
fprintf (stderr, "Thread '%s' waiting for signal from '%s'\n", MyThreadName (), cv->name);
if (cv->syncClass & TRACK_CONTENTION_CLASSES)
{
fprintf (stderr, "Thread '%s' waiting for signal from '%s'\n", MyThreadName (), cv->name);
}
#endif
while (SDL_CondWait (cv->cond, cv->mutex) != 0)
{
TaskSwitch_SDL ();
}
#ifdef TRACK_CONTENTION
fprintf (stderr, "Thread '%s' received signal from '%s', awakening.\n", MyThreadName (), cv->name);
if (cv->syncClass & TRACK_CONTENTION_CLASSES)
{
fprintf (stderr, "Thread '%s' received signal from '%s', awakening.\n", MyThreadName (), cv->name);
}
#endif
SDL_mutexV (cv->mutex);
}
void
WaitProtectedCondVar_SDL (CondVar c, Mutex m)
{
cvar *cv = (cvar *) c;
#ifdef TRACK_CONTENTION
fprintf (stderr, "Thread '%s' waiting for signal from '%s'\n", MyThreadName (), cv->name);
#endif
if (SDL_CondWait (cv->cond, m) != 0) {
TaskSwitch_SDL ();
}
#ifdef TRACK_CONTENTION
fprintf (stderr, "Thread '%s' received signal from '%s', awakening.\n", MyThreadName (), cv->name);
#endif
}
void
SignalCondVar_SDL (CondVar c)
{
+18 -21
View File
@@ -25,51 +25,42 @@
#include "libs/threadlib.h"
#include "libs/timelib.h"
#define NativeGetThreadID(thread) SDL_GetThreadID ((thread))
#define NativeThreadID() SDL_ThreadID ()
typedef SDL_mutex *NativeMutex;
#define NativeCreateMutex() \
SDL_CreateMutex ()
#define NativeDestroyMutex(mutex) \
SDL_DestroyMutex ((mutex))
#define NativeLockMutex(mutex) \
SDL_mutexP ((mutex))
#define NativeUnlockMutex(mutex) \
SDL_mutexV ((mutex))
#define NativeCurrentThreadID() \
SDL_ThreadID ()
void InitThreadSystem_SDL (void);
void UnInitThreadSystem_SDL (void);
#ifdef NAMED_SYNCHRO
/* Prototypes with the "name" field */
Thread CreateThread_SDL (ThreadFunction func, void *data, SDWORD stackSize, const char *name);
Semaphore CreateSemaphore_SDL (DWORD initial, const char *name);
RecursiveMutex CreateRecursiveMutex_SDL (const char *name);
CondVar CreateCondVar_SDL (const char *name);
Mutex CreateMutex_SDL (const char *name, DWORD syncClass);
Semaphore CreateSemaphore_SDL (DWORD initial, const char *name, DWORD syncClass);
RecursiveMutex CreateRecursiveMutex_SDL (const char *name, DWORD syncClass);
CondVar CreateCondVar_SDL (const char *name, DWORD syncClass);
#else
/* Prototypes without the "name" field. */
Thread CreateThread_SDL (ThreadFunction func, void *data, SDWORD stackSize);
Mutex CreateMutex_SDL (void);
Semaphore CreateSemaphore_SDL (DWORD initial);
RecursiveMutex CreateRecursiveMutex_SDL (void);
CondVar CreateCondVar_SDL (void);
#endif
ThreadLocal *GetMyThreadLocal_SDL (void);
void SleepThread_SDL (TimeCount sleepTime);
void SleepThreadUntil_SDL (TimeCount wakeTime);
void TaskSwitch_SDL (void);
void WaitThread_SDL (Thread thread, int *status);
void DestroyMutex_SDL (Mutex m);
void LockMutex_SDL (Mutex m);
void UnlockMutex_SDL (Mutex m);
void DestroySemaphore_SDL (Semaphore sem);
void SetSemaphore_SDL (Semaphore sem);
void ClearSemaphore_SDL (Semaphore sem);
void DestroyCondVar_SDL (CondVar c);
void WaitCondVar_SDL (CondVar c);
void WaitProtectedCondVar_SDL (CondVar c, Mutex m);
void SignalCondVar_SDL (CondVar c);
void BroadcastCondVar_SDL (CondVar c);
@@ -81,12 +72,19 @@ int GetRecursiveMutexDepth_SDL (RecursiveMutex m);
#define NativeInitThreadSystem InitThreadSystem_SDL
#define NativeUnInitThreadSystem UnInitThreadSystem_SDL
#define NativeGetMyThreadLocal GetMyThreadLocal_SDL
#define NativeCreateThread CreateThread_SDL
#define NativeSleepThread SleepThread_SDL
#define NativeSleepThreadUntil SleepThreadUntil_SDL
#define NativeTaskSwitch TaskSwitch_SDL
#define NativeWaitThread WaitThread_SDL
#define NativeCreateMutex CreateMutex_SDL
#define NativeDestroyMutex DestroyMutex_SDL
#define NativeLockMutex LockMutex_SDL
#define NativeUnlockMutex UnlockMutex_SDL
#define NativeCreateSemaphore CreateSemaphore_SDL
#define NativeDestroySemaphore DestroySemaphore_SDL
#define NativeSetSemaphore SetSemaphore_SDL
@@ -95,7 +93,6 @@ int GetRecursiveMutexDepth_SDL (RecursiveMutex m);
#define NativeCreateCondVar CreateCondVar_SDL
#define NativeDestroyCondVar DestroyCondVar_SDL
#define NativeWaitCondVar WaitCondVar_SDL
#define NativeWaitProtectedCondVar WaitProtectedCondVar_SDL
#define NativeSignalCondVar SignalCondVar_SDL
#define NativeBroadcastCondVar BroadcastCondVar_SDL
+33 -27
View File
@@ -46,27 +46,27 @@ CreateThread_Core (ThreadFunction func, void *data, SDWORD stackSize, const char
}
Mutex
CreateMutex_Core (void)
CreateMutex_Core (const char *name, DWORD syncClass)
{
return (Mutex) NativeCreateMutex ();
return NativeCreateMutex (name, syncClass);
}
Semaphore
CreateSemaphore_Core (DWORD initial, const char *name)
CreateSemaphore_Core (DWORD initial, const char *name, DWORD syncClass)
{
return NativeCreateSemaphore (initial, name);
return NativeCreateSemaphore (initial, name, syncClass);
}
RecursiveMutex
CreateRecursiveMutex_Core (const char *name)
CreateRecursiveMutex_Core (const char *name, DWORD syncClass)
{
return NativeCreateRecursiveMutex (name);
return NativeCreateRecursiveMutex (name, syncClass);
}
CondVar
CreateCondVar_Core (const char *name)
CreateCondVar_Core (const char *name, DWORD syncClass)
{
return NativeCreateCondVar (name);
return NativeCreateCondVar (name, syncClass);
}
#else
@@ -80,7 +80,7 @@ CreateThread_Core (ThreadFunction func, void *data, SDWORD stackSize)
Mutex
CreateMutex_Core (void)
{
return (Mutex) NativeCreateMutex ();
return NativeCreateMutex ();
}
Semaphore
@@ -102,6 +102,27 @@ CreateCondVar_Core (void)
}
#endif
ThreadLocal *
CreateThreadLocal (void)
{
ThreadLocal *tl = HMalloc (sizeof (ThreadLocal));
tl->flushSem = CreateSemaphore (0, "FlushGraphics", SYNC_CLASS_VIDEO);
return tl;
}
void
DestroyThreadLocal (ThreadLocal *tl)
{
DestroySemaphore (tl->flushSem);
HFree (tl);
}
ThreadLocal *
GetMyThreadLocal (void)
{
return NativeGetMyThreadLocal ();
}
void
WaitThread (Thread thread, int *status)
{
@@ -129,22 +150,19 @@ TaskSwitch (void)
void
DestroyMutex (Mutex sem)
{
NativeDestroyMutex ((NativeMutex) sem);
NativeDestroyMutex (sem);
}
void
LockMutex (Mutex sem)
{
while (NativeLockMutex ((NativeMutex) sem) == -1)
{
TaskSwitch ();
}
NativeLockMutex (sem);
}
void
UnlockMutex (Mutex sem)
{
NativeUnlockMutex ((NativeMutex) sem);
NativeUnlockMutex (sem);
}
void
@@ -177,12 +195,6 @@ WaitCondVar (CondVar cv)
NativeWaitCondVar (cv);
}
void
WaitProtectedCondVar (CondVar cv, Mutex m)
{
NativeWaitProtectedCondVar (cv, m);
}
void
SignalCondVar (CondVar cv)
{
@@ -195,12 +207,6 @@ BroadcastCondVar (CondVar cv)
NativeBroadcastCondVar (cv);
}
DWORD
CurrentThreadID ()
{
return (DWORD)NativeThreadID ();
}
void
DestroyRecursiveMutex (RecursiveMutex mutex)
{
+1 -1
View File
@@ -37,7 +37,7 @@ TFB_CreateVideoImage (int w, int h)
SDL_PixelFormat* fmt = SDL_Video->format;
img = HMalloc (sizeof (TFB_Image));
img->mutex = CreateMutex ();
img->mutex = CreateMutex ("vid image lock", SYNC_CLASS_VIDEO);
img->ScaledImg = NULL;
img->MipmapImg = NULL;
img->colormap_index = -1;
+2 -2
View File
@@ -127,8 +127,8 @@ _init_video_file(PVOID pStr)
vid->length = dec->length;
vid->w = vid->decoder->w;
vid->h = vid->decoder->h;
vid->guard = CreateMutex ();
vid->frame_lock = CreateCondVar ("frame lock");
vid->guard = CreateMutex ("video guard", SYNC_CLASS_VIDEO);
vid->frame_lock = CreateCondVar ("frame lock", SYNC_CLASS_VIDEO);
return (VIDEO_REF) vid;
}
+1 -1
View File
@@ -295,7 +295,7 @@ TFB_PlayVideo (VIDEO_REF VidRef, uint32 x, uint32 y)
// creation probably needs better handling
if (!vp_interthread_lock)
vp_interthread_lock = CreateSemaphore (1, "inter-thread param lock");
vp_interthread_lock = CreateSemaphore (1, "inter-thread param lock", SYNC_CLASS_VIDEO);
SetSemaphore (vp_interthread_lock);
vp_interthread_clip = vid;
+1 -1
View File
@@ -1354,7 +1354,7 @@ SetFlashRect (PRECT pRect, FRAME f)
int create_flash = 0;
if (! flash_mutex)
flash_mutex = CreateMutex ();
flash_mutex = CreateMutex ("FlashRect Lock", SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO);
old_r = flash_rect;
old_f = flash_frame;
+2 -2
View File
@@ -350,8 +350,8 @@ main (int argc, char *argv[])
InitTimeSystem ();
InitTaskSystem ();
GraphicsLock = CreateMutex (/*"Graphics"*/);
RenderingCond = CreateCondVar ("DCQ empty");
GraphicsLock = CreateMutex ("Graphics", SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO);
RenderingCond = CreateCondVar ("DCQ empty", SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO);
TFB_InitGraphics (gfxdriver, gfxflags, width, height, bpp);
init_communication ();