Replaced CondVar with a Semaphore in the new Signalling code.
This removes the race between releasing the bank semaphore and starting the WaitCondVar (which was causing deadlocks in Windows) git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@529 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
@@ -80,6 +80,8 @@ FlushGraphics (void)
|
||||
TFB_BatchReset ();
|
||||
DrawCommand.Type = TFB_DRAWCOMMANDTYPE_FLUSHGRAPHICS;
|
||||
DrawCommand.image = 0;
|
||||
// We need to lock the mutex before quein the DC to prevent races
|
||||
LockSignalMutex ();
|
||||
TFB_EnqueueDrawCommand(&DrawCommand);
|
||||
WaitForSignal ();
|
||||
}
|
||||
|
||||
@@ -104,11 +104,16 @@ typedef void *Semaphore;
|
||||
extern Semaphore CreateSemaphoreAux (DWORD initial, char *sem_name);
|
||||
# define CreateSemaphore(initial,sem_name) \
|
||||
CreateSemaphoreAux ((initial), (sem_name))
|
||||
extern void ResetSemaphoreOwnerAux (Semaphore sem);
|
||||
# define ResetSemaphoreOwner(sem_name) \
|
||||
ResetSemaphoreOwnerAux (sem_name)
|
||||
#else
|
||||
extern Semaphore CreateSemaphoreAux (DWORD initial);
|
||||
# define CreateSemaphore(initial,sem_name) \
|
||||
CreateSemaphoreAux ((initial))
|
||||
# define ResetSemaphoreOwner(sem_name)
|
||||
#endif
|
||||
extern DWORD SemaphoreValue (Semaphore sem);
|
||||
extern void DestroySemaphore (Semaphore sem);
|
||||
extern int SetSemaphore (Semaphore sem);
|
||||
extern int TrySetSemaphore (Semaphore sem);
|
||||
@@ -133,6 +138,7 @@ extern void BroadcastCondVar (CondVar);
|
||||
|
||||
extern DWORD CurrentThreadID (void);
|
||||
|
||||
extern void LockSignalMutex(void);
|
||||
extern void WaitForSignal (void);
|
||||
extern void SignalThread (DWORD);
|
||||
|
||||
|
||||
@@ -29,10 +29,11 @@
|
||||
|
||||
#define CONDVAR_BANK_SIZE 10
|
||||
|
||||
static Semaphore bank_sem;
|
||||
static Mutex bank_mutex;
|
||||
static int wait = 0, signal = 0;
|
||||
|
||||
static struct {
|
||||
CondVar var;
|
||||
Semaphore var;
|
||||
DWORD id;
|
||||
int used;
|
||||
} bank[CONDVAR_BANK_SIZE];
|
||||
@@ -41,10 +42,12 @@ void
|
||||
init_cond_bank ()
|
||||
{
|
||||
int i;
|
||||
bank_sem = CreateSemaphore (1, "CondVar Bank Semaphore");
|
||||
bank_mutex = CreateMutex ();
|
||||
for (i = 0; i < CONDVAR_BANK_SIZE; i++)
|
||||
{
|
||||
bank[i].var = CreateCondVar ();
|
||||
char str[20];
|
||||
sprintf (str, "bank sem %d", i);
|
||||
bank[i].var = CreateSemaphore (0, str);
|
||||
bank[i].id = bank[i].used = 0;
|
||||
}
|
||||
}
|
||||
@@ -57,16 +60,20 @@ uninit_cond_bank ()
|
||||
{
|
||||
DestroyCondVar (bank[i].var);
|
||||
}
|
||||
DestroySemaphore (bank_sem);
|
||||
DestroyMutex (bank_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
LockSignalMutex ()
|
||||
{
|
||||
LockMutex (bank_mutex);
|
||||
}
|
||||
void
|
||||
WaitForSignal ()
|
||||
{
|
||||
int i;
|
||||
int index = -1;
|
||||
DWORD me = CurrentThreadID ();
|
||||
SetSemaphore (bank_sem);
|
||||
for (i = 0; i < CONDVAR_BANK_SIZE; i++)
|
||||
{
|
||||
if (!bank[i].used)
|
||||
@@ -79,15 +86,19 @@ WaitForSignal ()
|
||||
{
|
||||
/* The bank is full! */
|
||||
fprintf(stderr, "Condvar bank is full, %ul is waiting on DCQ.", me);
|
||||
ClearSemaphore (bank_sem);
|
||||
UnlockMutex (bank_mutex);
|
||||
WaitCondVar (RenderingCond);
|
||||
}
|
||||
else
|
||||
{
|
||||
bank[i].used = 1;
|
||||
bank[i].id = me;
|
||||
ClearSemaphore (bank_sem);
|
||||
WaitCondVar (bank[i].var);
|
||||
// Initialize the Semaphore to a value of '0' in case it isn't already
|
||||
while (SemaphoreValue (bank[i].var))
|
||||
SetSemaphore (bank[i].var);
|
||||
UnlockMutex (bank_mutex);
|
||||
// Block on Semaphore until it is cleared by the Signal
|
||||
SetSemaphore (bank[i].var);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,16 +106,19 @@ void
|
||||
SignalThread (DWORD id)
|
||||
{
|
||||
int i;
|
||||
SetSemaphore (bank_sem);
|
||||
LockMutex (bank_mutex);
|
||||
for (i = 0; i < CONDVAR_BANK_SIZE; i++)
|
||||
{
|
||||
if (bank[i].used && bank[i].id == id)
|
||||
{
|
||||
bank[i].id = bank[i].used = 0;
|
||||
SignalCondVar (bank[i].var);
|
||||
ResetSemaphoreOwner (bank[i].var);
|
||||
ClearSemaphore (bank[i].var);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ClearSemaphore (bank_sem);
|
||||
if (i == CONDVAR_BANK_SIZE)
|
||||
fprintf (stderr, "Warning: Couldn't find thread to signal!\n");
|
||||
UnlockMutex (bank_mutex);
|
||||
}
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@ typedef SDL_cond *NativeCondVar;
|
||||
SDL_CreateCond ()
|
||||
#define NativeDestroyCondVar(condvar) \
|
||||
SDL_DestroyCond ((condvar))
|
||||
extern void SDLWrapper_WaitCondVar (CondVar candvar);
|
||||
#define NativeWaitCondVar(condvar) \
|
||||
SDLWrapper_WaitCondVar ((condvar))
|
||||
#define NativeSignalCondVar(condvar) \
|
||||
|
||||
@@ -518,6 +518,27 @@ TimeoutSetSemaphore (Semaphore sem, TimePeriod timeout)
|
||||
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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user