Threadlib refactoring, phase 1
All constructs, save Mutexes, can carry names. (Mutexes will carry them once HMalloc doesn't require a Mutex.) All constructs are now opaque to the game logic. Some limited upcalls will be added in phase 2 so that the game logic can initialize some thread-local data in a backend-independent way. DEBUG_TRACK_SEM is gone. In its place are NAMED_SYNCHRO (which names synchronization constructs) and TRACK_CONTENTION (which reports when threads go to sleep because of synchronization constructs.) Again, Mutexes are immune. A lot of conditionally compiled code in the threadlib was collated, dramatically reducing the number of preprocessing directives. The exposed (threadlib.h) and backend (sdlthreads.h) APIs match one another more closely now, further reducing the level of preprocessor work required. git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@1255 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
#endif
|
||||
#ifdef PROFILE_THREADS
|
||||
int startTime;
|
||||
#endif /* PROFILE_THREADS */
|
||||
#ifdef THREAD_QUEUE
|
||||
struct Thread *next;
|
||||
#endif
|
||||
} *Thread;
|
||||
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 */
|
||||
|
||||
#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);
|
||||
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) \
|
||||
CreateThreadAux ((func), (data), (stackSize))
|
||||
#endif /* !defined(THREAD_NAMES) */
|
||||
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
|
||||
|
||||
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);
|
||||
|
||||
@@ -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 ();
|
||||
}
|
||||
|
||||
@@ -20,15 +20,55 @@
|
||||
#include <stdlib.h>
|
||||
#include "misc.h"
|
||||
#include "sdlthreads.h"
|
||||
#ifdef PROFILE_THREADS
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(PROFILE_THREADS) && !defined(WIN32)
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#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 {
|
||||
SDL_mutex *mutex;
|
||||
typedef struct _cond {
|
||||
SDL_cond *cond;
|
||||
SDL_mutex *mutex;
|
||||
#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)
|
||||
#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)
|
||||
{
|
||||
if (ctm->locker != SDL_ThreadID ())
|
||||
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)
|
||||
{
|
||||
fprintf (stderr, "Cross-thread unlock on %s.\n", ctm->name);
|
||||
cvar *cv = (cvar *) c;
|
||||
SDL_CondSignal (cv->cond);
|
||||
}
|
||||
ctm->locker = 0;
|
||||
SDL_CondSignal (ctm->cond);
|
||||
}
|
||||
else
|
||||
|
||||
void
|
||||
BroadcastCondVar_SDL (CondVar c)
|
||||
{
|
||||
fprintf (stderr, "Double unlock attempt on %s ignored.\n", ctm->name);
|
||||
}
|
||||
SDL_mutexV (ctm->mutex);
|
||||
cvar *cv = (cvar *) c;
|
||||
SDL_CondBroadcast (cv->cond);
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -22,249 +22,90 @@
|
||||
#include "libs/timelib.h"
|
||||
#include "libs/misc.h"
|
||||
#include "thrcommon.h"
|
||||
#ifdef PROFILE_THREADS
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_TRACK_SEM
|
||||
#include <string.h>
|
||||
// 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 "<<UNNAMED>>";
|
||||
#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;
|
||||
return NativeCreateThread (func, data, stackSize, name);
|
||||
}
|
||||
|
||||
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))
|
||||
Mutex
|
||||
CreateMutex_Core (void)
|
||||
{
|
||||
HFree (startInfo);
|
||||
HFree (thread);
|
||||
return NULL;
|
||||
return (Mutex) NativeCreateMutex ();
|
||||
}
|
||||
// The responsibility to free 'startInfo' and 'thread' is now by the new
|
||||
// thread.
|
||||
|
||||
#ifdef THREAD_QUEUE
|
||||
QueueThread (thread);
|
||||
#endif /* THREAD_QUEUE */
|
||||
Semaphore
|
||||
CreateSemaphore_Core (DWORD initial, const char *name)
|
||||
{
|
||||
return NativeCreateSemaphore (initial, name);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_THREADS
|
||||
fprintf (stderr, "Thread '%s' created.\n", ThreadName (thread));
|
||||
fflush (stderr);
|
||||
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
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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 <numSems; i++)
|
||||
if (SemMon[i].Sem == sem)
|
||||
{
|
||||
SemMon[i].Sem = 0;
|
||||
break;
|
||||
}
|
||||
NativeClearSemaphore (SemMutex);
|
||||
#endif
|
||||
NativeDestroySemaphore ((NativeSemaphore) sem);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TRACK_SEM
|
||||
static void debug_set_sem (Semaphore sem
|
||||
#if defined (THREAD_QUEUE) && defined (THREAD_NAMES)
|
||||
, char *name
|
||||
#endif
|
||||
)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < numSems; i++)
|
||||
{
|
||||
if (SemMon[i].Sem == sem)
|
||||
{
|
||||
SemMon[i].Thread = NativeThreadID ();
|
||||
#if defined (THREAD_QUEUE) && defined (THREAD_NAMES)
|
||||
if (name != NULL)
|
||||
{
|
||||
strncpy(SemMon[i].ThreadName,name,20);
|
||||
SemMon[i].ThreadName[19] = 0;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
SetSemaphore (Semaphore sem)
|
||||
{
|
||||
int i;
|
||||
|
||||
#if defined (DEBUG_TRACK_SEM) && defined (THREAD_QUEUE) \
|
||||
&& defined (THREAD_NAMES)
|
||||
char *name = ThreadNameNative (NativeThreadID ());
|
||||
#endif
|
||||
|
||||
#if defined (DEBUG_TRACK_SEM) && defined (DEBUG_SEM_DEADLOCK)
|
||||
do
|
||||
{
|
||||
i = NativeTimeoutSetSemaphore ((NativeSemaphore) sem, SEM_TIMEOUT);
|
||||
if (i == NATIVE_MUTEX_TIMEOUT)
|
||||
{
|
||||
int j = -1;
|
||||
for (j = 0; j < numSems; j++)
|
||||
{
|
||||
if (SemMon[j].Sem == sem)
|
||||
break;
|
||||
}
|
||||
if (j != -1)
|
||||
#if defined (THREAD_QUEUE) && defined (THREAD_NAMES)
|
||||
fprintf (stderr, "Failed to acquire '%s' semaphore in thread '%s'.\n\tIt is held by thread '%s'. Retrying\n",
|
||||
SemMon[j].Name,
|
||||
name,
|
||||
SemMon[j].ThreadName);
|
||||
#else
|
||||
fprintf (stderr, "Failed to acquire '%s' semaphore. Retrying\n",
|
||||
SemMon[j].Name);
|
||||
#endif /* THREAD_NAMES */
|
||||
}
|
||||
} while (i == NATIVE_MUTEX_TIMEOUT);
|
||||
#else
|
||||
i = NativeSetSemaphore ((NativeSemaphore) sem);
|
||||
#endif /* DEBUG_SEM_DEADLOCK */
|
||||
#ifdef DEBUG_TRACK_SEM
|
||||
if (i != 0)
|
||||
fprintf(stderr, "WARNING: SetSemaphore did not return 0, this could be bad!\n");
|
||||
#if defined (THREAD_QUEUE) && defined (THREAD_NAMES)
|
||||
debug_set_sem (sem, name);
|
||||
#else
|
||||
debug_set_sem (sem);
|
||||
#endif /* THREAD_NAMES */
|
||||
#endif /* DEBUG_TRACK_SEM */
|
||||
return i;
|
||||
}
|
||||
|
||||
int
|
||||
TrySetSemaphore (Semaphore sem)
|
||||
{
|
||||
int i;
|
||||
|
||||
#if defined (DEBUG_TRACK_SEM) && defined (THREAD_QUEUE) \
|
||||
&& defined (THREAD_NAMES)
|
||||
char *name = ThreadNameNative (NativeThreadID ());
|
||||
#endif
|
||||
|
||||
i = NativeTrySetSemaphore ((NativeSemaphore) sem);
|
||||
#ifdef DEBUG_TRACK_SEM
|
||||
if (i == 0)
|
||||
#if defined (THREAD_QUEUE) && defined (THREAD_NAMES)
|
||||
debug_set_sem (sem, name);
|
||||
#else
|
||||
debug_set_sem (sem);
|
||||
#endif /* THREAD_NAMES */
|
||||
#endif /* DEBUG_TRACK_SEM */
|
||||
return (i);
|
||||
}
|
||||
|
||||
int
|
||||
TimeoutSetSemaphore (Semaphore sem, TimePeriod timeout)
|
||||
{
|
||||
int i;
|
||||
|
||||
#if defined (DEBUG_TRACK_SEM) && defined (THREAD_QUEUE) \
|
||||
&& defined (THREAD_NAMES)
|
||||
char *name = ThreadNameNative (NativeThreadID ());
|
||||
#endif
|
||||
|
||||
i = NativeTimeoutSetSemaphore ((NativeSemaphore) sem, timeout);
|
||||
#ifdef DEBUG_TRACK_SEM
|
||||
if (i == 0)
|
||||
#if defined (THREAD_QUEUE) && defined (THREAD_NAMES)
|
||||
debug_set_sem (sem, name);
|
||||
#else
|
||||
debug_set_sem (sem);
|
||||
#endif /* THREAD_NAMES */
|
||||
#endif /* DEBUG_TRACK_SEM */
|
||||
return (i);
|
||||
}
|
||||
|
||||
DWORD
|
||||
SemaphoreValue (Semaphore sem)
|
||||
{
|
||||
return NativeSemValue (sem);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TRACK_SEM
|
||||
// Use this function to prevent messages when it is known that
|
||||
// a semaphore will be cleared by a different thread than set it
|
||||
void
|
||||
ResetSemaphoreOwnerAux (Semaphore sem)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < numSems; i++)
|
||||
if (SemMon[i].Sem == sem)
|
||||
{
|
||||
SemMon[i].Thread = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
void
|
||||
ClearSemaphore (Semaphore sem)
|
||||
{
|
||||
#ifdef DEBUG_TRACK_SEM
|
||||
int i;
|
||||
Uint32 semval = NativeSemValue (sem);
|
||||
char *sem_name = NULL;
|
||||
|
||||
for (i = 0; i < numSems; i++)
|
||||
if (SemMon[i].Sem == sem)
|
||||
{
|
||||
sem_name = SemMon[i].Name;
|
||||
if (SemMon[i].Thread && SemMon[i].Thread != NativeThreadID ())
|
||||
#if defined (THREAD_QUEUE) && defined (THREAD_NAMES)
|
||||
{
|
||||
if (ThreadNameNative (SemMon[i].Thread) == NULL)
|
||||
fprintf( stderr, "Freeing %s Semaphore in '%s' set by defunct thread '%s'!\n",
|
||||
sem_name,
|
||||
ThreadNameNative (NativeThreadID ()),
|
||||
SemMon[i].ThreadName);
|
||||
else
|
||||
fprintf( stderr, "Freeing %s Semaphore in '%s' set by thread '%s'!\n",
|
||||
sem_name,
|
||||
ThreadNameNative (NativeThreadID ()),
|
||||
ThreadNameNative (SemMon[i].Thread));
|
||||
}
|
||||
SemMon[i].ThreadName[0] = 0;
|
||||
#else
|
||||
fprintf (stderr, "Freeing %s Semaphore that was set by a different thread\n",
|
||||
sem_name);
|
||||
#endif
|
||||
SemMon[i].Thread = 0;
|
||||
break;
|
||||
}
|
||||
if (semval != 0)
|
||||
fprintf (stderr, "Incrementing semaphore '%s' (newvalue=%d)\n", sem_name, semval + 1);
|
||||
#endif
|
||||
NativeClearSemaphore ((NativeSemaphore) sem);
|
||||
}
|
||||
|
||||
Mutex
|
||||
CreateMutex ()
|
||||
{
|
||||
return (Mutex) NativeCreateMutex ();
|
||||
}
|
||||
|
||||
void
|
||||
DestroyMutex (Mutex sem)
|
||||
{
|
||||
NativeDestroyMutex ((NativeMutex) sem);
|
||||
}
|
||||
|
||||
int
|
||||
void
|
||||
LockMutex (Mutex sem)
|
||||
{
|
||||
return NativeLockMutex ((NativeMutex) sem);
|
||||
while (NativeLockMutex ((NativeMutex) sem) == -1)
|
||||
{
|
||||
TaskSwitch ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -579,40 +147,52 @@ UnlockMutex (Mutex sem)
|
||||
NativeUnlockMutex ((NativeMutex) sem);
|
||||
}
|
||||
|
||||
CondVar
|
||||
CreateCondVar ()
|
||||
void
|
||||
DestroySemaphore (Semaphore sem)
|
||||
{
|
||||
return NativeCreateCondVar ();
|
||||
NativeDestroySemaphore (sem);
|
||||
}
|
||||
|
||||
void
|
||||
SetSemaphore (Semaphore sem)
|
||||
{
|
||||
NativeSetSemaphore (sem);
|
||||
}
|
||||
|
||||
void
|
||||
ClearSemaphore (Semaphore sem)
|
||||
{
|
||||
NativeClearSemaphore (sem);
|
||||
}
|
||||
|
||||
void
|
||||
DestroyCondVar (CondVar cv)
|
||||
{
|
||||
NativeDestroyCondVar ((CondVar)cv);
|
||||
NativeDestroyCondVar (cv);
|
||||
}
|
||||
|
||||
void
|
||||
WaitCondVar (CondVar cv)
|
||||
{
|
||||
NativeWaitCondVar ((NativeCondVar)cv);
|
||||
NativeWaitCondVar (cv);
|
||||
}
|
||||
|
||||
void
|
||||
WaitProtectedCondVar (CondVar cv, Mutex m)
|
||||
{
|
||||
NativeWaitProtectedCondVar ((NativeCondVar)cv, (NativeMutex)m);
|
||||
NativeWaitProtectedCondVar (cv, m);
|
||||
}
|
||||
|
||||
void
|
||||
SignalCondVar (CondVar cv)
|
||||
{
|
||||
NativeSignalCondVar ((NativeCondVar)cv);
|
||||
NativeSignalCondVar (cv);
|
||||
}
|
||||
|
||||
void
|
||||
BroadcastCondVar (CondVar cv)
|
||||
{
|
||||
NativeBroadcastCondVar ((NativeCondVar)cv);
|
||||
NativeBroadcastCondVar (cv);
|
||||
}
|
||||
|
||||
DWORD
|
||||
@@ -620,3 +200,27 @@ CurrentThreadID ()
|
||||
{
|
||||
return (DWORD)NativeThreadID ();
|
||||
}
|
||||
|
||||
void
|
||||
DestroyRecursiveMutex (RecursiveMutex mutex)
|
||||
{
|
||||
NativeDestroyRecursiveMutex (mutex);
|
||||
}
|
||||
|
||||
void
|
||||
LockRecursiveMutex (RecursiveMutex mutex)
|
||||
{
|
||||
NativeLockRecursiveMutex (mutex);
|
||||
}
|
||||
|
||||
void
|
||||
UnlockRecursiveMutex (RecursiveMutex mutex)
|
||||
{
|
||||
NativeUnlockRecursiveMutex (mutex);
|
||||
}
|
||||
|
||||
int
|
||||
GetRecursiveMutexDepth (RecursiveMutex mutex)
|
||||
{
|
||||
return NativeGetRecursiveMutexDepth (mutex);
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ _init_video_file(PVOID pStr)
|
||||
vid->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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 ();
|
||||
}
|
||||
|
||||
+7
-5
@@ -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.
|
||||
|
||||
/* mem_init () uses mutexes. Mutex creation cannot use
|
||||
the memory system until the memory system is rewritten
|
||||
to rely on a thread-safe allocator.
|
||||
*/
|
||||
InitThreadSystem ();
|
||||
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 ();
|
||||
|
||||
Reference in New Issue
Block a user