diff --git a/sc2/build/unix/build.config b/sc2/build/unix/build.config index 45ef1052c..76e4b72c8 100644 --- a/sc2/build/unix/build.config +++ b/sc2/build/unix/build.config @@ -59,7 +59,6 @@ CHOICE_debug_OPTION_debug_TITLE="Debugging information" CHOICE_debug_OPTION_debug_ACTION='debug_action' debug_action() { CFLAGS="$CFLAGS -g -O0 -W -Wall" - CFLAGS="$CFLAGS -DDEBUG_TRACK_SEM" # enable semaphore deugging LDFLAGS="$LDFLAGS -O0" DEBUG=1 } @@ -67,7 +66,6 @@ CHOICE_debug_OPTION_strictdebug_TITLE="Debug info + strict compile checks" CHOICE_debug_OPTION_strictdebug_ACTION='strictdebug_action' strictdebug_action() { CFLAGS="$CFLAGS -O1" # This is needed for -Wunitialized - CFLAGS="$CFLAGS -DDEBUG_TRACK_SEM" # enable semaphore debugging CFLAGS="$CFLAGS -W -Wall \ -Wbad-function-cast -Wcast-qual -Wmissing-prototypes \ -Wstrict-prototypes -Wmissing-declarations \ diff --git a/sc2/src/sc2code/clock.c b/sc2/src/sc2code/clock.c index f41e9e2ba..6bc787884 100644 --- a/sc2/src/sc2code/clock.c +++ b/sc2/src/sc2code/clock.c @@ -65,7 +65,7 @@ int clock_task_func(void* data) * can be halted. (e.g. during battle * or communications) */ - LockCrossThreadMutex (GLOBAL (GameClock.clock_lock)); + SetSemaphore (GLOBAL (GameClock.clock_sem)); TimeIn = GetTimeCounter (); if (GLOBAL (GameClock).tick_count <= 0 @@ -165,7 +165,7 @@ int clock_task_func(void* data) LastTime += num_ticks; } - UnlockCrossThreadMutex (GLOBAL (GameClock.clock_lock)); + ClearSemaphore (GLOBAL (GameClock.clock_sem)); SleepThreadUntil (TimeIn + ONE_SECOND / 120); } FinishTask (task); @@ -215,7 +215,7 @@ SuspendGameClock (void) LockMutex (clock_mutex); if (GameClockRunning ()) { - LockCrossThreadMutex (GLOBAL (GameClock.clock_lock)); + SetSemaphore (GLOBAL (GameClock.clock_sem)); GLOBAL (GameClock.TimeCounter) = 0; } UnlockMutex (clock_mutex); @@ -228,7 +228,7 @@ ResumeGameClock (void) if (!GameClockRunning ()) { GLOBAL (GameClock.TimeCounter) = GetTimeCounter (); - UnlockCrossThreadMutex (GLOBAL (GameClock.clock_lock)); + ClearSemaphore (GLOBAL (GameClock.clock_sem)); } UnlockMutex (clock_mutex); } @@ -245,7 +245,7 @@ SetGameClockRate (COUNT seconds_per_day) SIZE new_day_in_ticks, new_tick_count; //if (GLOBAL (GameClock.clock_sem)) fprintf (stderr, "%u\n", GLOBAL (GameClock.clock_sem)); - LockCrossThreadMutex (GLOBAL (GameClock.clock_lock)); + SetSemaphore (GLOBAL (GameClock.clock_sem)); new_day_in_ticks = (SIZE)(seconds_per_day * CLOCK_BASE_FRAMERATE); if (GLOBAL (GameClock.day_in_ticks) == 0) new_tick_count = new_day_in_ticks; @@ -256,7 +256,7 @@ SetGameClockRate (COUNT seconds_per_day) new_tick_count = 1; GLOBAL (GameClock.day_in_ticks) = new_day_in_ticks; GLOBAL (GameClock.tick_count) = new_tick_count; - UnlockCrossThreadMutex (GLOBAL (GameClock.clock_lock)); + ClearSemaphore (GLOBAL (GameClock.clock_sem)); } BOOLEAN diff --git a/sc2/src/sc2code/clock.h b/sc2/src/sc2code/clock.h index b4fcfe232..0c3b4bf3f 100644 --- a/sc2/src/sc2code/clock.h +++ b/sc2/src/sc2code/clock.h @@ -56,7 +56,7 @@ typedef struct BYTE day_index, month_index; COUNT year_index; SIZE tick_count, day_in_ticks; - CrossThreadMutex clock_lock; + Semaphore clock_sem; Task clock_task; DWORD TimeCounter; diff --git a/sc2/src/sc2code/init.c b/sc2/src/sc2code/init.c index 57b9c6509..81b33c7b9 100644 --- a/sc2/src/sc2code/init.c +++ b/sc2/src/sc2code/init.c @@ -270,12 +270,9 @@ InitGlobData (void) GLOBAL (DisplayArray) = DisplayArray; // The clock semaphore was initially initialized as '1' // but it is always cleared before set, so it toggled between - // 2 and 1, which doesn't actually do anything. When this - // was transformed into a mutex, we lock it first to prevent - // double-unlock. + // 2 and 1, which doesn't actually do anything. - GLOBAL (GameClock.clock_lock) = CreateCrossThreadMutex("Clock"); - LockCrossThreadMutex (GLOBAL (GameClock.clock_lock)); + GLOBAL (GameClock.clock_sem) = CreateSemaphore(0, "Clock"); } int diff --git a/sc2/src/sc2code/libs/graphics/gfx_common.h b/sc2/src/sc2code/libs/graphics/gfx_common.h index aa49d1536..782398329 100644 --- a/sc2/src/sc2code/libs/graphics/gfx_common.h +++ b/sc2/src/sc2code/libs/graphics/gfx_common.h @@ -42,6 +42,7 @@ enum #define TFB_GFXFLAGS_SCALE_BIADAPT (1<<4) #define TFB_GFXFLAGS_SCALE_BIADAPTADV (1<<5) +void TFB_PreInit (void); int TFB_InitGraphics (int driver, int flags, int width, int height, int bpp); void TFB_UninitGraphics (void); void TFB_ProcessEvents (void); diff --git a/sc2/src/sc2code/libs/graphics/sdl/opengl.c b/sc2/src/sc2code/libs/graphics/sdl/opengl.c index 974c97f5f..1f02f53d9 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/opengl.c +++ b/sc2/src/sc2code/libs/graphics/sdl/opengl.c @@ -66,12 +66,7 @@ TFB_GL_InitGraphics (int driver, int flags, int width, int height, int bpp) GraphicsDriver = driver; - fprintf (stderr, "Initializing SDL (OpenGL).\n"); - if ((SDL_Init (SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) == -1)) - { - fprintf (stderr, "Could not initialize SDL: %s.\n", SDL_GetError()); - exit(-1); - } + fprintf (stderr, "Initializing SDL with OpenGL support.\n"); SDL_VideoDriverName (VideoName, sizeof (VideoName)); fprintf (stderr, "SDL driver used: %s\n", VideoName); diff --git a/sc2/src/sc2code/libs/graphics/sdl/pure.c b/sc2/src/sc2code/libs/graphics/sdl/pure.c index f79ee5038..2b1a6686b 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/pure.c +++ b/sc2/src/sc2code/libs/graphics/sdl/pure.c @@ -46,13 +46,7 @@ TFB_Pure_InitGraphics (int driver, int flags, int width, int height, int bpp) GraphicsDriver = driver; - fprintf (stderr, "Initializing SDL (pure).\n"); - - if ((SDL_Init (SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) == -1)) - { - fprintf (stderr, "Could not initialize SDL: %s.\n", SDL_GetError()); - exit(-1); - } + fprintf (stderr, "Initializing Pure-SDL graphics.).\n"); SDL_VideoDriverName (VideoName, sizeof (VideoName)); fprintf (stderr, "SDL driver used: %s\n", VideoName); diff --git a/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c b/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c index 3ac96f12d..2a59391e2 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c +++ b/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c @@ -55,6 +55,17 @@ TFB_Abort (void) abortFlag = TRUE; } +void +TFB_PreInit (void) +{ + fprintf (stderr, "Initializing base SDL functionality.\n"); + if ((SDL_Init (SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) == -1)) + { + fprintf (stderr, "Could not initialize SDL: %s.\n", SDL_GetError()); + exit(-1); + } +} + int TFB_InitGraphics (int driver, int flags, int width, int height, int bpp) { diff --git a/sc2/src/sc2code/libs/threadlib.h b/sc2/src/sc2code/libs/threadlib.h index 4f0af8190..0f54d01b7 100644 --- a/sc2/src/sc2code/libs/threadlib.h +++ b/sc2/src/sc2code/libs/threadlib.h @@ -22,10 +22,14 @@ #define THREADLIB SDL -/* -This is now a compile-time define -#define DEBUG_TRACK_SEM -*/ +#define NAMED_SYNCHRO /* Should synchronizable objects have names? */ +// #define TRACK_CONTENTION /* Should we report when a thread sleeps on synchronize? */ + +#ifdef TRACK_CONTENTION +# ifndef NAMED_SYNCHRO +# define NAMED_SYNCHRO +# endif +#endif /* TRACK_CONTENTION */ #ifdef DEBUG # ifndef DEBUG_THREADS @@ -74,80 +78,83 @@ void uninit_cond_bank (void); typedef int (*ThreadFunction) (void *); -typedef struct Thread { - void *native; -#ifdef THREAD_NAMES - const char *name; +typedef void *Thread; +typedef void *Mutex; +typedef void *Semaphore; +typedef void *RecursiveMutex; +typedef void *CondVar; + +#ifdef NAMED_SYNCHRO +/* 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); + +/* 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)) + +#else + +/* Prototypes without the "name" field. */ +Thread CreateThread_Core (ThreadFunction func, void *data, SDWORD stackSize); +Semaphore CreateSemaphore_Core (DWORD initial); +Mutex CreateMutex_Core (void); +RecursiveMutex CreateRecursiveMutex_Core (void); +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) \ + CreateThread_Core ((func), (data), (stackSize)) +#define CreateSemaphore(initial, name) \ + CreateSemaphore_Core ((initial)) +#define CreateMutex() \ + CreateMutex_Core () +#define CreateRecursiveMutex(name) \ + CreateRecursiveMutex_Core() +#define CreateCondVar(name) \ + CreateCondVar_Core () + #endif -#ifdef PROFILE_THREADS - int startTime; -#endif /* PROFILE_THREADS */ -#ifdef THREAD_QUEUE - struct Thread *next; -#endif -} *Thread; -#ifdef THREAD_NAMES -Thread CreateThreadAux (ThreadFunction func, void *data, - SDWORD stackSize, const char *name); -# define CreateThread(func, data, stackSize, name) \ - CreateThreadAux ((func), (data), (stackSize), (name)) -#else /* !defined(THREAD_NAMES) */ -Thread CreateThreadAux (ThreadFunction func, void *data, - SDWORD stackSize); -# define CreateThread(func, data, stackSize, name) \ - CreateThreadAux ((func), (data), (stackSize)) -#endif /* !defined(THREAD_NAMES) */ void SleepThread (TimePeriod timePeriod); void SleepThreadUntil (TimeCount wakeTime); void TaskSwitch (void); void WaitThread (Thread thread, int *status); -typedef void *Semaphore; -#ifdef DEBUG_TRACK_SEM -Semaphore CreateSemaphoreAux (DWORD initial, const char *sem_name); -# define CreateSemaphore(initial,sem_name) \ - CreateSemaphoreAux ((initial), (sem_name)) -void ResetSemaphoreOwnerAux (Semaphore sem); -# define ResetSemaphoreOwner(sem_name) \ - ResetSemaphoreOwnerAux (sem_name) -#else -Semaphore CreateSemaphoreAux (DWORD initial); -# define CreateSemaphore(initial,sem_name) \ - CreateSemaphoreAux ((initial)) -# define ResetSemaphoreOwner(sem_name) -#endif -DWORD SemaphoreValue (Semaphore sem); -void DestroySemaphore (Semaphore sem); -int SetSemaphore (Semaphore sem); -int TrySetSemaphore (Semaphore sem); -int TimeoutSetSemaphore (Semaphore sem, TimePeriod timeout); -void ClearSemaphore (Semaphore sem); #ifdef PROFILE_THREADS void PrintThreadsStats (void); #endif /* PROFILE_THREADS */ -typedef void *Mutex; -Mutex CreateMutex (void); + +void DestroySemaphore (Semaphore sem); +void SetSemaphore (Semaphore sem); +void ClearSemaphore (Semaphore sem); + void DestroyMutex (Mutex sem); -int LockMutex (Mutex sem); +void LockMutex (Mutex sem); void UnlockMutex (Mutex sem); -typedef void *RecursiveMutex; -RecursiveMutex CreateRecursiveMutex (const char *name); void DestroyRecursiveMutex (RecursiveMutex m); void LockRecursiveMutex (RecursiveMutex m); void UnlockRecursiveMutex (RecursiveMutex m); int GetRecursiveMutexDepth (RecursiveMutex m); -typedef void *CrossThreadMutex; -CrossThreadMutex CreateCrossThreadMutex (const char *name); -void DestroyCrossThreadMutex (CrossThreadMutex ctm); -int LockCrossThreadMutex (CrossThreadMutex ctm); -void UnlockCrossThreadMutex (CrossThreadMutex ctm); - -typedef void *CondVar; -CondVar CreateCondVar (void); void DestroyCondVar (CondVar); void WaitCondVar (CondVar); void WaitProtectedCondVar (CondVar, Mutex); diff --git a/sc2/src/sc2code/libs/threads/condbank.c b/sc2/src/sc2code/libs/threads/condbank.c index 577568c9d..60f4f87ec 100644 --- a/sc2/src/sc2code/libs/threads/condbank.c +++ b/sc2/src/sc2code/libs/threads/condbank.c @@ -45,7 +45,7 @@ init_cond_bank () bank_mutex = CreateMutex (); for (i = 0; i < CONDVAR_BANK_SIZE; i++) { - bank[i].var = CreateCondVar (); + bank[i].var = CreateCondVar ("FlushGraphics Bank"); bank[i].id = bank[i].used = 0; bank[i].control = CreateMutex (); } diff --git a/sc2/src/sc2code/libs/threads/sdl/sdlthreads.c b/sc2/src/sc2code/libs/threads/sdl/sdlthreads.c index 49ebc3c88..cfb9930cb 100644 --- a/sc2/src/sc2code/libs/threads/sdl/sdlthreads.c +++ b/sc2/src/sc2code/libs/threads/sdl/sdlthreads.c @@ -20,15 +20,55 @@ #include #include "misc.h" #include "sdlthreads.h" +#ifdef PROFILE_THREADS +#include +#include +#endif #if defined(PROFILE_THREADS) && !defined(WIN32) #include #include #endif +typedef struct _thread { + void *native; +#ifdef NAMED_SYNCHRO + const char *name; +#endif #ifdef PROFILE_THREADS -void -SDLWrapper_PrintThreadStats (SDL_Thread *thread) { + int startTime; +#endif /* PROFILE_THREADS */ + struct _thread *next; +} *TrueThread; + +static volatile TrueThread threadQueue = NULL; +static SDL_mutex *threadQueueMutex; + +struct ThreadStartInfo +{ + ThreadFunction func; + void *data; + SDL_sem *sem; + TrueThread thread; +}; + +#ifdef PROFILE_THREADS +static void +SigUSR1Handler (int signr) { + if (getpgrp () != getpid ()) + { + // Only act for the main process + return; + } + PrintThreadsStats (); + // It's not a good idea in general to do many things in a signal + // handler, (and especially the locking) but I guess it will + // have to do for now (and it's only for debugging). + (void) signr; /* Satisfying compiler (unused parameter) */ +} + +static void +LocalStats (SDL_Thread *thread) { #if defined (WIN32) || !defined(SDL_PTHREADS) fprintf (stderr, "Thread ID %u\n", SDL_GetThreadID (thread)); #else /* !defined (WIN32) && defined(SDL_PTHREADS) */ @@ -45,74 +85,327 @@ SDLWrapper_PrintThreadStats (SDL_Thread *thread) { seconds / 60, seconds % 60); #endif /* defined (WIN32) && defined(SDL_PTHREADS) */ } -#endif void -SDLWrapper_SleepThread (TimeCount sleepTime) +PrintThreadsStats_SDL (void) +{ + TrueThread ptr; + int now; + + now = GetTimeCounter (); + SDL_mutexP (threadQueueMutex); + fprintf(stderr, "--- Active threads ---\n"); + for (ptr = threadQueue; ptr != NULL; ptr = ptr->next) { + fprintf (stderr, "Thread named '%s'.\n", ptr->name); + fprintf (stderr, "Started %d.%d minutes ago.\n", + (now - ptr->startTime) / 60000, + ((now - ptr->startTime) / 1000) % 60); + LocalStats (ptr->native); + if (ptr->next != NULL) + fprintf(stderr, "\n"); + } + SDL_mutexV (threadQueueMutex); + fprintf(stderr, "----------------------\n"); + fflush (stderr); +} +#endif /* PROFILE_THREADS */ + +void +InitThreadSystem_SDL (void) +{ + threadQueueMutex = SDL_CreateMutex (); +#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 + SDL_DestroyMutex (threadQueueMutex); +} + +static void +QueueThread (TrueThread thread) +{ + SDL_mutexP (threadQueueMutex); + thread->next = threadQueue; + threadQueue = thread; + SDL_mutexV (threadQueueMutex); +} + +static void +UnQueueThread (TrueThread thread) +{ + volatile TrueThread *ptr; + + ptr = &threadQueue; + SDL_mutexP (threadQueueMutex); + while (*ptr != thread) + { +#ifdef DEBUG_THREADS + if (*ptr == NULL) + { + // Should not happen. + fprintf (stderr, "Error: Trying to remove non-present thread " + "from thread queue.\n"); + fflush (stderr); + abort(); + } +#endif /* DEBUG_THREADS */ + ptr = &(*ptr)->next; + } + *ptr = (*ptr)->next; + SDL_mutexV (threadQueueMutex); +} + +static TrueThread +FindThreadInfo (Uint32 threadID) +{ + TrueThread ptr; + + ptr = threadQueue; + SDL_mutexP (threadQueueMutex); + while (ptr) + { + if (SDL_GetThreadID (ptr->native) == threadID) + { + SDL_mutexV (threadQueueMutex); + return ptr; + } + ptr = ptr->next; + } + SDL_mutexV (threadQueueMutex); + return NULL; +} + +#ifdef NAMED_SYNCHRO +static const char * +MyThreadName (void) +{ + TrueThread t = FindThreadInfo (SDL_ThreadID ()); + return t ? t->name : "Unknown (probably renderer)"; +} +#endif + +static int +ThreadHelper (void *startInfo) { + ThreadFunction func; + void *data; + SDL_sem *sem; + TrueThread thread; + int result; + + func = ((struct ThreadStartInfo *) startInfo)->func; + data = ((struct ThreadStartInfo *) startInfo)->data; + sem = ((struct ThreadStartInfo *) startInfo)->sem; + + // Wait until the Thread structure is available. + SDL_SemWait (sem); + SDL_DestroySemaphore (sem); + thread = ((struct ThreadStartInfo *) startInfo)->thread; + HFree (startInfo); + + result = (*func) (data); + +#ifdef DEBUG_THREADS + fprintf (stderr, "Thread '%s' done (returned %d).\n", + thread->name, result); + fflush (stderr); +#endif + + UnQueueThread (thread); + + HFree (thread); + return result; +} + +Thread +CreateThread_SDL (ThreadFunction func, void *data, SDWORD stackSize +#ifdef NAMED_SYNCHRO + , const char *name +#endif + ) +{ + TrueThread thread; + struct ThreadStartInfo *startInfo; + + thread = (struct _thread *) HMalloc (sizeof *thread); +#ifdef NAMED_SYNCHRO + thread->name = name; +#endif +#ifdef PROFILE_THREADS + thread->startTime = GetTimeCounter (); +#endif + + startInfo = (struct ThreadStartInfo *) HMalloc (sizeof (*startInfo)); + startInfo->func = func; + startInfo->data = data; + startInfo->sem = SDL_CreateSemaphore (0); + startInfo->thread = thread; + + thread->native = SDL_CreateThread (ThreadHelper, (void *) startInfo); + if (!(thread->native)) + { + HFree (startInfo); + HFree (thread); + return NULL; + } + // The responsibility to free 'startInfo' and 'thread' is now by the new + // thread. + + QueueThread (thread); + +#ifdef DEBUG_THREADS + fprintf (stderr, "Thread '%s' created.\n", ThreadName (thread)); + fflush (stderr); +#endif + + // Signal to the new thread that the thread structure is ready + // and it can begin to use it. + SDL_SemPost (startInfo->sem); + + (void) stackSize; /* Satisfying compiler (unused parameter) */ + return thread; +} + +void +SleepThread_SDL (TimeCount sleepTime) { SDL_Delay (sleepTime * 1000 / ONE_SECOND); } void -SDLWrapper_SleepThreadUntil (TimeCount wakeTime) { +SleepThreadUntil_SDL (TimeCount wakeTime) { TimeCount now; now = GetTimeCounter (); if (wakeTime <= now) - SDLWrapper_TaskSwitch (); + TaskSwitch_SDL (); else SDL_Delay ((wakeTime - now) * 1000 / ONE_SECOND); } -int -SDLWrapper_TimeoutSetSemaphore (Semaphore sem, TimePeriod timeout) { - return SDL_SemWaitTimeout (sem, timeout * 1000 / ONE_SECOND); -} - void -SDLWrapper_TaskSwitch (void) { +TaskSwitch_SDL (void) { SDL_Delay (1); } void -SDLWrapper_WaitCondVar (CondVar cv) { - int result; - Mutex temp = CreateMutex (); - LockMutex (temp); - result = SDL_CondWait (cv, temp); - UnlockMutex (temp); - DestroyMutex (temp); - if (result != 0) { - fprintf (stderr, "Error result from SDL_CondWait: %d\n", result); +WaitThread_SDL (Thread thread, int *status) { + SDL_WaitThread (((TrueThread)thread)->native, status); +} + +/* 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. */ + +/* Semaphores. */ + +typedef struct _sem { + SDL_sem *sem; +#ifdef NAMED_SYNCHRO + const char *name; +#endif +} Sem; + +Semaphore +CreateSemaphore_SDL (DWORD initial +#ifdef NAMED_SYNCHRO + , const char *name +#endif + ) +{ + Sem *sem = (Sem *) HMalloc (sizeof (struct _sem)); +#ifdef NAMED_SYNCHRO + sem->name = name; +#endif + sem->sem = SDL_CreateSemaphore (initial); + return sem; +} + +void +DestroySemaphore_SDL (Semaphore s) +{ + Sem *sem = (Sem *)s; + SDL_DestroySemaphore (sem->sem); + HFree (sem); +} + +void +SetSemaphore_SDL (Semaphore s) +{ + Sem *sem = (Sem *)s; +#ifdef TRACK_CONTENTION + BOOLEAN contention = !(SDL_SemValue (sem->sem)); + if (contention) + { + fprintf (stderr, "Thread '%s' goes to sleep, waiting on semaphore '%s'\n", MyThreadName (), sem->name); + } +#endif + while (SDL_SemWait (sem->sem) == -1) + { + TaskSwitch_SDL (); + } +#ifdef TRACK_CONTENTION + if (contention) + { + fprintf (stderr, "Thread '%s' awakens, released from semaphore '%s'\n", MyThreadName (), sem->name); + } +#endif +} + +void +ClearSemaphore_SDL (Semaphore s) +{ + Sem *sem = (Sem *)s; + while (SDL_SemPost (sem->sem) == -1) + { + TaskSwitch_SDL (); } } -/* Code for recursive mutexes. Adapted from mixSDL code, which was adapted from the - original DCQ code. */ -/* TODO: Make these be forwarded calls instead of just implementations of threadlib.h functions. */ -/* TODO: Remove the names when compiling under release mode. */ +/* Recursive mutexes. Adapted from mixSDL code, which was adapted from + the original DCQ code. */ typedef struct _recm { SDL_mutex *mutex; Uint32 thread_id; Uint32 locks; +#ifdef NAMED_SYNCHRO const char *name; +#endif } RecM; RecursiveMutex -CreateRecursiveMutex (const char *name) +#ifdef NAMED_SYNCHRO +CreateRecursiveMutex_SDL (const char *name) +#else +CreateRecursiveMutex_SDL (void) +#endif { RecM *mtx = (RecM *) HMalloc (sizeof (struct _recm)); mtx->thread_id = 0; mtx->mutex = SDL_CreateMutex (); +#ifdef NAMED_SYNCHRO mtx->name = name; +#endif mtx->locks = 0; return (RecursiveMutex) mtx; } void -DestroyRecursiveMutex (RecursiveMutex val) +DestroyRecursiveMutex_SDL (RecursiveMutex val) { RecM *mtx = (RecM *)val; SDL_DestroyMutex (mtx->mutex); @@ -120,27 +413,35 @@ DestroyRecursiveMutex (RecursiveMutex val) } void -LockRecursiveMutex (RecursiveMutex val) +LockRecursiveMutex_SDL (RecursiveMutex val) { RecM *mtx = (RecM *)val; Uint32 thread_id = SDL_ThreadID(); if (mtx->thread_id != thread_id) { +#ifdef TRACK_CONTENTION + if (mtx->thread_id) + { + fprintf (stderr, "Thread '%s' blocking on '%s'\n", MyThreadName (), mtx->name); + } +#endif while (SDL_mutexP (mtx->mutex)) - TaskSwitch (); + TaskSwitch_SDL (); mtx->thread_id = thread_id; } mtx->locks++; } void -UnlockRecursiveMutex (RecursiveMutex val) +UnlockRecursiveMutex_SDL (RecursiveMutex val) { RecM *mtx = (RecM *)val; Uint32 thread_id = SDL_ThreadID(); if (mtx->thread_id != thread_id) { - fprintf (stderr, "%8x attempted to unlock %s when it didn't hold it\n", thread_id, mtx->name); +#ifdef NAMED_SYNCHRO + fprintf (stderr, "'%s' attempted to unlock %s when it didn't hold it\n", MyThreadName (), mtx->name); +#endif } else { @@ -154,85 +455,88 @@ UnlockRecursiveMutex (RecursiveMutex val) } int -GetRecursiveMutexDepth (RecursiveMutex val) +GetRecursiveMutexDepth_SDL (RecursiveMutex val) { RecM *mtx = (RecM *)val; return mtx->locks; } -/* Code for cross-thread mutexes. The prototypes for these functions are in threadlib.h. */ - -typedef struct _ctm { +typedef struct _cond { + SDL_cond *cond; SDL_mutex *mutex; - SDL_cond *cond; +#ifdef NAMED_SYNCHRO const char *name; - Uint32 locker; -} _NativeCTM; +#endif +} cvar; -CrossThreadMutex -CreateCrossThreadMutex (const char *name) +CondVar +#ifdef NAMED_SYNCHRO +CreateCondVar_SDL (const char *name) +#else +CreateCondVar_SDL (void) +#endif { - _NativeCTM *result = HMalloc (sizeof (_NativeCTM)); - result->mutex = SDL_CreateMutex (); - result->cond = SDL_CreateCond (); - result->name = name; - result->locker = 0; - return (CrossThreadMutex)result; + cvar *cv = (cvar *) HMalloc (sizeof (cvar)); + cv->cond = SDL_CreateCond (); + cv->mutex = SDL_CreateMutex (); +#ifdef NAMED_SYNCHRO + cv->name = name; +#endif + return cv; } void -DestroyCrossThreadMutex (CrossThreadMutex val) +DestroyCondVar_SDL (CondVar c) { - _NativeCTM *ctm = (_NativeCTM *)val; - if (ctm) - { - SDL_DestroyMutex (ctm->mutex); - SDL_DestroyCond (ctm->cond); - HFree (ctm); - } -} - -int -LockCrossThreadMutex (CrossThreadMutex val) -{ - _NativeCTM *ctm = (_NativeCTM *)val; - if (SDL_mutexP (ctm->mutex)) - { - fprintf (stderr, "LockCrossThreadMutex failed to lock internal mutex in %s!\n", ctm->name); - return -1; - } - while (ctm->locker) - { - // fprintf (stderr, "Thread %8x goes to sleep, waiting on %s\n", SDL_ThreadID (), ctm->name); - SDL_CondWait (ctm->cond, ctm->mutex); - // fprintf (stderr, "Thread %8x awakens, acquires %s.\n", SDL_ThreadID (), ctm->name); - } - ctm->locker = SDL_ThreadID (); - SDL_mutexV (ctm->mutex); - return 0; /* success */ + cvar *cv = (cvar *) c; + SDL_DestroyCond (cv->cond); + SDL_DestroyMutex (cv->mutex); + HFree (cv); } void -UnlockCrossThreadMutex (CrossThreadMutex val) +WaitCondVar_SDL (CondVar c) { - _NativeCTM *ctm = (_NativeCTM *)val; - if (SDL_mutexP (ctm->mutex)) + cvar *cv = (cvar *) c; + SDL_mutexP (cv->mutex); +#ifdef TRACK_CONTENTION + fprintf (stderr, "Thread '%s' waiting for signal from '%s'\n", MyThreadName (), cv->name); +#endif + while (SDL_CondWait (cv->cond, cv->mutex) != 0) { - fprintf (stderr, "UnlockCrossThreadMutex failed to lock internal mutex in %s!\n", ctm->name); - return; + TaskSwitch_SDL (); } - if (ctm->locker) - { - if (ctm->locker != SDL_ThreadID ()) - { - fprintf (stderr, "Cross-thread unlock on %s.\n", ctm->name); - } - ctm->locker = 0; - SDL_CondSignal (ctm->cond); - } - else - { - fprintf (stderr, "Double unlock attempt on %s ignored.\n", ctm->name); - } - SDL_mutexV (ctm->mutex); +#ifdef TRACK_CONTENTION + 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) +{ + cvar *cv = (cvar *) c; + SDL_CondSignal (cv->cond); +} + +void +BroadcastCondVar_SDL (CondVar c) +{ + cvar *cv = (cvar *) c; + SDL_CondBroadcast (cv->cond); } diff --git a/sc2/src/sc2code/libs/threads/sdl/sdlthreads.h b/sc2/src/sc2code/libs/threads/sdl/sdlthreads.h index 8f2e9560f..728eecc85 100644 --- a/sc2/src/sc2code/libs/threads/sdl/sdlthreads.h +++ b/sc2/src/sc2code/libs/threads/sdl/sdlthreads.h @@ -25,51 +25,8 @@ #include "libs/threadlib.h" #include "libs/timelib.h" -typedef SDL_Thread *NativeThread; -typedef int (*NativeThreadFunction) (void *); -#define NativeInitThreadSystem() -#define NativeUnInitThreadSystem() -#define NativeCreateThread(func, data, stackSize) \ - SDL_CreateThread ((func), (data)) -extern void SDLWrapper_SleepThread (TimeCount sleepTime); -#define NativeSleepThread(sleepTime) \ - SDLWrapper_SleepThread ((sleepTime)) -extern void SDLWrapper_SleepThreadUntil (TimeCount wakeTime); -#define NativeSleepThreadUntil(wakeTime) \ - SDLWrapper_SleepThreadUntil ((wakeTime)) -extern void SDLWrapper_TaskSwitch (void); -#define NativeTaskSwitch() \ - SDLWrapper_TaskSwitch() -#define NativeWaitThread(thread, status) \ - SDL_WaitThread ((thread), (status)) #define NativeGetThreadID(thread) SDL_GetThreadID ((thread)) #define NativeThreadID() SDL_ThreadID () -#ifdef PROFILE_THREADS -extern void SDLWrapper_PrintThreadStats (SDL_Thread *thread); -#define NativePrintThreadStats(thread) \ - SDLWrapper_PrintThreadStats ((thread)) -#endif -#define NativeThreadOk(thread) \ - ((thread) != NULL) - -typedef SDL_sem *NativeSemaphore; -#define NativeCreateSemaphore(initial) \ - SDL_CreateSemaphore ((initial)) -#define NativeDestroySemaphore(sem) \ - SDL_DestroySemaphore ((sem)) -#define NativeSetSemaphore(sem) \ - SDL_SemWait ((sem)) -#define NativeTrySetSemaphore(sem) \ - SDL_SemTryWait ((sem)) -#define NativeSemValue(sem) \ - SDL_SemValue ((sem)) -#define NATIVE_MUTEX_TIMEOUT SDL_MUTEX_TIMEDOUT -extern int SDLWrapper_TimeoutSetSemaphore (Semaphore sem, - TimePeriod timeperiod); -#define NativeTimeoutSetSemaphore(sem, timeperiod) \ - SDLWrapper_TimeoutSetSemaphore ((sem), timeperiod) -#define NativeClearSemaphore(sem) \ - SDL_SemPost ((sem)) typedef SDL_mutex *NativeMutex; #define NativeCreateMutex() \ @@ -81,23 +38,72 @@ typedef SDL_mutex *NativeMutex; #define NativeUnlockMutex(mutex) \ SDL_mutexV ((mutex)) -typedef SDL_cond *NativeCondVar; -#define NativeCreateCondVar() \ - SDL_CreateCond () -#define NativeDestroyCondVar(condvar) \ - SDL_DestroyCond ((condvar)) -extern void SDLWrapper_WaitCondVar (CondVar candvar); -#define NativeWaitCondVar(condvar) \ - SDLWrapper_WaitCondVar ((condvar)) -#define NativeWaitProtectedCondVar(condvar, mutex) \ - SDL_CondWait ((condvar), (mutex)) -#define NativeSignalCondVar(condvar) \ - SDL_CondSignal ((condvar)) -#define NativeBroadcastCondVar(condvar) \ - SDL_CondBroadcast ((condvar)) - #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); +#else +/* Prototypes without the "name" field. */ +Thread CreateThread_SDL (ThreadFunction func, void *data, SDWORD stackSize); +Semaphore CreateSemaphore_SDL (DWORD initial); +RecursiveMutex CreateRecursiveMutex_SDL (void); +CondVar CreateCondVar_SDL (void); +#endif + +void SleepThread_SDL (TimeCount sleepTime); +void SleepThreadUntil_SDL (TimeCount wakeTime); +void TaskSwitch_SDL (void); +void WaitThread_SDL (Thread thread, int *status); + +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); + +void DestroyRecursiveMutex_SDL (RecursiveMutex m); +void LockRecursiveMutex_SDL (RecursiveMutex m); +void UnlockRecursiveMutex_SDL (RecursiveMutex m); +int GetRecursiveMutexDepth_SDL (RecursiveMutex m); + +#define NativeInitThreadSystem InitThreadSystem_SDL +#define NativeUnInitThreadSystem UnInitThreadSystem_SDL + +#define NativeCreateThread CreateThread_SDL +#define NativeSleepThread SleepThread_SDL +#define NativeSleepThreadUntil SleepThreadUntil_SDL +#define NativeTaskSwitch TaskSwitch_SDL +#define NativeWaitThread WaitThread_SDL + +#define NativeCreateSemaphore CreateSemaphore_SDL +#define NativeDestroySemaphore DestroySemaphore_SDL +#define NativeSetSemaphore SetSemaphore_SDL +#define NativeClearSemaphore ClearSemaphore_SDL + +#define NativeCreateCondVar CreateCondVar_SDL +#define NativeDestroyCondVar DestroyCondVar_SDL +#define NativeWaitCondVar WaitCondVar_SDL +#define NativeWaitProtectedCondVar WaitProtectedCondVar_SDL +#define NativeSignalCondVar SignalCondVar_SDL +#define NativeBroadcastCondVar BroadcastCondVar_SDL + +#define NativeCreateRecursiveMutex CreateRecursiveMutex_SDL +#define NativeDestroyRecursiveMutex DestroyRecursiveMutex_SDL +#define NativeLockRecursiveMutex LockRecursiveMutex_SDL +#define NativeUnlockRecursiveMutex UnlockRecursiveMutex_SDL +#define NativeGetRecursiveMutexDepth GetRecursiveMutexDepth_SDL + #endif /* _SDLTHREAD_H */ diff --git a/sc2/src/sc2code/libs/threads/thrcommon.c b/sc2/src/sc2code/libs/threads/thrcommon.c index ce7cc19da..50275953b 100644 --- a/sc2/src/sc2code/libs/threads/thrcommon.c +++ b/sc2/src/sc2code/libs/threads/thrcommon.c @@ -22,249 +22,90 @@ #include "libs/timelib.h" #include "libs/misc.h" #include "thrcommon.h" -#ifdef PROFILE_THREADS -#include -#include -#endif - -#ifdef DEBUG_TRACK_SEM -#include -// The semaphore tracker looks for possible semaphore issues. -// It will report semaphores cleared by threads other than what set them -// and when the semaphore value is larger than 1 -#define NUM_SEMAPHORES 50 -// Set the timeout to 60 seconds -#define SEM_TIMEOUT 6000 -#undef DEBUG_SEM_DEADLOCK -typedef struct { - Semaphore Sem; - Uint32 Thread; - char Name[20]; -#if defined (THREAD_QUEUE) && defined (THREAD_NAMES) - char ThreadName[20]; -#endif -} MonitorSem; -Semaphore SemMutex; -static MonitorSem SemMon[NUM_SEMAPHORES]; -static UWORD numSems = 0; -#endif - -#ifdef THREAD_QUEUE -static volatile Thread threadQueue = NULL; -static Semaphore threadQueueSemaphore; -#endif - - -struct ThreadStartInfo -{ - ThreadFunction func; - void *data; - Semaphore sem; - Thread thread; -}; - -#ifdef PROFILE_THREADS -static void -SigUSR1Handler (int signr) { - if (getpgrp () != getpid ()) - { - // Only act for the main process - return; - } - PrintThreadsStats (); - // It's not a good idea in general to do many things in a signal - // handler, (and especially the locking) but I guess it will - // have to do for now (and it's only for debugging). - (void) signr; /* Satisfying compiler (unused parameter) */ -} -#endif void InitThreadSystem (void) { -#ifdef THREAD_QUEUE - threadQueueSemaphore = CreateSemaphore (1, "ThreadQueue"); -#endif /* THREAD_QUEUE */ -#ifdef PROFILE_THREADS - signal(SIGUSR1, SigUSR1Handler); -#endif NativeInitThreadSystem (); - init_cond_bank (); } void UnInitThreadSystem (void) { - uninit_cond_bank (); NativeUnInitThreadSystem (); -#ifdef PROFILE_THREADS - signal(SIGUSR1, SIG_DFL); -#endif -#ifdef THREAD_QUEUE - DestroySemaphore (threadQueueSemaphore); -#endif /* THREAD_QUEUE */ } -#ifdef THREAD_QUEUE -static void -QueueThread (Thread thread) -{ - SetSemaphore (threadQueueSemaphore); - thread->next = threadQueue; - threadQueue = thread; - ClearSemaphore (threadQueueSemaphore); -} - -static void -UnQueueThread (Thread thread) -{ - volatile Thread *ptr; - - ptr = &threadQueue; - SetSemaphore (threadQueueSemaphore); - while (*ptr != thread) - { -#ifdef DEBUG_THREADS - if (*ptr == NULL) - { - // Should not happen. - fprintf (stderr, "Error: Trying to remove non-present thread " - "from thread queue.\n"); - fflush (stderr); - abort(); - } -#endif /* DEBUG_THREADS */ - ptr = &(*ptr)->next; - } - *ptr = (*ptr)->next; - ClearSemaphore (threadQueueSemaphore); -} -#endif /* THREAD_QUEUE */ - -#if defined (DEBUG_TRACK_SEM) && defined (THREAD_QUEUE) \ - && defined (THREAD_NAMES) -static char *ThreadNameNative (Uint32 native) -{ - volatile Thread ptr; - - if (threadQueueSemaphore) - NativeSetSemaphore (threadQueueSemaphore); - ptr = threadQueue; - while (ptr && NativeGetThreadID (ptr->native) != native) - { - ptr = ptr->next; - } - if(threadQueueSemaphore) - NativeClearSemaphore (threadQueueSemaphore); - if (ptr) - return ((char *)ptr->name); - else - return (NULL); -} -#endif /* DEBUG_TRACK_SEM */ - -#ifdef DEBUG_THREADS -static const char * -ThreadName(Thread thread) { -#if defined (THREAD_QUEUE) && defined (THREAD_NAMES) - return thread->name; -#else - return "<>"; -#endif /* !defined (THREAD_QUEUE) || !defined (THREAD_NAMES) */ -} -#endif - -static int -ThreadHelper (void *startInfo) { - ThreadFunction func; - void *data; - Semaphore sem; - Thread thread; - int result; - - func = ((struct ThreadStartInfo *) startInfo)->func; - data = ((struct ThreadStartInfo *) startInfo)->data; - sem = ((struct ThreadStartInfo *) startInfo)->sem; - - // Wait until the Thread structure is available. - while (SetSemaphore (sem) == -1) - ; - DestroySemaphore (sem); - thread = ((struct ThreadStartInfo *) startInfo)->thread; - HFree (startInfo); - - result = (*(NativeThreadFunction) func) (data); - -#ifdef DEBUG_THREADS - fprintf (stderr, "Thread '%s' done (returned %d).\n", - ThreadName (thread), result); - fflush (stderr); -#endif - -#ifdef THREAD_QUEUE - UnQueueThread (thread); -#endif /* THREAD_QUEUE */ - - HFree (thread); - return result; -} +/* The Create routines look different based on whether NAMED_SYNCHRO + is defined or not. */ +#ifdef NAMED_SYNCHRO Thread -CreateThreadAux (ThreadFunction func, void *data, SDWORD stackSize -#ifdef THREAD_NAMES - , const char *name -#endif - ) +CreateThread_Core (ThreadFunction func, void *data, SDWORD stackSize, const char *name) { - Thread thread; - struct ThreadStartInfo *startInfo; - - thread = (struct Thread *) HMalloc (sizeof *thread); -#ifdef THREAD_NAMES - thread->name = name; -#endif -#ifdef PROFILE_THREADS - thread->startTime = GetTimeCounter (); -#endif - - startInfo = (struct ThreadStartInfo *) HMalloc (sizeof (*startInfo)); - startInfo->func = func; - startInfo->data = data; - startInfo->sem = CreateSemaphore (0, "StartThread"); - startInfo->thread = thread; - - thread->native = NativeCreateThread (ThreadHelper, (void *) startInfo, - stackSize ? stackSize + 32 : 0); - if (!NativeThreadOk (thread->native)) - { - HFree (startInfo); - HFree (thread); - return NULL; - } - // The responsibility to free 'startInfo' and 'thread' is now by the new - // thread. - -#ifdef THREAD_QUEUE - QueueThread (thread); -#endif /* THREAD_QUEUE */ - -#ifdef DEBUG_THREADS - fprintf (stderr, "Thread '%s' created.\n", ThreadName (thread)); - fflush (stderr); -#endif - - // Signal to the new thread that the thread structure is ready - // and it can begin to use it. - ClearSemaphore (startInfo->sem); - - (void) stackSize; /* Satisfying compiler (unused parameter) */ - return thread; + return NativeCreateThread (func, data, stackSize, name); } +Mutex +CreateMutex_Core (void) +{ + return (Mutex) NativeCreateMutex (); +} + +Semaphore +CreateSemaphore_Core (DWORD initial, const char *name) +{ + return NativeCreateSemaphore (initial, name); +} + +RecursiveMutex +CreateRecursiveMutex_Core (const char *name) +{ + return NativeCreateRecursiveMutex (name); +} + +CondVar +CreateCondVar_Core (const char *name) +{ + return NativeCreateCondVar (name); +} + +#else +/* These are the versions of Create* without the names. */ +Thread +CreateThread_Core (ThreadFunction func, void *data, SDWORD stackSize) +{ + return NativeCreateThread (func, data, stackSize); +} + +Mutex +CreateMutex_Core (void) +{ + return (Mutex) NativeCreateMutex (); +} + +Semaphore +CreateSemaphore_Core (DWORD initial) +{ + return NativeCreateSemaphore (initial); +} + +RecursiveMutex +CreateRecursiveMutex_Core (void) +{ + return NativeCreateRecursiveMutex (); +} + +CondVar +CreateCondVar_Core (void) +{ + return NativeCreateCondVar (); +} +#endif + void WaitThread (Thread thread, int *status) { - NativeWaitThread (thread->native, status); + NativeWaitThread (thread, status); } void @@ -285,292 +126,19 @@ TaskSwitch (void) NativeTaskSwitch (); } -#ifdef PROFILE_THREADS -// PROFILE_THREADS implies THREAD_QUEUES -void -PrintThreadsStats (void) -{ - Thread ptr; - int now; - - now = GetTimeCounter (); - SetSemaphore (threadQueueSemaphore); - fprintf(stderr, "--- Active threads ---\n"); - for (ptr = threadQueue; ptr != NULL; ptr = ptr->next) { -#ifndef THREAD_NAMES - fprintf (stderr, "(Thread name not available).\n"); -#else - fprintf (stderr, "Thread named '%s'.\n", ptr->name); -#endif - fprintf (stderr, "Started %d.%d minutes ago.\n", - (now - ptr->startTime) / 60000, - ((now - ptr->startTime) / 1000) % 60); - NativePrintThreadStats (ptr->native); - if (ptr->next != NULL) - fprintf(stderr, "\n"); - } - ClearSemaphore (threadQueueSemaphore); - fprintf(stderr, "----------------------\n"); - fflush (stderr); -} -#endif /* PROFILE_THREADS */ - -Semaphore -CreateSemaphoreAux (DWORD initial -#ifdef DEBUG_TRACK_SEM - , const char *sem_name -#endif - ) -{ - Semaphore sem = (Semaphore)NativeCreateSemaphore (initial); -#ifdef DEBUG_TRACK_SEM - int pos; - if (SemMutex == 0) - SemMutex = NativeCreateSemaphore (0); - else - NativeSetSemaphore (SemMutex); - for (pos = 0; pos < numSems; pos++) - if (SemMon[pos].Sem == 0) - break; - if (pos == numSems) - { - numSems++; - if (numSems == NUM_SEMAPHORES) - { - fprintf(stderr, "Error: We ran out of semaphores. aborting!\n"); - NativeClearSemaphore (SemMutex); - return (0); - } - } - SemMon[pos].Sem = sem; - SemMon[pos].Thread = 0; - strncpy(SemMon[pos].Name, sem_name, 20); - SemMon[pos].Name[19] = 0; -#if defined (THREAD_QUEUE) && defined (THREAD_NAMES) -// fprintf (stderr, "Created Semaphore # %d: %s in thread '%s'\n", -// numSems, SemMon[pos].Name, ThreadNameNative (NativeThreadID ())); -#else -// fprintf (stderr, "Created Semaphore # %d: %s\n", -// numSems, SemMon[pos].Name); -#endif - NativeClearSemaphore (SemMutex); -#endif - return (sem); -} - -void -DestroySemaphore (Semaphore sem) -{ -#ifdef DEBUG_TRACK_SEM - int i; - NativeSetSemaphore (SemMutex); - for (i = 0; i w = vid->decoder->w; vid->h = vid->decoder->h; vid->guard = CreateMutex (); - vid->frame_lock = CreateCondVar (); + vid->frame_lock = CreateCondVar ("frame lock"); return (VIDEO_REF) vid; } diff --git a/sc2/src/sc2code/libs/video/vidplayer.c b/sc2/src/sc2code/libs/video/vidplayer.c index c41515c23..1c4afdefb 100644 --- a/sc2/src/sc2code/libs/video/vidplayer.c +++ b/sc2/src/sc2code/libs/video/vidplayer.c @@ -308,7 +308,6 @@ TFB_PlayVideo (VIDEO_REF VidRef, uint32 x, uint32 y) if (!vid->play_task) { vid->playing = false; - //UnlockCrossThreadMutex (vid->frame_lock); ClearSemaphore (vp_interthread_lock); TFB_StopVideo (VidRef); diff --git a/sc2/src/sc2code/load.c b/sc2/src/sc2code/load.c index 49a2221cb..7af4b0e86 100644 --- a/sc2/src/sc2code/load.c +++ b/sc2/src/sc2code/load.c @@ -96,7 +96,7 @@ LoadGame (COUNT which_game, SUMMARY_DESC *summary_desc) uio_Stream *fp; DECODE_REF fh; COUNT num_links; - CrossThreadMutex clock_lock; + Semaphore clock_sem; Task clock_task; QUEUE event_q, encounter_q, avail_q, npc_q, player_q; STAR_DESC SD; @@ -126,7 +126,7 @@ LoadGame (COUNT which_game, SUMMARY_DESC *summary_desc) ReinitQueue (&GLOBAL (npc_built_ship_q)); ReinitQueue (&GLOBAL (built_ship_q)); - clock_lock = GLOBAL (GameClock.clock_lock); + clock_sem = GLOBAL (GameClock.clock_sem); clock_task = GLOBAL (GameClock.clock_task); event_q = GLOBAL (GameClock.event_q); encounter_q = GLOBAL (encounter_q); @@ -141,7 +141,7 @@ LoadGame (COUNT which_game, SUMMARY_DESC *summary_desc) NextActivity = GLOBAL (CurrentActivity); GLOBAL (CurrentActivity) = Activity; - GLOBAL (GameClock.clock_lock) = clock_lock; + GLOBAL (GameClock.clock_sem) = clock_sem; GLOBAL (GameClock.clock_task) = clock_task; GLOBAL (GameClock.event_q) = event_q; GLOBAL (encounter_q) = encounter_q; diff --git a/sc2/src/sc2code/starcon.c b/sc2/src/sc2code/starcon.c index adce001d3..5f70befb7 100644 --- a/sc2/src/sc2code/starcon.c +++ b/sc2/src/sc2code/starcon.c @@ -46,7 +46,7 @@ int arilou_gate_task(void* data) counter = GET_GAME_STATE (ARILOU_SPACE_COUNTER); while (!Task_ReadState (task, TASK_EXIT)) { - LockCrossThreadMutex (GLOBAL (GameClock.clock_lock)); + SetSemaphore (GLOBAL (GameClock.clock_sem)); if (GET_GAME_STATE (ARILOU_SPACE) == OPENING) { @@ -63,7 +63,7 @@ int arilou_gate_task(void* data) SET_GAME_STATE (ARILOU_SPACE_COUNTER, counter); UnlockMutex (GraphicsLock); - UnlockCrossThreadMutex (GLOBAL (GameClock.clock_lock)); + ClearSemaphore (GLOBAL (GameClock.clock_sem)); SleepThreadUntil (TimeIn + BATTLE_FRAME_RATE); TimeIn = GetTimeCounter (); } diff --git a/sc2/src/starcon2.c b/sc2/src/starcon2.c index 6111d4e78..0130b00f9 100644 --- a/sc2/src/starcon2.c +++ b/sc2/src/starcon2.c @@ -134,12 +134,14 @@ main (int argc, char *argv[]) contentDir = "content"; #endif - /* InitThreadSystem should come before anything else. - * The memory system uses semaphores. - * Everything else uses the memory system. - */ - InitThreadSystem (); + + /* mem_init () uses mutexes. Mutex creation cannot use + the memory system until the memory system is rewritten + to rely on a thread-safe allocator. + */ + TFB_PreInit (); mem_init (); + InitThreadSystem (); addons = HMalloc(1 * sizeof (const char *)); addons[0] = NULL; @@ -349,7 +351,7 @@ main (int argc, char *argv[]) InitTaskSystem (); GraphicsLock = CreateMutex (/*"Graphics"*/); - RenderingCond = CreateCondVar (); + RenderingCond = CreateCondVar ("DCQ empty"); TFB_InitGraphics (gfxdriver, gfxflags, width, height, bpp); init_communication ();