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:
@@ -1,4 +1,5 @@
|
|||||||
Changes towards version 0.4:
|
Changes towards version 0.4:
|
||||||
|
- Major refactoring of threadlib; see doc/devel/threads -Michael
|
||||||
- Downgraded the GraphicsLock to an ordinary Mutex -Michael
|
- Downgraded the GraphicsLock to an ordinary Mutex -Michael
|
||||||
- Added movie player; only movies defined are intro and ending;
|
- Added movie player; only movies defined are intro and ending;
|
||||||
only .duk decoder present (.duk audio decoder mostly derived
|
only .duk decoder present (.duk audio decoder mostly derived
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -783,10 +783,6 @@ SOURCE=..\sc2code\libs\threads\thrcommon.c
|
|||||||
|
|
||||||
SOURCE=..\sc2code\libs\threads\thrcommon.h
|
SOURCE=..\sc2code\libs\threads\thrcommon.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\sc2code\libs\threads\condbank.c
|
|
||||||
# End Source File
|
|
||||||
# End Group
|
# End Group
|
||||||
# Begin Group "time"
|
# Begin Group "time"
|
||||||
|
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ InitGameClock (void)
|
|||||||
{
|
{
|
||||||
if (!InitQueue (&GLOBAL (GameClock.event_q), NUM_EVENTS, sizeof (EVENT)))
|
if (!InitQueue (&GLOBAL (GameClock.event_q), NUM_EVENTS, sizeof (EVENT)))
|
||||||
return (FALSE);
|
return (FALSE);
|
||||||
clock_mutex = CreateMutex ();
|
clock_mutex = CreateMutex ("Clock Mutex", SYNC_CLASS_TOPLEVEL);
|
||||||
GLOBAL (GameClock.month_index) = 2;
|
GLOBAL (GameClock.month_index) = 2;
|
||||||
GLOBAL (GameClock.day_index) = 17;
|
GLOBAL (GameClock.day_index) = 17;
|
||||||
GLOBAL (GameClock.year_index) = START_YEAR; /* Feb 17, START_YEAR */
|
GLOBAL (GameClock.year_index) = START_YEAR; /* Feb 17, START_YEAR */
|
||||||
|
|||||||
@@ -488,7 +488,7 @@ init_xform_control (void)
|
|||||||
{
|
{
|
||||||
XFormControl.XFormCurrent = XFormControl.XFormInsertPoint = 0;
|
XFormControl.XFormCurrent = XFormControl.XFormInsertPoint = 0;
|
||||||
XFormControl.XFormsPending = FALSE;
|
XFormControl.XFormsPending = FALSE;
|
||||||
XFormControl.XFormLock = CreateMutex ();
|
XFormControl.XFormLock = CreateMutex ("Transform Lock", SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -521,7 +521,7 @@ init_communication (void)
|
|||||||
{
|
{
|
||||||
TFB_Canvas canvas;
|
TFB_Canvas canvas;
|
||||||
|
|
||||||
subtitle_mutex = CreateMutex ();
|
subtitle_mutex = CreateMutex ("Subtitle Lock", SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO);
|
||||||
init_xform_control ();
|
init_xform_control ();
|
||||||
|
|
||||||
canvas = TFB_DrawCanvas_New_TrueColor (SIS_SCREEN_WIDTH,
|
canvas = TFB_DrawCanvas_New_TrueColor (SIS_SCREEN_WIDTH,
|
||||||
|
|||||||
@@ -272,7 +272,7 @@ InitGlobData (void)
|
|||||||
// but it is always cleared before set, so it toggled between
|
// but it is always cleared before set, so it toggled between
|
||||||
// 2 and 1, which doesn't actually do anything.
|
// 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
|
int
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ typedef struct tfb_dc_delimg
|
|||||||
|
|
||||||
typedef struct tfb_dc_signal
|
typedef struct tfb_dc_signal
|
||||||
{
|
{
|
||||||
DWORD thread;
|
Semaphore sem;
|
||||||
} TFB_DrawCommand_SendSignal;
|
} TFB_DrawCommand_SendSignal;
|
||||||
|
|
||||||
typedef struct tfb_drawcommand
|
typedef struct tfb_drawcommand
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ Init_DrawCommandQueue (void)
|
|||||||
DrawCommandQueue.FullSize = 0;
|
DrawCommandQueue.FullSize = 0;
|
||||||
DrawCommandQueue.Size = 0;
|
DrawCommandQueue.Size = 0;
|
||||||
|
|
||||||
DCQ_Mutex = CreateRecursiveMutex ("DCQ");
|
DCQ_Mutex = CreateRecursiveMutex ("DCQ", SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -200,9 +200,6 @@ TFB_EnqueueDrawCommand (TFB_DrawCommand* DrawCommand)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DrawCommand->Type == TFB_DRAWCOMMANDTYPE_SENDSIGNAL)
|
|
||||||
DrawCommand->data.sendsignal.thread = CurrentThreadID ();
|
|
||||||
|
|
||||||
if (DrawCommand->Type <= TFB_DRAWCOMMANDTYPE_COPYTOIMAGE
|
if (DrawCommand->Type <= TFB_DRAWCOMMANDTYPE_COPYTOIMAGE
|
||||||
&& TYPE_GET (_CurFramePtr->TypeIndexAndFlags) == SCREEN_DRAWABLE)
|
&& TYPE_GET (_CurFramePtr->TypeIndexAndFlags) == SCREEN_DRAWABLE)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -669,7 +669,7 @@ TFB_FlushGraphics () // Only call from main thread!!
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TFB_DRAWCOMMANDTYPE_SENDSIGNAL:
|
case TFB_DRAWCOMMANDTYPE_SENDSIGNAL:
|
||||||
SignalThread (DC.data.sendsignal.thread);
|
ClearSemaphore (DC.data.sendsignal.sem);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -197,14 +197,15 @@ void
|
|||||||
TFB_DrawScreen_WaitForSignal (void)
|
TFB_DrawScreen_WaitForSignal (void)
|
||||||
{
|
{
|
||||||
TFB_DrawCommand DrawCommand;
|
TFB_DrawCommand DrawCommand;
|
||||||
int channel;
|
Semaphore s;
|
||||||
|
s = GetMyThreadLocal ()->flushSem;
|
||||||
DrawCommand.Type = TFB_DRAWCOMMANDTYPE_SENDSIGNAL;
|
DrawCommand.Type = TFB_DRAWCOMMANDTYPE_SENDSIGNAL;
|
||||||
|
DrawCommand.data.sendsignal.sem = s;
|
||||||
Lock_DCQ (1);
|
Lock_DCQ (1);
|
||||||
channel = FindSignalChannel ();
|
|
||||||
TFB_BatchReset ();
|
TFB_BatchReset ();
|
||||||
TFB_EnqueueDrawCommand(&DrawCommand);
|
TFB_EnqueueDrawCommand(&DrawCommand);
|
||||||
Unlock_DCQ();
|
Unlock_DCQ();
|
||||||
WaitForSignal (channel);
|
SetSemaphore (s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -247,7 +248,7 @@ TFB_Image *
|
|||||||
TFB_DrawImage_New (TFB_Canvas canvas)
|
TFB_DrawImage_New (TFB_Canvas canvas)
|
||||||
{
|
{
|
||||||
TFB_Image *img = HMalloc (sizeof (TFB_Image));
|
TFB_Image *img = HMalloc (sizeof (TFB_Image));
|
||||||
img->mutex = CreateMutex ();
|
img->mutex = CreateMutex ("image lock", SYNC_CLASS_VIDEO);
|
||||||
img->ScaledImg = NULL;
|
img->ScaledImg = NULL;
|
||||||
img->MipmapImg = NULL;
|
img->MipmapImg = NULL;
|
||||||
img->colormap_index = -1;
|
img->colormap_index = -1;
|
||||||
|
|||||||
@@ -382,7 +382,7 @@ mem_init (void)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
_MemoryLock = CreateMutex ();
|
_MemoryLock = CreateMutex ("memory lock", SYNC_CLASS_RESOURCE);
|
||||||
LockMutex (_MemoryLock);
|
LockMutex (_MemoryLock);
|
||||||
|
|
||||||
freeListHead = &extents[0];
|
freeListHead = &extents[0];
|
||||||
|
|||||||
@@ -209,9 +209,9 @@ mixSDL_OpenAudio (uint32 frequency, uint32 format, uint32 samples_buf,
|
|||||||
mixer_datasize = samples_buf * mixer_spec.channels * 2;
|
mixer_datasize = samples_buf * mixer_spec.channels * 2;
|
||||||
mixer_data = (sint32 *) HMalloc (sizeof (uint32) * mixer_datasize);
|
mixer_data = (sint32 *) HMalloc (sizeof (uint32) * mixer_datasize);
|
||||||
|
|
||||||
src_mutex = CreateRecursiveMutex("mixSDL_SourceMutex");
|
src_mutex = CreateRecursiveMutex("mixSDL_SourceMutex", SYNC_CLASS_AUDIO);
|
||||||
buf_mutex = CreateRecursiveMutex("mixSDL_BufferMutex");
|
buf_mutex = CreateRecursiveMutex("mixSDL_BufferMutex", SYNC_CLASS_AUDIO);
|
||||||
act_mutex = CreateRecursiveMutex("mixSDL_ActiveMutex");
|
act_mutex = CreateRecursiveMutex("mixSDL_ActiveMutex", SYNC_CLASS_AUDIO);
|
||||||
|
|
||||||
audio_opened = 1;
|
audio_opened = 1;
|
||||||
mixer_driver->PauseAudio (0);
|
mixer_driver->PauseAudio (0);
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ TFB_mixSDL_InitSound (int driver, int flags)
|
|||||||
|
|
||||||
soundSource[i].sample = NULL;
|
soundSource[i].sample = NULL;
|
||||||
soundSource[i].stream_should_be_playing = FALSE;
|
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].sbuffer = NULL;
|
||||||
soundSource[i].sbuf_start = 0;
|
soundSource[i].sbuf_start = 0;
|
||||||
soundSource[i].sbuf_size = 0;
|
soundSource[i].sbuf_size = 0;
|
||||||
@@ -241,7 +241,7 @@ TFB_NoSound_InitSound (int driver, int flags)
|
|||||||
|
|
||||||
soundSource[i].sample = NULL;
|
soundSource[i].sample = NULL;
|
||||||
soundSource[i].stream_should_be_playing = FALSE;
|
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].sbuffer = NULL;
|
||||||
soundSource[i].sbuf_start = 0;
|
soundSource[i].sbuf_start = 0;
|
||||||
soundSource[i].sbuf_size = 0;
|
soundSource[i].sbuf_size = 0;
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ TFB_alInitSound (int driver, int flags)
|
|||||||
|
|
||||||
soundSource[i].sample = NULL;
|
soundSource[i].sample = NULL;
|
||||||
soundSource[i].stream_should_be_playing = FALSE;
|
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].sbuffer = NULL;
|
||||||
soundSource[i].sbuf_start = 0;
|
soundSource[i].sbuf_start = 0;
|
||||||
soundSource[i].sbuf_size = 0;
|
soundSource[i].sbuf_size = 0;
|
||||||
|
|||||||
@@ -583,7 +583,7 @@ SpliceTrack (UNICODE *TrackName, UNICODE *TrackText, UNICODE *TimeStamp, TFB_Tra
|
|||||||
TFB_SoundDecoder *decoder;
|
TFB_SoundDecoder *decoder;
|
||||||
TFB_SoundChainData* scd;
|
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));
|
sound_sample = (TFB_SoundSample *) HMalloc (sizeof (TFB_SoundSample));
|
||||||
scd = (TFB_SoundChainData *) HCalloc (sizeof (TFB_SoundChainData));
|
scd = (TFB_SoundChainData *) HCalloc (sizeof (TFB_SoundChainData));
|
||||||
sound_sample->data = scd;
|
sound_sample->data = scd;
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ InitTaskSystem (void)
|
|||||||
int i;
|
int i;
|
||||||
for (i = 0; i < TASK_MAX; ++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);
|
atexit (CleanupTaskSystem);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#define NAMED_SYNCHRO /* Should synchronizable objects have names? */
|
#define NAMED_SYNCHRO /* Should synchronizable objects have names? */
|
||||||
// #define TRACK_CONTENTION /* Should we report when a thread sleeps on synchronize? */
|
// #define TRACK_CONTENTION /* Should we report when a thread sleeps on synchronize? */
|
||||||
|
|
||||||
|
/* TRACK_CONTENTION implies NAMED_SYNCHRO. */
|
||||||
#ifdef TRACK_CONTENTION
|
#ifdef TRACK_CONTENTION
|
||||||
# ifndef NAMED_SYNCHRO
|
# ifndef NAMED_SYNCHRO
|
||||||
# define NAMED_SYNCHRO
|
# define NAMED_SYNCHRO
|
||||||
@@ -38,12 +39,6 @@
|
|||||||
#endif /* DEBUG */
|
#endif /* DEBUG */
|
||||||
|
|
||||||
#ifdef DEBUG_THREADS
|
#ifdef DEBUG_THREADS
|
||||||
# ifndef THREAD_QUEUE
|
|
||||||
# define THREAD_QUEUE
|
|
||||||
# endif
|
|
||||||
# ifndef THREAD_NAMES
|
|
||||||
# define THREAD_NAMES
|
|
||||||
# endif
|
|
||||||
# ifndef PROFILE_THREADS
|
# ifndef PROFILE_THREADS
|
||||||
# define PROFILE_THREADS
|
# define PROFILE_THREADS
|
||||||
# endif
|
# endif
|
||||||
@@ -56,25 +51,8 @@
|
|||||||
#define THREAD_NAMES
|
#define THREAD_NAMES
|
||||||
#endif
|
#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 InitThreadSystem (void);
|
||||||
void UnInitThreadSystem (void);
|
void UnInitThreadSystem (void);
|
||||||
void init_cond_bank (void);
|
|
||||||
void uninit_cond_bank (void);
|
|
||||||
|
|
||||||
typedef int (*ThreadFunction) (void *);
|
typedef int (*ThreadFunction) (void *);
|
||||||
|
|
||||||
@@ -84,27 +62,45 @@ typedef void *Semaphore;
|
|||||||
typedef void *RecursiveMutex;
|
typedef void *RecursiveMutex;
|
||||||
typedef void *CondVar;
|
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
|
#ifdef NAMED_SYNCHRO
|
||||||
|
/* Logical OR of all classes we want to track. */
|
||||||
|
#define TRACK_CONTENTION_CLASSES (SYNC_CLASS_TOPLEVEL)
|
||||||
|
|
||||||
/* Prototypes with the "name" field */
|
/* Prototypes with the "name" field */
|
||||||
|
|
||||||
Thread CreateThread_Core (ThreadFunction func, void *data, SDWORD stackSize, const char *name);
|
Thread CreateThread_Core (ThreadFunction func, void *data, SDWORD stackSize, const char *name);
|
||||||
Semaphore CreateSemaphore_Core (DWORD initial, const char *name);
|
Semaphore CreateSemaphore_Core (DWORD initial, const char *name, DWORD syncClass);
|
||||||
Mutex CreateMutex_Core (void);
|
Mutex CreateMutex_Core (const char *name, DWORD syncClass);
|
||||||
RecursiveMutex CreateRecursiveMutex_Core (const char *name);
|
RecursiveMutex CreateRecursiveMutex_Core (const char *name, DWORD syncClass);
|
||||||
CondVar CreateCondVar_Core (const char *name);
|
CondVar CreateCondVar_Core (const char *name, DWORD syncClass);
|
||||||
|
|
||||||
/* Preprocessor directives to forward to the appropriate routines */
|
/* Preprocessor directives to forward to the appropriate routines */
|
||||||
|
|
||||||
#define CreateThread(func, data, stackSize, name) \
|
#define CreateThread(func, data, stackSize, name) \
|
||||||
CreateThread_Core ((func), (data), (stackSize), (name))
|
CreateThread_Core ((func), (data), (stackSize), (name))
|
||||||
#define CreateSemaphore(initial, name) \
|
#define CreateSemaphore(initial, name, syncClass) \
|
||||||
CreateSemaphore_Core ((initial), (name))
|
CreateSemaphore_Core ((initial), (name), (syncClass))
|
||||||
#define CreateMutex() \
|
#define CreateMutex(name, syncClass) \
|
||||||
CreateMutex_Core ()
|
CreateMutex_Core ((name), (syncClass))
|
||||||
#define CreateRecursiveMutex(name) \
|
#define CreateRecursiveMutex(name, syncClass) \
|
||||||
CreateRecursiveMutex_Core((name))
|
CreateRecursiveMutex_Core((name), (syncClass))
|
||||||
#define CreateCondVar(name) \
|
#define CreateCondVar(name, syncClass) \
|
||||||
CreateCondVar_Core ((name))
|
CreateCondVar_Core ((name), (syncClass))
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
@@ -119,19 +115,23 @@ CondVar CreateCondVar_Core (void);
|
|||||||
/* Preprocessor directives to forward to the appropriate routines.
|
/* Preprocessor directives to forward to the appropriate routines.
|
||||||
The "name" field is stripped away in preprocessing. */
|
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))
|
CreateThread_Core ((func), (data), (stackSize))
|
||||||
#define CreateSemaphore(initial, name) \
|
#define CreateSemaphore(initial, name, syncClass) \
|
||||||
CreateSemaphore_Core ((initial))
|
CreateSemaphore_Core ((initial))
|
||||||
#define CreateMutex() \
|
#define CreateMutex(name, syncClass) \
|
||||||
CreateMutex_Core ()
|
CreateMutex_Core ()
|
||||||
#define CreateRecursiveMutex(name) \
|
#define CreateRecursiveMutex(name, syncClass) \
|
||||||
CreateRecursiveMutex_Core()
|
CreateRecursiveMutex_Core()
|
||||||
#define CreateCondVar(name) \
|
#define CreateCondVar(name, syncClass) \
|
||||||
CreateCondVar_Core ()
|
CreateCondVar_Core ()
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ThreadLocal *CreateThreadLocal (void);
|
||||||
|
void DestroyThreadLocal (ThreadLocal *tl);
|
||||||
|
ThreadLocal *GetMyThreadLocal (void);
|
||||||
|
|
||||||
void SleepThread (TimePeriod timePeriod);
|
void SleepThread (TimePeriod timePeriod);
|
||||||
void SleepThreadUntil (TimeCount wakeTime);
|
void SleepThreadUntil (TimeCount wakeTime);
|
||||||
void TaskSwitch (void);
|
void TaskSwitch (void);
|
||||||
@@ -157,15 +157,8 @@ int GetRecursiveMutexDepth (RecursiveMutex m);
|
|||||||
|
|
||||||
void DestroyCondVar (CondVar);
|
void DestroyCondVar (CondVar);
|
||||||
void WaitCondVar (CondVar);
|
void WaitCondVar (CondVar);
|
||||||
void WaitProtectedCondVar (CondVar, Mutex);
|
|
||||||
void SignalCondVar (CondVar);
|
void SignalCondVar (CondVar);
|
||||||
void BroadcastCondVar (CondVar);
|
void BroadcastCondVar (CondVar);
|
||||||
|
|
||||||
DWORD CurrentThreadID (void);
|
|
||||||
|
|
||||||
int FindSignalChannel ();
|
|
||||||
void WaitForSignal (int);
|
|
||||||
void SignalThread (DWORD);
|
|
||||||
|
|
||||||
#endif /* _THREADLIB_H */
|
#endif /* _THREADLIB_H */
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
uqm_SUBDIRS="sdl"
|
uqm_SUBDIRS="sdl"
|
||||||
uqm_CFILES="condbank.c thrcommon.c"
|
uqm_CFILES="thrcommon.c"
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -38,6 +38,7 @@ typedef struct _thread {
|
|||||||
#ifdef PROFILE_THREADS
|
#ifdef PROFILE_THREADS
|
||||||
int startTime;
|
int startTime;
|
||||||
#endif /* PROFILE_THREADS */
|
#endif /* PROFILE_THREADS */
|
||||||
|
ThreadLocal *localData;
|
||||||
struct _thread *next;
|
struct _thread *next;
|
||||||
} *TrueThread;
|
} *TrueThread;
|
||||||
|
|
||||||
@@ -117,13 +118,11 @@ InitThreadSystem_SDL (void)
|
|||||||
#ifdef PROFILE_THREADS
|
#ifdef PROFILE_THREADS
|
||||||
signal(SIGUSR1, SigUSR1Handler);
|
signal(SIGUSR1, SigUSR1Handler);
|
||||||
#endif
|
#endif
|
||||||
init_cond_bank ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
UnInitThreadSystem_SDL (void)
|
UnInitThreadSystem_SDL (void)
|
||||||
{
|
{
|
||||||
uninit_cond_bank ();
|
|
||||||
#ifdef PROFILE_THREADS
|
#ifdef PROFILE_THREADS
|
||||||
signal(SIGUSR1, SIG_DFL);
|
signal(SIGUSR1, SIG_DFL);
|
||||||
#endif
|
#endif
|
||||||
@@ -220,7 +219,7 @@ ThreadHelper (void *startInfo) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
UnQueueThread (thread);
|
UnQueueThread (thread);
|
||||||
|
DestroyThreadLocal (thread->localData);
|
||||||
HFree (thread);
|
HFree (thread);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -243,6 +242,8 @@ CreateThread_SDL (ThreadFunction func, void *data, SDWORD stackSize
|
|||||||
thread->startTime = GetTimeCounter ();
|
thread->startTime = GetTimeCounter ();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
thread->localData = CreateThreadLocal ();
|
||||||
|
|
||||||
startInfo = (struct ThreadStartInfo *) HMalloc (sizeof (*startInfo));
|
startInfo = (struct ThreadStartInfo *) HMalloc (sizeof (*startInfo));
|
||||||
startInfo->func = func;
|
startInfo->func = func;
|
||||||
startInfo->data = data;
|
startInfo->data = data;
|
||||||
@@ -252,6 +253,7 @@ CreateThread_SDL (ThreadFunction func, void *data, SDWORD stackSize
|
|||||||
thread->native = SDL_CreateThread (ThreadHelper, (void *) startInfo);
|
thread->native = SDL_CreateThread (ThreadHelper, (void *) startInfo);
|
||||||
if (!(thread->native))
|
if (!(thread->native))
|
||||||
{
|
{
|
||||||
|
DestroyThreadLocal (thread->localData);
|
||||||
HFree (startInfo);
|
HFree (startInfo);
|
||||||
HFree (thread);
|
HFree (thread);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -301,13 +303,112 @@ WaitThread_SDL (Thread thread, int *status) {
|
|||||||
SDL_WaitThread (((TrueThread)thread)->native, 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. */
|
/* 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. */
|
/* Mutexes. */
|
||||||
/* TODO. The w_memlib uses Mutexes right now, so we can't use HMalloc
|
/* 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. */
|
/* Semaphores. */
|
||||||
|
|
||||||
@@ -315,21 +416,32 @@ typedef struct _sem {
|
|||||||
SDL_sem *sem;
|
SDL_sem *sem;
|
||||||
#ifdef NAMED_SYNCHRO
|
#ifdef NAMED_SYNCHRO
|
||||||
const char *name;
|
const char *name;
|
||||||
|
DWORD syncClass;
|
||||||
#endif
|
#endif
|
||||||
} Sem;
|
} Sem;
|
||||||
|
|
||||||
Semaphore
|
Semaphore
|
||||||
CreateSemaphore_SDL (DWORD initial
|
CreateSemaphore_SDL (DWORD initial
|
||||||
#ifdef NAMED_SYNCHRO
|
#ifdef NAMED_SYNCHRO
|
||||||
, const char *name
|
, const char *name, DWORD syncClass
|
||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Sem *sem = (Sem *) HMalloc (sizeof (struct _sem));
|
Sem *sem = (Sem *) HMalloc (sizeof (struct _sem));
|
||||||
#ifdef NAMED_SYNCHRO
|
#ifdef NAMED_SYNCHRO
|
||||||
sem->name = name;
|
sem->name = name;
|
||||||
|
sem->syncClass = syncClass;
|
||||||
#endif
|
#endif
|
||||||
sem->sem = SDL_CreateSemaphore (initial);
|
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;
|
return sem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,9 +459,9 @@ SetSemaphore_SDL (Semaphore s)
|
|||||||
Sem *sem = (Sem *)s;
|
Sem *sem = (Sem *)s;
|
||||||
#ifdef TRACK_CONTENTION
|
#ifdef TRACK_CONTENTION
|
||||||
BOOLEAN contention = !(SDL_SemValue (sem->sem));
|
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
|
#endif
|
||||||
while (SDL_SemWait (sem->sem) == -1)
|
while (SDL_SemWait (sem->sem) == -1)
|
||||||
@@ -357,7 +469,7 @@ SetSemaphore_SDL (Semaphore s)
|
|||||||
TaskSwitch_SDL ();
|
TaskSwitch_SDL ();
|
||||||
}
|
}
|
||||||
#ifdef TRACK_CONTENTION
|
#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);
|
fprintf (stderr, "Thread '%s' awakens, released from semaphore '%s'\n", MyThreadName (), sem->name);
|
||||||
}
|
}
|
||||||
@@ -383,12 +495,13 @@ typedef struct _recm {
|
|||||||
Uint32 locks;
|
Uint32 locks;
|
||||||
#ifdef NAMED_SYNCHRO
|
#ifdef NAMED_SYNCHRO
|
||||||
const char *name;
|
const char *name;
|
||||||
|
DWORD syncClass;
|
||||||
#endif
|
#endif
|
||||||
} RecM;
|
} RecM;
|
||||||
|
|
||||||
RecursiveMutex
|
RecursiveMutex
|
||||||
#ifdef NAMED_SYNCHRO
|
#ifdef NAMED_SYNCHRO
|
||||||
CreateRecursiveMutex_SDL (const char *name)
|
CreateRecursiveMutex_SDL (const char *name, DWORD syncClass)
|
||||||
#else
|
#else
|
||||||
CreateRecursiveMutex_SDL (void)
|
CreateRecursiveMutex_SDL (void)
|
||||||
#endif
|
#endif
|
||||||
@@ -397,8 +510,18 @@ CreateRecursiveMutex_SDL (void)
|
|||||||
|
|
||||||
mtx->thread_id = 0;
|
mtx->thread_id = 0;
|
||||||
mtx->mutex = SDL_CreateMutex ();
|
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
|
#ifdef NAMED_SYNCHRO
|
||||||
mtx->name = name;
|
mtx->name = name;
|
||||||
|
mtx->syncClass = syncClass;
|
||||||
#endif
|
#endif
|
||||||
mtx->locks = 0;
|
mtx->locks = 0;
|
||||||
return (RecursiveMutex) mtx;
|
return (RecursiveMutex) mtx;
|
||||||
@@ -420,7 +543,7 @@ LockRecursiveMutex_SDL (RecursiveMutex val)
|
|||||||
if (mtx->thread_id != thread_id)
|
if (mtx->thread_id != thread_id)
|
||||||
{
|
{
|
||||||
#ifdef TRACK_CONTENTION
|
#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);
|
fprintf (stderr, "Thread '%s' blocking on '%s'\n", MyThreadName (), mtx->name);
|
||||||
}
|
}
|
||||||
@@ -466,12 +589,13 @@ typedef struct _cond {
|
|||||||
SDL_mutex *mutex;
|
SDL_mutex *mutex;
|
||||||
#ifdef NAMED_SYNCHRO
|
#ifdef NAMED_SYNCHRO
|
||||||
const char *name;
|
const char *name;
|
||||||
|
DWORD syncClass;
|
||||||
#endif
|
#endif
|
||||||
} cvar;
|
} cvar;
|
||||||
|
|
||||||
CondVar
|
CondVar
|
||||||
#ifdef NAMED_SYNCHRO
|
#ifdef NAMED_SYNCHRO
|
||||||
CreateCondVar_SDL (const char *name)
|
CreateCondVar_SDL (const char *name, DWORD syncClass)
|
||||||
#else
|
#else
|
||||||
CreateCondVar_SDL (void)
|
CreateCondVar_SDL (void)
|
||||||
#endif
|
#endif
|
||||||
@@ -479,8 +603,18 @@ CreateCondVar_SDL (void)
|
|||||||
cvar *cv = (cvar *) HMalloc (sizeof (cvar));
|
cvar *cv = (cvar *) HMalloc (sizeof (cvar));
|
||||||
cv->cond = SDL_CreateCond ();
|
cv->cond = SDL_CreateCond ();
|
||||||
cv->mutex = SDL_CreateMutex ();
|
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
|
#ifdef NAMED_SYNCHRO
|
||||||
cv->name = name;
|
cv->name = name;
|
||||||
|
cv->syncClass = syncClass;
|
||||||
#endif
|
#endif
|
||||||
return cv;
|
return cv;
|
||||||
}
|
}
|
||||||
@@ -500,33 +634,24 @@ WaitCondVar_SDL (CondVar c)
|
|||||||
cvar *cv = (cvar *) c;
|
cvar *cv = (cvar *) c;
|
||||||
SDL_mutexP (cv->mutex);
|
SDL_mutexP (cv->mutex);
|
||||||
#ifdef TRACK_CONTENTION
|
#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
|
#endif
|
||||||
while (SDL_CondWait (cv->cond, cv->mutex) != 0)
|
while (SDL_CondWait (cv->cond, cv->mutex) != 0)
|
||||||
{
|
{
|
||||||
TaskSwitch_SDL ();
|
TaskSwitch_SDL ();
|
||||||
}
|
}
|
||||||
#ifdef TRACK_CONTENTION
|
#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
|
#endif
|
||||||
SDL_mutexV (cv->mutex);
|
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
|
void
|
||||||
SignalCondVar_SDL (CondVar c)
|
SignalCondVar_SDL (CondVar c)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -25,51 +25,42 @@
|
|||||||
#include "libs/threadlib.h"
|
#include "libs/threadlib.h"
|
||||||
#include "libs/timelib.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 InitThreadSystem_SDL (void);
|
||||||
void UnInitThreadSystem_SDL (void);
|
void UnInitThreadSystem_SDL (void);
|
||||||
|
|
||||||
#ifdef NAMED_SYNCHRO
|
#ifdef NAMED_SYNCHRO
|
||||||
/* Prototypes with the "name" field */
|
/* Prototypes with the "name" field */
|
||||||
Thread CreateThread_SDL (ThreadFunction func, void *data, SDWORD stackSize, const char *name);
|
Thread CreateThread_SDL (ThreadFunction func, void *data, SDWORD stackSize, const char *name);
|
||||||
Semaphore CreateSemaphore_SDL (DWORD initial, const char *name);
|
Mutex CreateMutex_SDL (const char *name, DWORD syncClass);
|
||||||
RecursiveMutex CreateRecursiveMutex_SDL (const char *name);
|
Semaphore CreateSemaphore_SDL (DWORD initial, const char *name, DWORD syncClass);
|
||||||
CondVar CreateCondVar_SDL (const char *name);
|
RecursiveMutex CreateRecursiveMutex_SDL (const char *name, DWORD syncClass);
|
||||||
|
CondVar CreateCondVar_SDL (const char *name, DWORD syncClass);
|
||||||
#else
|
#else
|
||||||
/* Prototypes without the "name" field. */
|
/* Prototypes without the "name" field. */
|
||||||
Thread CreateThread_SDL (ThreadFunction func, void *data, SDWORD stackSize);
|
Thread CreateThread_SDL (ThreadFunction func, void *data, SDWORD stackSize);
|
||||||
|
Mutex CreateMutex_SDL (void);
|
||||||
Semaphore CreateSemaphore_SDL (DWORD initial);
|
Semaphore CreateSemaphore_SDL (DWORD initial);
|
||||||
RecursiveMutex CreateRecursiveMutex_SDL (void);
|
RecursiveMutex CreateRecursiveMutex_SDL (void);
|
||||||
CondVar CreateCondVar_SDL (void);
|
CondVar CreateCondVar_SDL (void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ThreadLocal *GetMyThreadLocal_SDL (void);
|
||||||
|
|
||||||
void SleepThread_SDL (TimeCount sleepTime);
|
void SleepThread_SDL (TimeCount sleepTime);
|
||||||
void SleepThreadUntil_SDL (TimeCount wakeTime);
|
void SleepThreadUntil_SDL (TimeCount wakeTime);
|
||||||
void TaskSwitch_SDL (void);
|
void TaskSwitch_SDL (void);
|
||||||
void WaitThread_SDL (Thread thread, int *status);
|
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 DestroySemaphore_SDL (Semaphore sem);
|
||||||
void SetSemaphore_SDL (Semaphore sem);
|
void SetSemaphore_SDL (Semaphore sem);
|
||||||
void ClearSemaphore_SDL (Semaphore sem);
|
void ClearSemaphore_SDL (Semaphore sem);
|
||||||
|
|
||||||
void DestroyCondVar_SDL (CondVar c);
|
void DestroyCondVar_SDL (CondVar c);
|
||||||
void WaitCondVar_SDL (CondVar c);
|
void WaitCondVar_SDL (CondVar c);
|
||||||
void WaitProtectedCondVar_SDL (CondVar c, Mutex m);
|
|
||||||
void SignalCondVar_SDL (CondVar c);
|
void SignalCondVar_SDL (CondVar c);
|
||||||
void BroadcastCondVar_SDL (CondVar c);
|
void BroadcastCondVar_SDL (CondVar c);
|
||||||
|
|
||||||
@@ -81,12 +72,19 @@ int GetRecursiveMutexDepth_SDL (RecursiveMutex m);
|
|||||||
#define NativeInitThreadSystem InitThreadSystem_SDL
|
#define NativeInitThreadSystem InitThreadSystem_SDL
|
||||||
#define NativeUnInitThreadSystem UnInitThreadSystem_SDL
|
#define NativeUnInitThreadSystem UnInitThreadSystem_SDL
|
||||||
|
|
||||||
|
#define NativeGetMyThreadLocal GetMyThreadLocal_SDL
|
||||||
|
|
||||||
#define NativeCreateThread CreateThread_SDL
|
#define NativeCreateThread CreateThread_SDL
|
||||||
#define NativeSleepThread SleepThread_SDL
|
#define NativeSleepThread SleepThread_SDL
|
||||||
#define NativeSleepThreadUntil SleepThreadUntil_SDL
|
#define NativeSleepThreadUntil SleepThreadUntil_SDL
|
||||||
#define NativeTaskSwitch TaskSwitch_SDL
|
#define NativeTaskSwitch TaskSwitch_SDL
|
||||||
#define NativeWaitThread WaitThread_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 NativeCreateSemaphore CreateSemaphore_SDL
|
||||||
#define NativeDestroySemaphore DestroySemaphore_SDL
|
#define NativeDestroySemaphore DestroySemaphore_SDL
|
||||||
#define NativeSetSemaphore SetSemaphore_SDL
|
#define NativeSetSemaphore SetSemaphore_SDL
|
||||||
@@ -95,7 +93,6 @@ int GetRecursiveMutexDepth_SDL (RecursiveMutex m);
|
|||||||
#define NativeCreateCondVar CreateCondVar_SDL
|
#define NativeCreateCondVar CreateCondVar_SDL
|
||||||
#define NativeDestroyCondVar DestroyCondVar_SDL
|
#define NativeDestroyCondVar DestroyCondVar_SDL
|
||||||
#define NativeWaitCondVar WaitCondVar_SDL
|
#define NativeWaitCondVar WaitCondVar_SDL
|
||||||
#define NativeWaitProtectedCondVar WaitProtectedCondVar_SDL
|
|
||||||
#define NativeSignalCondVar SignalCondVar_SDL
|
#define NativeSignalCondVar SignalCondVar_SDL
|
||||||
#define NativeBroadcastCondVar BroadcastCondVar_SDL
|
#define NativeBroadcastCondVar BroadcastCondVar_SDL
|
||||||
|
|
||||||
|
|||||||
@@ -46,27 +46,27 @@ CreateThread_Core (ThreadFunction func, void *data, SDWORD stackSize, const char
|
|||||||
}
|
}
|
||||||
|
|
||||||
Mutex
|
Mutex
|
||||||
CreateMutex_Core (void)
|
CreateMutex_Core (const char *name, DWORD syncClass)
|
||||||
{
|
{
|
||||||
return (Mutex) NativeCreateMutex ();
|
return NativeCreateMutex (name, syncClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
Semaphore
|
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
|
RecursiveMutex
|
||||||
CreateRecursiveMutex_Core (const char *name)
|
CreateRecursiveMutex_Core (const char *name, DWORD syncClass)
|
||||||
{
|
{
|
||||||
return NativeCreateRecursiveMutex (name);
|
return NativeCreateRecursiveMutex (name, syncClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
CondVar
|
CondVar
|
||||||
CreateCondVar_Core (const char *name)
|
CreateCondVar_Core (const char *name, DWORD syncClass)
|
||||||
{
|
{
|
||||||
return NativeCreateCondVar (name);
|
return NativeCreateCondVar (name, syncClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@@ -80,7 +80,7 @@ CreateThread_Core (ThreadFunction func, void *data, SDWORD stackSize)
|
|||||||
Mutex
|
Mutex
|
||||||
CreateMutex_Core (void)
|
CreateMutex_Core (void)
|
||||||
{
|
{
|
||||||
return (Mutex) NativeCreateMutex ();
|
return NativeCreateMutex ();
|
||||||
}
|
}
|
||||||
|
|
||||||
Semaphore
|
Semaphore
|
||||||
@@ -102,6 +102,27 @@ CreateCondVar_Core (void)
|
|||||||
}
|
}
|
||||||
#endif
|
#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
|
void
|
||||||
WaitThread (Thread thread, int *status)
|
WaitThread (Thread thread, int *status)
|
||||||
{
|
{
|
||||||
@@ -129,22 +150,19 @@ TaskSwitch (void)
|
|||||||
void
|
void
|
||||||
DestroyMutex (Mutex sem)
|
DestroyMutex (Mutex sem)
|
||||||
{
|
{
|
||||||
NativeDestroyMutex ((NativeMutex) sem);
|
NativeDestroyMutex (sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LockMutex (Mutex sem)
|
LockMutex (Mutex sem)
|
||||||
{
|
{
|
||||||
while (NativeLockMutex ((NativeMutex) sem) == -1)
|
NativeLockMutex (sem);
|
||||||
{
|
|
||||||
TaskSwitch ();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
UnlockMutex (Mutex sem)
|
UnlockMutex (Mutex sem)
|
||||||
{
|
{
|
||||||
NativeUnlockMutex ((NativeMutex) sem);
|
NativeUnlockMutex (sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -177,12 +195,6 @@ WaitCondVar (CondVar cv)
|
|||||||
NativeWaitCondVar (cv);
|
NativeWaitCondVar (cv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
WaitProtectedCondVar (CondVar cv, Mutex m)
|
|
||||||
{
|
|
||||||
NativeWaitProtectedCondVar (cv, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
SignalCondVar (CondVar cv)
|
SignalCondVar (CondVar cv)
|
||||||
{
|
{
|
||||||
@@ -195,12 +207,6 @@ BroadcastCondVar (CondVar cv)
|
|||||||
NativeBroadcastCondVar (cv);
|
NativeBroadcastCondVar (cv);
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD
|
|
||||||
CurrentThreadID ()
|
|
||||||
{
|
|
||||||
return (DWORD)NativeThreadID ();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
DestroyRecursiveMutex (RecursiveMutex mutex)
|
DestroyRecursiveMutex (RecursiveMutex mutex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ TFB_CreateVideoImage (int w, int h)
|
|||||||
SDL_PixelFormat* fmt = SDL_Video->format;
|
SDL_PixelFormat* fmt = SDL_Video->format;
|
||||||
|
|
||||||
img = HMalloc (sizeof (TFB_Image));
|
img = HMalloc (sizeof (TFB_Image));
|
||||||
img->mutex = CreateMutex ();
|
img->mutex = CreateMutex ("vid image lock", SYNC_CLASS_VIDEO);
|
||||||
img->ScaledImg = NULL;
|
img->ScaledImg = NULL;
|
||||||
img->MipmapImg = NULL;
|
img->MipmapImg = NULL;
|
||||||
img->colormap_index = -1;
|
img->colormap_index = -1;
|
||||||
|
|||||||
@@ -127,8 +127,8 @@ _init_video_file(PVOID pStr)
|
|||||||
vid->length = dec->length;
|
vid->length = dec->length;
|
||||||
vid->w = vid->decoder->w;
|
vid->w = vid->decoder->w;
|
||||||
vid->h = vid->decoder->h;
|
vid->h = vid->decoder->h;
|
||||||
vid->guard = CreateMutex ();
|
vid->guard = CreateMutex ("video guard", SYNC_CLASS_VIDEO);
|
||||||
vid->frame_lock = CreateCondVar ("frame lock");
|
vid->frame_lock = CreateCondVar ("frame lock", SYNC_CLASS_VIDEO);
|
||||||
|
|
||||||
return (VIDEO_REF) vid;
|
return (VIDEO_REF) vid;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -295,7 +295,7 @@ TFB_PlayVideo (VIDEO_REF VidRef, uint32 x, uint32 y)
|
|||||||
|
|
||||||
// creation probably needs better handling
|
// creation probably needs better handling
|
||||||
if (!vp_interthread_lock)
|
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);
|
SetSemaphore (vp_interthread_lock);
|
||||||
vp_interthread_clip = vid;
|
vp_interthread_clip = vid;
|
||||||
|
|
||||||
|
|||||||
@@ -1354,7 +1354,7 @@ SetFlashRect (PRECT pRect, FRAME f)
|
|||||||
int create_flash = 0;
|
int create_flash = 0;
|
||||||
|
|
||||||
if (! flash_mutex)
|
if (! flash_mutex)
|
||||||
flash_mutex = CreateMutex ();
|
flash_mutex = CreateMutex ("FlashRect Lock", SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO);
|
||||||
|
|
||||||
old_r = flash_rect;
|
old_r = flash_rect;
|
||||||
old_f = flash_frame;
|
old_f = flash_frame;
|
||||||
|
|||||||
+2
-2
@@ -350,8 +350,8 @@ main (int argc, char *argv[])
|
|||||||
InitTimeSystem ();
|
InitTimeSystem ();
|
||||||
InitTaskSystem ();
|
InitTaskSystem ();
|
||||||
|
|
||||||
GraphicsLock = CreateMutex (/*"Graphics"*/);
|
GraphicsLock = CreateMutex ("Graphics", SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO);
|
||||||
RenderingCond = CreateCondVar ("DCQ empty");
|
RenderingCond = CreateCondVar ("DCQ empty", SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO);
|
||||||
|
|
||||||
TFB_InitGraphics (gfxdriver, gfxflags, width, height, bpp);
|
TFB_InitGraphics (gfxdriver, gfxflags, width, height, bpp);
|
||||||
init_communication ();
|
init_communication ();
|
||||||
|
|||||||
Reference in New Issue
Block a user