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'
|
CHOICE_debug_OPTION_debug_ACTION='debug_action'
|
||||||
debug_action() {
|
debug_action() {
|
||||||
CFLAGS="$CFLAGS -g -O0 -W -Wall"
|
CFLAGS="$CFLAGS -g -O0 -W -Wall"
|
||||||
CFLAGS="$CFLAGS -DDEBUG_TRACK_SEM" # enable semaphore deugging
|
|
||||||
LDFLAGS="$LDFLAGS -O0"
|
LDFLAGS="$LDFLAGS -O0"
|
||||||
DEBUG=1
|
DEBUG=1
|
||||||
}
|
}
|
||||||
@@ -67,7 +66,6 @@ CHOICE_debug_OPTION_strictdebug_TITLE="Debug info + strict compile checks"
|
|||||||
CHOICE_debug_OPTION_strictdebug_ACTION='strictdebug_action'
|
CHOICE_debug_OPTION_strictdebug_ACTION='strictdebug_action'
|
||||||
strictdebug_action() {
|
strictdebug_action() {
|
||||||
CFLAGS="$CFLAGS -O1" # This is needed for -Wunitialized
|
CFLAGS="$CFLAGS -O1" # This is needed for -Wunitialized
|
||||||
CFLAGS="$CFLAGS -DDEBUG_TRACK_SEM" # enable semaphore debugging
|
|
||||||
CFLAGS="$CFLAGS -W -Wall \
|
CFLAGS="$CFLAGS -W -Wall \
|
||||||
-Wbad-function-cast -Wcast-qual -Wmissing-prototypes \
|
-Wbad-function-cast -Wcast-qual -Wmissing-prototypes \
|
||||||
-Wstrict-prototypes -Wmissing-declarations \
|
-Wstrict-prototypes -Wmissing-declarations \
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ int clock_task_func(void* data)
|
|||||||
* can be halted. (e.g. during battle
|
* can be halted. (e.g. during battle
|
||||||
* or communications)
|
* or communications)
|
||||||
*/
|
*/
|
||||||
LockCrossThreadMutex (GLOBAL (GameClock.clock_lock));
|
SetSemaphore (GLOBAL (GameClock.clock_sem));
|
||||||
TimeIn = GetTimeCounter ();
|
TimeIn = GetTimeCounter ();
|
||||||
|
|
||||||
if (GLOBAL (GameClock).tick_count <= 0
|
if (GLOBAL (GameClock).tick_count <= 0
|
||||||
@@ -165,7 +165,7 @@ int clock_task_func(void* data)
|
|||||||
LastTime += num_ticks;
|
LastTime += num_ticks;
|
||||||
}
|
}
|
||||||
|
|
||||||
UnlockCrossThreadMutex (GLOBAL (GameClock.clock_lock));
|
ClearSemaphore (GLOBAL (GameClock.clock_sem));
|
||||||
SleepThreadUntil (TimeIn + ONE_SECOND / 120);
|
SleepThreadUntil (TimeIn + ONE_SECOND / 120);
|
||||||
}
|
}
|
||||||
FinishTask (task);
|
FinishTask (task);
|
||||||
@@ -215,7 +215,7 @@ SuspendGameClock (void)
|
|||||||
LockMutex (clock_mutex);
|
LockMutex (clock_mutex);
|
||||||
if (GameClockRunning ())
|
if (GameClockRunning ())
|
||||||
{
|
{
|
||||||
LockCrossThreadMutex (GLOBAL (GameClock.clock_lock));
|
SetSemaphore (GLOBAL (GameClock.clock_sem));
|
||||||
GLOBAL (GameClock.TimeCounter) = 0;
|
GLOBAL (GameClock.TimeCounter) = 0;
|
||||||
}
|
}
|
||||||
UnlockMutex (clock_mutex);
|
UnlockMutex (clock_mutex);
|
||||||
@@ -228,7 +228,7 @@ ResumeGameClock (void)
|
|||||||
if (!GameClockRunning ())
|
if (!GameClockRunning ())
|
||||||
{
|
{
|
||||||
GLOBAL (GameClock.TimeCounter) = GetTimeCounter ();
|
GLOBAL (GameClock.TimeCounter) = GetTimeCounter ();
|
||||||
UnlockCrossThreadMutex (GLOBAL (GameClock.clock_lock));
|
ClearSemaphore (GLOBAL (GameClock.clock_sem));
|
||||||
}
|
}
|
||||||
UnlockMutex (clock_mutex);
|
UnlockMutex (clock_mutex);
|
||||||
}
|
}
|
||||||
@@ -245,7 +245,7 @@ SetGameClockRate (COUNT seconds_per_day)
|
|||||||
SIZE new_day_in_ticks, new_tick_count;
|
SIZE new_day_in_ticks, new_tick_count;
|
||||||
|
|
||||||
//if (GLOBAL (GameClock.clock_sem)) fprintf (stderr, "%u\n", GLOBAL (GameClock.clock_sem));
|
//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);
|
new_day_in_ticks = (SIZE)(seconds_per_day * CLOCK_BASE_FRAMERATE);
|
||||||
if (GLOBAL (GameClock.day_in_ticks) == 0)
|
if (GLOBAL (GameClock.day_in_ticks) == 0)
|
||||||
new_tick_count = new_day_in_ticks;
|
new_tick_count = new_day_in_ticks;
|
||||||
@@ -256,7 +256,7 @@ SetGameClockRate (COUNT seconds_per_day)
|
|||||||
new_tick_count = 1;
|
new_tick_count = 1;
|
||||||
GLOBAL (GameClock.day_in_ticks) = new_day_in_ticks;
|
GLOBAL (GameClock.day_in_ticks) = new_day_in_ticks;
|
||||||
GLOBAL (GameClock.tick_count) = new_tick_count;
|
GLOBAL (GameClock.tick_count) = new_tick_count;
|
||||||
UnlockCrossThreadMutex (GLOBAL (GameClock.clock_lock));
|
ClearSemaphore (GLOBAL (GameClock.clock_sem));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOLEAN
|
BOOLEAN
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ typedef struct
|
|||||||
BYTE day_index, month_index;
|
BYTE day_index, month_index;
|
||||||
COUNT year_index;
|
COUNT year_index;
|
||||||
SIZE tick_count, day_in_ticks;
|
SIZE tick_count, day_in_ticks;
|
||||||
CrossThreadMutex clock_lock;
|
Semaphore clock_sem;
|
||||||
Task clock_task;
|
Task clock_task;
|
||||||
DWORD TimeCounter;
|
DWORD TimeCounter;
|
||||||
|
|
||||||
|
|||||||
@@ -270,12 +270,9 @@ InitGlobData (void)
|
|||||||
GLOBAL (DisplayArray) = DisplayArray;
|
GLOBAL (DisplayArray) = DisplayArray;
|
||||||
// The clock semaphore was initially initialized as '1'
|
// The clock semaphore was initially initialized as '1'
|
||||||
// but it is always cleared before set, so it toggled between
|
// but it is always cleared before set, so it toggled between
|
||||||
// 2 and 1, which doesn't actually do anything. When this
|
// 2 and 1, which doesn't actually do anything.
|
||||||
// was transformed into a mutex, we lock it first to prevent
|
|
||||||
// double-unlock.
|
|
||||||
|
|
||||||
GLOBAL (GameClock.clock_lock) = CreateCrossThreadMutex("Clock");
|
GLOBAL (GameClock.clock_sem) = CreateSemaphore(0, "Clock");
|
||||||
LockCrossThreadMutex (GLOBAL (GameClock.clock_lock));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ enum
|
|||||||
#define TFB_GFXFLAGS_SCALE_BIADAPT (1<<4)
|
#define TFB_GFXFLAGS_SCALE_BIADAPT (1<<4)
|
||||||
#define TFB_GFXFLAGS_SCALE_BIADAPTADV (1<<5)
|
#define TFB_GFXFLAGS_SCALE_BIADAPTADV (1<<5)
|
||||||
|
|
||||||
|
void TFB_PreInit (void);
|
||||||
int TFB_InitGraphics (int driver, int flags, int width, int height, int bpp);
|
int TFB_InitGraphics (int driver, int flags, int width, int height, int bpp);
|
||||||
void TFB_UninitGraphics (void);
|
void TFB_UninitGraphics (void);
|
||||||
void TFB_ProcessEvents (void);
|
void TFB_ProcessEvents (void);
|
||||||
|
|||||||
@@ -66,12 +66,7 @@ TFB_GL_InitGraphics (int driver, int flags, int width, int height, int bpp)
|
|||||||
|
|
||||||
GraphicsDriver = driver;
|
GraphicsDriver = driver;
|
||||||
|
|
||||||
fprintf (stderr, "Initializing SDL (OpenGL).\n");
|
fprintf (stderr, "Initializing SDL with OpenGL support.\n");
|
||||||
if ((SDL_Init (SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) == -1))
|
|
||||||
{
|
|
||||||
fprintf (stderr, "Could not initialize SDL: %s.\n", SDL_GetError());
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_VideoDriverName (VideoName, sizeof (VideoName));
|
SDL_VideoDriverName (VideoName, sizeof (VideoName));
|
||||||
fprintf (stderr, "SDL driver used: %s\n", 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;
|
GraphicsDriver = driver;
|
||||||
|
|
||||||
fprintf (stderr, "Initializing SDL (pure).\n");
|
fprintf (stderr, "Initializing Pure-SDL graphics.).\n");
|
||||||
|
|
||||||
if ((SDL_Init (SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) == -1))
|
|
||||||
{
|
|
||||||
fprintf (stderr, "Could not initialize SDL: %s.\n", SDL_GetError());
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_VideoDriverName (VideoName, sizeof (VideoName));
|
SDL_VideoDriverName (VideoName, sizeof (VideoName));
|
||||||
fprintf (stderr, "SDL driver used: %s\n", VideoName);
|
fprintf (stderr, "SDL driver used: %s\n", VideoName);
|
||||||
|
|||||||
@@ -55,6 +55,17 @@ TFB_Abort (void)
|
|||||||
abortFlag = TRUE;
|
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
|
int
|
||||||
TFB_InitGraphics (int driver, int flags, int width, int height, int bpp)
|
TFB_InitGraphics (int driver, int flags, int width, int height, int bpp)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,10 +22,14 @@
|
|||||||
|
|
||||||
#define THREADLIB SDL
|
#define THREADLIB SDL
|
||||||
|
|
||||||
/*
|
#define NAMED_SYNCHRO /* Should synchronizable objects have names? */
|
||||||
This is now a compile-time define
|
// #define TRACK_CONTENTION /* Should we report when a thread sleeps on synchronize? */
|
||||||
#define DEBUG_TRACK_SEM
|
|
||||||
*/
|
#ifdef TRACK_CONTENTION
|
||||||
|
# ifndef NAMED_SYNCHRO
|
||||||
|
# define NAMED_SYNCHRO
|
||||||
|
# endif
|
||||||
|
#endif /* TRACK_CONTENTION */
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
# ifndef DEBUG_THREADS
|
# ifndef DEBUG_THREADS
|
||||||
@@ -74,80 +78,83 @@ void uninit_cond_bank (void);
|
|||||||
|
|
||||||
typedef int (*ThreadFunction) (void *);
|
typedef int (*ThreadFunction) (void *);
|
||||||
|
|
||||||
typedef struct Thread {
|
typedef void *Thread;
|
||||||
void *native;
|
typedef void *Mutex;
|
||||||
#ifdef THREAD_NAMES
|
typedef void *Semaphore;
|
||||||
const char *name;
|
typedef void *RecursiveMutex;
|
||||||
#endif
|
typedef void *CondVar;
|
||||||
#ifdef PROFILE_THREADS
|
|
||||||
int startTime;
|
#ifdef NAMED_SYNCHRO
|
||||||
#endif /* PROFILE_THREADS */
|
/* Prototypes with the "name" field */
|
||||||
#ifdef THREAD_QUEUE
|
|
||||||
struct Thread *next;
|
Thread CreateThread_Core (ThreadFunction func, void *data, SDWORD stackSize, const char *name);
|
||||||
#endif
|
Semaphore CreateSemaphore_Core (DWORD initial, const char *name);
|
||||||
} *Thread;
|
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) \
|
#define CreateThread(func, data, stackSize, name) \
|
||||||
CreateThreadAux ((func), (data), (stackSize), (name))
|
CreateThread_Core ((func), (data), (stackSize), (name))
|
||||||
#else /* !defined(THREAD_NAMES) */
|
#define CreateSemaphore(initial, name) \
|
||||||
Thread CreateThreadAux (ThreadFunction func, void *data,
|
CreateSemaphore_Core ((initial), (name))
|
||||||
SDWORD stackSize);
|
#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) \
|
#define CreateThread(func, data, stackSize, name) \
|
||||||
CreateThreadAux ((func), (data), (stackSize))
|
CreateThread_Core ((func), (data), (stackSize))
|
||||||
#endif /* !defined(THREAD_NAMES) */
|
#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 SleepThread (TimePeriod timePeriod);
|
||||||
void SleepThreadUntil (TimeCount wakeTime);
|
void SleepThreadUntil (TimeCount wakeTime);
|
||||||
void TaskSwitch (void);
|
void TaskSwitch (void);
|
||||||
void WaitThread (Thread thread, int *status);
|
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
|
#ifdef PROFILE_THREADS
|
||||||
void PrintThreadsStats (void);
|
void PrintThreadsStats (void);
|
||||||
#endif /* PROFILE_THREADS */
|
#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);
|
void DestroyMutex (Mutex sem);
|
||||||
int LockMutex (Mutex sem);
|
void LockMutex (Mutex sem);
|
||||||
void UnlockMutex (Mutex sem);
|
void UnlockMutex (Mutex sem);
|
||||||
|
|
||||||
typedef void *RecursiveMutex;
|
|
||||||
RecursiveMutex CreateRecursiveMutex (const char *name);
|
|
||||||
void DestroyRecursiveMutex (RecursiveMutex m);
|
void DestroyRecursiveMutex (RecursiveMutex m);
|
||||||
void LockRecursiveMutex (RecursiveMutex m);
|
void LockRecursiveMutex (RecursiveMutex m);
|
||||||
void UnlockRecursiveMutex (RecursiveMutex m);
|
void UnlockRecursiveMutex (RecursiveMutex m);
|
||||||
int GetRecursiveMutexDepth (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 DestroyCondVar (CondVar);
|
||||||
void WaitCondVar (CondVar);
|
void WaitCondVar (CondVar);
|
||||||
void WaitProtectedCondVar (CondVar, Mutex);
|
void WaitProtectedCondVar (CondVar, Mutex);
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ init_cond_bank ()
|
|||||||
bank_mutex = CreateMutex ();
|
bank_mutex = CreateMutex ();
|
||||||
for (i = 0; i < CONDVAR_BANK_SIZE; i++)
|
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].id = bank[i].used = 0;
|
||||||
bank[i].control = CreateMutex ();
|
bank[i].control = CreateMutex ();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,15 +20,55 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "sdlthreads.h"
|
#include "sdlthreads.h"
|
||||||
|
#ifdef PROFILE_THREADS
|
||||||
|
#include <signal.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(PROFILE_THREADS) && !defined(WIN32)
|
#if defined(PROFILE_THREADS) && !defined(WIN32)
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef struct _thread {
|
||||||
|
void *native;
|
||||||
|
#ifdef NAMED_SYNCHRO
|
||||||
|
const char *name;
|
||||||
|
#endif
|
||||||
#ifdef PROFILE_THREADS
|
#ifdef PROFILE_THREADS
|
||||||
void
|
int startTime;
|
||||||
SDLWrapper_PrintThreadStats (SDL_Thread *thread) {
|
#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)
|
#if defined (WIN32) || !defined(SDL_PTHREADS)
|
||||||
fprintf (stderr, "Thread ID %u\n", SDL_GetThreadID (thread));
|
fprintf (stderr, "Thread ID %u\n", SDL_GetThreadID (thread));
|
||||||
#else /* !defined (WIN32) && defined(SDL_PTHREADS) */
|
#else /* !defined (WIN32) && defined(SDL_PTHREADS) */
|
||||||
@@ -45,74 +85,327 @@ SDLWrapper_PrintThreadStats (SDL_Thread *thread) {
|
|||||||
seconds / 60, seconds % 60);
|
seconds / 60, seconds % 60);
|
||||||
#endif /* defined (WIN32) && defined(SDL_PTHREADS) */
|
#endif /* defined (WIN32) && defined(SDL_PTHREADS) */
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
void
|
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);
|
SDL_Delay (sleepTime * 1000 / ONE_SECOND);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SDLWrapper_SleepThreadUntil (TimeCount wakeTime) {
|
SleepThreadUntil_SDL (TimeCount wakeTime) {
|
||||||
TimeCount now;
|
TimeCount now;
|
||||||
|
|
||||||
now = GetTimeCounter ();
|
now = GetTimeCounter ();
|
||||||
if (wakeTime <= now)
|
if (wakeTime <= now)
|
||||||
SDLWrapper_TaskSwitch ();
|
TaskSwitch_SDL ();
|
||||||
else
|
else
|
||||||
SDL_Delay ((wakeTime - now) * 1000 / ONE_SECOND);
|
SDL_Delay ((wakeTime - now) * 1000 / ONE_SECOND);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
SDLWrapper_TimeoutSetSemaphore (Semaphore sem, TimePeriod timeout) {
|
|
||||||
return SDL_SemWaitTimeout (sem, timeout * 1000 / ONE_SECOND);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
SDLWrapper_TaskSwitch (void) {
|
TaskSwitch_SDL (void) {
|
||||||
SDL_Delay (1);
|
SDL_Delay (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SDLWrapper_WaitCondVar (CondVar cv) {
|
WaitThread_SDL (Thread thread, int *status) {
|
||||||
int result;
|
SDL_WaitThread (((TrueThread)thread)->native, status);
|
||||||
Mutex temp = CreateMutex ();
|
}
|
||||||
LockMutex (temp);
|
|
||||||
result = SDL_CondWait (cv, temp);
|
/* These are the SDL implementations of the UQM synchronization objects. */
|
||||||
UnlockMutex (temp);
|
/* TODO: Remove the names of the following data types when compiling
|
||||||
DestroyMutex (temp);
|
* under release mode. */
|
||||||
if (result != 0) {
|
|
||||||
fprintf (stderr, "Error result from SDL_CondWait: %d\n", result);
|
/* 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
|
/* Recursive mutexes. Adapted from mixSDL code, which was adapted from
|
||||||
original DCQ code. */
|
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. */
|
|
||||||
|
|
||||||
typedef struct _recm {
|
typedef struct _recm {
|
||||||
SDL_mutex *mutex;
|
SDL_mutex *mutex;
|
||||||
Uint32 thread_id;
|
Uint32 thread_id;
|
||||||
Uint32 locks;
|
Uint32 locks;
|
||||||
|
#ifdef NAMED_SYNCHRO
|
||||||
const char *name;
|
const char *name;
|
||||||
|
#endif
|
||||||
} RecM;
|
} RecM;
|
||||||
|
|
||||||
RecursiveMutex
|
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));
|
RecM *mtx = (RecM *) HMalloc (sizeof (struct _recm));
|
||||||
|
|
||||||
mtx->thread_id = 0;
|
mtx->thread_id = 0;
|
||||||
mtx->mutex = SDL_CreateMutex ();
|
mtx->mutex = SDL_CreateMutex ();
|
||||||
|
#ifdef NAMED_SYNCHRO
|
||||||
mtx->name = name;
|
mtx->name = name;
|
||||||
|
#endif
|
||||||
mtx->locks = 0;
|
mtx->locks = 0;
|
||||||
return (RecursiveMutex) mtx;
|
return (RecursiveMutex) mtx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
DestroyRecursiveMutex (RecursiveMutex val)
|
DestroyRecursiveMutex_SDL (RecursiveMutex val)
|
||||||
{
|
{
|
||||||
RecM *mtx = (RecM *)val;
|
RecM *mtx = (RecM *)val;
|
||||||
SDL_DestroyMutex (mtx->mutex);
|
SDL_DestroyMutex (mtx->mutex);
|
||||||
@@ -120,27 +413,35 @@ DestroyRecursiveMutex (RecursiveMutex val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LockRecursiveMutex (RecursiveMutex val)
|
LockRecursiveMutex_SDL (RecursiveMutex val)
|
||||||
{
|
{
|
||||||
RecM *mtx = (RecM *)val;
|
RecM *mtx = (RecM *)val;
|
||||||
Uint32 thread_id = SDL_ThreadID();
|
Uint32 thread_id = SDL_ThreadID();
|
||||||
if (mtx->thread_id != thread_id)
|
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))
|
while (SDL_mutexP (mtx->mutex))
|
||||||
TaskSwitch ();
|
TaskSwitch_SDL ();
|
||||||
mtx->thread_id = thread_id;
|
mtx->thread_id = thread_id;
|
||||||
}
|
}
|
||||||
mtx->locks++;
|
mtx->locks++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
UnlockRecursiveMutex (RecursiveMutex val)
|
UnlockRecursiveMutex_SDL (RecursiveMutex val)
|
||||||
{
|
{
|
||||||
RecM *mtx = (RecM *)val;
|
RecM *mtx = (RecM *)val;
|
||||||
Uint32 thread_id = SDL_ThreadID();
|
Uint32 thread_id = SDL_ThreadID();
|
||||||
if (mtx->thread_id != thread_id)
|
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
|
else
|
||||||
{
|
{
|
||||||
@@ -154,85 +455,88 @@ UnlockRecursiveMutex (RecursiveMutex val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
GetRecursiveMutexDepth (RecursiveMutex val)
|
GetRecursiveMutexDepth_SDL (RecursiveMutex val)
|
||||||
{
|
{
|
||||||
RecM *mtx = (RecM *)val;
|
RecM *mtx = (RecM *)val;
|
||||||
return mtx->locks;
|
return mtx->locks;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Code for cross-thread mutexes. The prototypes for these functions are in threadlib.h. */
|
typedef struct _cond {
|
||||||
|
|
||||||
typedef struct _ctm {
|
|
||||||
SDL_mutex *mutex;
|
|
||||||
SDL_cond *cond;
|
SDL_cond *cond;
|
||||||
|
SDL_mutex *mutex;
|
||||||
|
#ifdef NAMED_SYNCHRO
|
||||||
const char *name;
|
const char *name;
|
||||||
Uint32 locker;
|
#endif
|
||||||
} _NativeCTM;
|
} cvar;
|
||||||
|
|
||||||
CrossThreadMutex
|
CondVar
|
||||||
CreateCrossThreadMutex (const char *name)
|
#ifdef NAMED_SYNCHRO
|
||||||
|
CreateCondVar_SDL (const char *name)
|
||||||
|
#else
|
||||||
|
CreateCondVar_SDL (void)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
_NativeCTM *result = HMalloc (sizeof (_NativeCTM));
|
cvar *cv = (cvar *) HMalloc (sizeof (cvar));
|
||||||
result->mutex = SDL_CreateMutex ();
|
cv->cond = SDL_CreateCond ();
|
||||||
result->cond = SDL_CreateCond ();
|
cv->mutex = SDL_CreateMutex ();
|
||||||
result->name = name;
|
#ifdef NAMED_SYNCHRO
|
||||||
result->locker = 0;
|
cv->name = name;
|
||||||
return (CrossThreadMutex)result;
|
#endif
|
||||||
|
return cv;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
DestroyCrossThreadMutex (CrossThreadMutex val)
|
DestroyCondVar_SDL (CondVar c)
|
||||||
{
|
{
|
||||||
_NativeCTM *ctm = (_NativeCTM *)val;
|
cvar *cv = (cvar *) c;
|
||||||
if (ctm)
|
SDL_DestroyCond (cv->cond);
|
||||||
{
|
SDL_DestroyMutex (cv->mutex);
|
||||||
SDL_DestroyMutex (ctm->mutex);
|
HFree (cv);
|
||||||
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 */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
UnlockCrossThreadMutex (CrossThreadMutex val)
|
WaitCondVar_SDL (CondVar c)
|
||||||
{
|
{
|
||||||
_NativeCTM *ctm = (_NativeCTM *)val;
|
cvar *cv = (cvar *) c;
|
||||||
if (SDL_mutexP (ctm->mutex))
|
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);
|
TaskSwitch_SDL ();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
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);
|
void
|
||||||
}
|
BroadcastCondVar_SDL (CondVar c)
|
||||||
else
|
|
||||||
{
|
{
|
||||||
fprintf (stderr, "Double unlock attempt on %s ignored.\n", ctm->name);
|
cvar *cv = (cvar *) c;
|
||||||
}
|
SDL_CondBroadcast (cv->cond);
|
||||||
SDL_mutexV (ctm->mutex);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,51 +25,8 @@
|
|||||||
#include "libs/threadlib.h"
|
#include "libs/threadlib.h"
|
||||||
#include "libs/timelib.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 NativeGetThreadID(thread) SDL_GetThreadID ((thread))
|
||||||
#define NativeThreadID() SDL_ThreadID ()
|
#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;
|
typedef SDL_mutex *NativeMutex;
|
||||||
#define NativeCreateMutex() \
|
#define NativeCreateMutex() \
|
||||||
@@ -81,23 +38,72 @@ typedef SDL_mutex *NativeMutex;
|
|||||||
#define NativeUnlockMutex(mutex) \
|
#define NativeUnlockMutex(mutex) \
|
||||||
SDL_mutexV ((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() \
|
#define NativeCurrentThreadID() \
|
||||||
SDL_ThreadID ()
|
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 */
|
#endif /* _SDLTHREAD_H */
|
||||||
|
|
||||||
|
|||||||
@@ -22,249 +22,90 @@
|
|||||||
#include "libs/timelib.h"
|
#include "libs/timelib.h"
|
||||||
#include "libs/misc.h"
|
#include "libs/misc.h"
|
||||||
#include "thrcommon.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
|
void
|
||||||
InitThreadSystem (void)
|
InitThreadSystem (void)
|
||||||
{
|
{
|
||||||
#ifdef THREAD_QUEUE
|
|
||||||
threadQueueSemaphore = CreateSemaphore (1, "ThreadQueue");
|
|
||||||
#endif /* THREAD_QUEUE */
|
|
||||||
#ifdef PROFILE_THREADS
|
|
||||||
signal(SIGUSR1, SigUSR1Handler);
|
|
||||||
#endif
|
|
||||||
NativeInitThreadSystem ();
|
NativeInitThreadSystem ();
|
||||||
init_cond_bank ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
UnInitThreadSystem (void)
|
UnInitThreadSystem (void)
|
||||||
{
|
{
|
||||||
uninit_cond_bank ();
|
|
||||||
NativeUnInitThreadSystem ();
|
NativeUnInitThreadSystem ();
|
||||||
#ifdef PROFILE_THREADS
|
|
||||||
signal(SIGUSR1, SIG_DFL);
|
|
||||||
#endif
|
|
||||||
#ifdef THREAD_QUEUE
|
|
||||||
DestroySemaphore (threadQueueSemaphore);
|
|
||||||
#endif /* THREAD_QUEUE */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef THREAD_QUEUE
|
/* The Create routines look different based on whether NAMED_SYNCHRO
|
||||||
static void
|
is defined or not. */
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#ifdef NAMED_SYNCHRO
|
||||||
Thread
|
Thread
|
||||||
CreateThreadAux (ThreadFunction func, void *data, SDWORD stackSize
|
CreateThread_Core (ThreadFunction func, void *data, SDWORD stackSize, const char *name)
|
||||||
#ifdef THREAD_NAMES
|
|
||||||
, const char *name
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
Thread thread;
|
return NativeCreateThread (func, data, stackSize, name);
|
||||||
struct ThreadStartInfo *startInfo;
|
}
|
||||||
|
|
||||||
thread = (struct Thread *) HMalloc (sizeof *thread);
|
Mutex
|
||||||
#ifdef THREAD_NAMES
|
CreateMutex_Core (void)
|
||||||
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);
|
return (Mutex) NativeCreateMutex ();
|
||||||
HFree (thread);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
// The responsibility to free 'startInfo' and 'thread' is now by the new
|
|
||||||
// thread.
|
|
||||||
|
|
||||||
#ifdef THREAD_QUEUE
|
Semaphore
|
||||||
QueueThread (thread);
|
CreateSemaphore_Core (DWORD initial, const char *name)
|
||||||
#endif /* THREAD_QUEUE */
|
{
|
||||||
|
return NativeCreateSemaphore (initial, name);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_THREADS
|
RecursiveMutex
|
||||||
fprintf (stderr, "Thread '%s' created.\n", ThreadName (thread));
|
CreateRecursiveMutex_Core (const char *name)
|
||||||
fflush (stderr);
|
{
|
||||||
|
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
|
#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
|
void
|
||||||
WaitThread (Thread thread, int *status)
|
WaitThread (Thread thread, int *status)
|
||||||
{
|
{
|
||||||
NativeWaitThread (thread->native, status);
|
NativeWaitThread (thread, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -285,292 +126,19 @@ TaskSwitch (void)
|
|||||||
NativeTaskSwitch ();
|
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
|
void
|
||||||
DestroyMutex (Mutex sem)
|
DestroyMutex (Mutex sem)
|
||||||
{
|
{
|
||||||
NativeDestroyMutex ((NativeMutex) sem);
|
NativeDestroyMutex ((NativeMutex) sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
void
|
||||||
LockMutex (Mutex sem)
|
LockMutex (Mutex sem)
|
||||||
{
|
{
|
||||||
return NativeLockMutex ((NativeMutex) sem);
|
while (NativeLockMutex ((NativeMutex) sem) == -1)
|
||||||
|
{
|
||||||
|
TaskSwitch ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -579,40 +147,52 @@ UnlockMutex (Mutex sem)
|
|||||||
NativeUnlockMutex ((NativeMutex) sem);
|
NativeUnlockMutex ((NativeMutex) sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
CondVar
|
void
|
||||||
CreateCondVar ()
|
DestroySemaphore (Semaphore sem)
|
||||||
{
|
{
|
||||||
return NativeCreateCondVar ();
|
NativeDestroySemaphore (sem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SetSemaphore (Semaphore sem)
|
||||||
|
{
|
||||||
|
NativeSetSemaphore (sem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ClearSemaphore (Semaphore sem)
|
||||||
|
{
|
||||||
|
NativeClearSemaphore (sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
DestroyCondVar (CondVar cv)
|
DestroyCondVar (CondVar cv)
|
||||||
{
|
{
|
||||||
NativeDestroyCondVar ((CondVar)cv);
|
NativeDestroyCondVar (cv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
WaitCondVar (CondVar cv)
|
WaitCondVar (CondVar cv)
|
||||||
{
|
{
|
||||||
NativeWaitCondVar ((NativeCondVar)cv);
|
NativeWaitCondVar (cv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
WaitProtectedCondVar (CondVar cv, Mutex m)
|
WaitProtectedCondVar (CondVar cv, Mutex m)
|
||||||
{
|
{
|
||||||
NativeWaitProtectedCondVar ((NativeCondVar)cv, (NativeMutex)m);
|
NativeWaitProtectedCondVar (cv, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SignalCondVar (CondVar cv)
|
SignalCondVar (CondVar cv)
|
||||||
{
|
{
|
||||||
NativeSignalCondVar ((NativeCondVar)cv);
|
NativeSignalCondVar (cv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BroadcastCondVar (CondVar cv)
|
BroadcastCondVar (CondVar cv)
|
||||||
{
|
{
|
||||||
NativeBroadcastCondVar ((NativeCondVar)cv);
|
NativeBroadcastCondVar (cv);
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD
|
DWORD
|
||||||
@@ -620,3 +200,27 @@ CurrentThreadID ()
|
|||||||
{
|
{
|
||||||
return (DWORD)NativeThreadID ();
|
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->w = vid->decoder->w;
|
||||||
vid->h = vid->decoder->h;
|
vid->h = vid->decoder->h;
|
||||||
vid->guard = CreateMutex ();
|
vid->guard = CreateMutex ();
|
||||||
vid->frame_lock = CreateCondVar ();
|
vid->frame_lock = CreateCondVar ("frame lock");
|
||||||
|
|
||||||
return (VIDEO_REF) vid;
|
return (VIDEO_REF) vid;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -308,7 +308,6 @@ TFB_PlayVideo (VIDEO_REF VidRef, uint32 x, uint32 y)
|
|||||||
if (!vid->play_task)
|
if (!vid->play_task)
|
||||||
{
|
{
|
||||||
vid->playing = false;
|
vid->playing = false;
|
||||||
//UnlockCrossThreadMutex (vid->frame_lock);
|
|
||||||
ClearSemaphore (vp_interthread_lock);
|
ClearSemaphore (vp_interthread_lock);
|
||||||
TFB_StopVideo (VidRef);
|
TFB_StopVideo (VidRef);
|
||||||
|
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ LoadGame (COUNT which_game, SUMMARY_DESC *summary_desc)
|
|||||||
uio_Stream *fp;
|
uio_Stream *fp;
|
||||||
DECODE_REF fh;
|
DECODE_REF fh;
|
||||||
COUNT num_links;
|
COUNT num_links;
|
||||||
CrossThreadMutex clock_lock;
|
Semaphore clock_sem;
|
||||||
Task clock_task;
|
Task clock_task;
|
||||||
QUEUE event_q, encounter_q, avail_q, npc_q, player_q;
|
QUEUE event_q, encounter_q, avail_q, npc_q, player_q;
|
||||||
STAR_DESC SD;
|
STAR_DESC SD;
|
||||||
@@ -126,7 +126,7 @@ LoadGame (COUNT which_game, SUMMARY_DESC *summary_desc)
|
|||||||
ReinitQueue (&GLOBAL (npc_built_ship_q));
|
ReinitQueue (&GLOBAL (npc_built_ship_q));
|
||||||
ReinitQueue (&GLOBAL (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);
|
clock_task = GLOBAL (GameClock.clock_task);
|
||||||
event_q = GLOBAL (GameClock.event_q);
|
event_q = GLOBAL (GameClock.event_q);
|
||||||
encounter_q = GLOBAL (encounter_q);
|
encounter_q = GLOBAL (encounter_q);
|
||||||
@@ -141,7 +141,7 @@ LoadGame (COUNT which_game, SUMMARY_DESC *summary_desc)
|
|||||||
NextActivity = GLOBAL (CurrentActivity);
|
NextActivity = GLOBAL (CurrentActivity);
|
||||||
GLOBAL (CurrentActivity) = Activity;
|
GLOBAL (CurrentActivity) = Activity;
|
||||||
|
|
||||||
GLOBAL (GameClock.clock_lock) = clock_lock;
|
GLOBAL (GameClock.clock_sem) = clock_sem;
|
||||||
GLOBAL (GameClock.clock_task) = clock_task;
|
GLOBAL (GameClock.clock_task) = clock_task;
|
||||||
GLOBAL (GameClock.event_q) = event_q;
|
GLOBAL (GameClock.event_q) = event_q;
|
||||||
GLOBAL (encounter_q) = encounter_q;
|
GLOBAL (encounter_q) = encounter_q;
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ int arilou_gate_task(void* data)
|
|||||||
counter = GET_GAME_STATE (ARILOU_SPACE_COUNTER);
|
counter = GET_GAME_STATE (ARILOU_SPACE_COUNTER);
|
||||||
while (!Task_ReadState (task, TASK_EXIT))
|
while (!Task_ReadState (task, TASK_EXIT))
|
||||||
{
|
{
|
||||||
LockCrossThreadMutex (GLOBAL (GameClock.clock_lock));
|
SetSemaphore (GLOBAL (GameClock.clock_sem));
|
||||||
|
|
||||||
if (GET_GAME_STATE (ARILOU_SPACE) == OPENING)
|
if (GET_GAME_STATE (ARILOU_SPACE) == OPENING)
|
||||||
{
|
{
|
||||||
@@ -63,7 +63,7 @@ int arilou_gate_task(void* data)
|
|||||||
SET_GAME_STATE (ARILOU_SPACE_COUNTER, counter);
|
SET_GAME_STATE (ARILOU_SPACE_COUNTER, counter);
|
||||||
UnlockMutex (GraphicsLock);
|
UnlockMutex (GraphicsLock);
|
||||||
|
|
||||||
UnlockCrossThreadMutex (GLOBAL (GameClock.clock_lock));
|
ClearSemaphore (GLOBAL (GameClock.clock_sem));
|
||||||
SleepThreadUntil (TimeIn + BATTLE_FRAME_RATE);
|
SleepThreadUntil (TimeIn + BATTLE_FRAME_RATE);
|
||||||
TimeIn = GetTimeCounter ();
|
TimeIn = GetTimeCounter ();
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-5
@@ -134,12 +134,14 @@ main (int argc, char *argv[])
|
|||||||
contentDir = "content";
|
contentDir = "content";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* InitThreadSystem should come before anything else.
|
|
||||||
* The memory system uses semaphores.
|
/* mem_init () uses mutexes. Mutex creation cannot use
|
||||||
* Everything else uses the memory system.
|
the memory system until the memory system is rewritten
|
||||||
|
to rely on a thread-safe allocator.
|
||||||
*/
|
*/
|
||||||
InitThreadSystem ();
|
TFB_PreInit ();
|
||||||
mem_init ();
|
mem_init ();
|
||||||
|
InitThreadSystem ();
|
||||||
|
|
||||||
addons = HMalloc(1 * sizeof (const char *));
|
addons = HMalloc(1 * sizeof (const char *));
|
||||||
addons[0] = NULL;
|
addons[0] = NULL;
|
||||||
@@ -349,7 +351,7 @@ main (int argc, char *argv[])
|
|||||||
InitTaskSystem ();
|
InitTaskSystem ();
|
||||||
|
|
||||||
GraphicsLock = CreateMutex (/*"Graphics"*/);
|
GraphicsLock = CreateMutex (/*"Graphics"*/);
|
||||||
RenderingCond = CreateCondVar ();
|
RenderingCond = CreateCondVar ("DCQ empty");
|
||||||
|
|
||||||
TFB_InitGraphics (gfxdriver, gfxflags, width, height, bpp);
|
TFB_InitGraphics (gfxdriver, gfxflags, width, height, bpp);
|
||||||
init_communication ();
|
init_communication ();
|
||||||
|
|||||||
Reference in New Issue
Block a user