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:
ghaushe
2003-01-04 16:55:31 +00:00
parent c043017049
commit 7f0251ba4d
6 changed files with 57 additions and 12 deletions
+1
View File
@@ -1,4 +1,5 @@
Changes towards version 0.2: Changes towards version 0.2:
- Fixed deadlock races in new FlushGraphics method -PhracturedBlue
- FlushGraphics now waits and notifies on a per-thread level - FlushGraphics now waits and notifies on a per-thread level
- No longer using SHGetFolderPath on Windows - SvdB - No longer using SHGetFolderPath on Windows - SvdB
- Key repeat is now enabled when typing text, from slayne - Key repeat is now enabled when typing text, from slayne
@@ -80,6 +80,8 @@ FlushGraphics (void)
TFB_BatchReset (); TFB_BatchReset ();
DrawCommand.Type = TFB_DRAWCOMMANDTYPE_FLUSHGRAPHICS; DrawCommand.Type = TFB_DRAWCOMMANDTYPE_FLUSHGRAPHICS;
DrawCommand.image = 0; DrawCommand.image = 0;
// We need to lock the mutex before quein the DC to prevent races
LockSignalMutex ();
TFB_EnqueueDrawCommand(&DrawCommand); TFB_EnqueueDrawCommand(&DrawCommand);
WaitForSignal (); WaitForSignal ();
} }
+6
View File
@@ -104,11 +104,16 @@ typedef void *Semaphore;
extern Semaphore CreateSemaphoreAux (DWORD initial, char *sem_name); extern Semaphore CreateSemaphoreAux (DWORD initial, char *sem_name);
# define CreateSemaphore(initial,sem_name) \ # define CreateSemaphore(initial,sem_name) \
CreateSemaphoreAux ((initial), (sem_name)) CreateSemaphoreAux ((initial), (sem_name))
extern void ResetSemaphoreOwnerAux (Semaphore sem);
# define ResetSemaphoreOwner(sem_name) \
ResetSemaphoreOwnerAux (sem_name)
#else #else
extern Semaphore CreateSemaphoreAux (DWORD initial); extern Semaphore CreateSemaphoreAux (DWORD initial);
# define CreateSemaphore(initial,sem_name) \ # define CreateSemaphore(initial,sem_name) \
CreateSemaphoreAux ((initial)) CreateSemaphoreAux ((initial))
# define ResetSemaphoreOwner(sem_name)
#endif #endif
extern DWORD SemaphoreValue (Semaphore sem);
extern void DestroySemaphore (Semaphore sem); extern void DestroySemaphore (Semaphore sem);
extern int SetSemaphore (Semaphore sem); extern int SetSemaphore (Semaphore sem);
extern int TrySetSemaphore (Semaphore sem); extern int TrySetSemaphore (Semaphore sem);
@@ -133,6 +138,7 @@ extern void BroadcastCondVar (CondVar);
extern DWORD CurrentThreadID (void); extern DWORD CurrentThreadID (void);
extern void LockSignalMutex(void);
extern void WaitForSignal (void); extern void WaitForSignal (void);
extern void SignalThread (DWORD); extern void SignalThread (DWORD);
+26 -12
View File
@@ -29,10 +29,11 @@
#define CONDVAR_BANK_SIZE 10 #define CONDVAR_BANK_SIZE 10
static Semaphore bank_sem; static Mutex bank_mutex;
static int wait = 0, signal = 0;
static struct { static struct {
CondVar var; Semaphore var;
DWORD id; DWORD id;
int used; int used;
} bank[CONDVAR_BANK_SIZE]; } bank[CONDVAR_BANK_SIZE];
@@ -41,10 +42,12 @@ void
init_cond_bank () init_cond_bank ()
{ {
int i; int i;
bank_sem = CreateSemaphore (1, "CondVar Bank Semaphore"); bank_mutex = CreateMutex ();
for (i = 0; i < CONDVAR_BANK_SIZE; i++) 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; bank[i].id = bank[i].used = 0;
} }
} }
@@ -57,16 +60,20 @@ uninit_cond_bank ()
{ {
DestroyCondVar (bank[i].var); DestroyCondVar (bank[i].var);
} }
DestroySemaphore (bank_sem); DestroyMutex (bank_mutex);
} }
void
LockSignalMutex ()
{
LockMutex (bank_mutex);
}
void void
WaitForSignal () WaitForSignal ()
{ {
int i; int i;
int index = -1; int index = -1;
DWORD me = CurrentThreadID (); DWORD me = CurrentThreadID ();
SetSemaphore (bank_sem);
for (i = 0; i < CONDVAR_BANK_SIZE; i++) for (i = 0; i < CONDVAR_BANK_SIZE; i++)
{ {
if (!bank[i].used) if (!bank[i].used)
@@ -79,15 +86,19 @@ WaitForSignal ()
{ {
/* The bank is full! */ /* The bank is full! */
fprintf(stderr, "Condvar bank is full, %ul is waiting on DCQ.", me); fprintf(stderr, "Condvar bank is full, %ul is waiting on DCQ.", me);
ClearSemaphore (bank_sem); UnlockMutex (bank_mutex);
WaitCondVar (RenderingCond); WaitCondVar (RenderingCond);
} }
else else
{ {
bank[i].used = 1; bank[i].used = 1;
bank[i].id = me; bank[i].id = me;
ClearSemaphore (bank_sem); // Initialize the Semaphore to a value of '0' in case it isn't already
WaitCondVar (bank[i].var); 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) SignalThread (DWORD id)
{ {
int i; int i;
SetSemaphore (bank_sem); LockMutex (bank_mutex);
for (i = 0; i < CONDVAR_BANK_SIZE; i++) for (i = 0; i < CONDVAR_BANK_SIZE; i++)
{ {
if (bank[i].used && bank[i].id == id) if (bank[i].used && bank[i].id == id)
{ {
bank[i].id = bank[i].used = 0; bank[i].id = bank[i].used = 0;
SignalCondVar (bank[i].var); ResetSemaphoreOwner (bank[i].var);
ClearSemaphore (bank[i].var);
break; 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 () SDL_CreateCond ()
#define NativeDestroyCondVar(condvar) \ #define NativeDestroyCondVar(condvar) \
SDL_DestroyCond ((condvar)) SDL_DestroyCond ((condvar))
extern void SDLWrapper_WaitCondVar (CondVar candvar);
#define NativeWaitCondVar(condvar) \ #define NativeWaitCondVar(condvar) \
SDLWrapper_WaitCondVar ((condvar)) SDLWrapper_WaitCondVar ((condvar))
#define NativeSignalCondVar(condvar) \ #define NativeSignalCondVar(condvar) \
+21
View File
@@ -518,6 +518,27 @@ TimeoutSetSemaphore (Semaphore sem, TimePeriod timeout)
return (i); 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 void
ClearSemaphore (Semaphore sem) ClearSemaphore (Semaphore sem)
{ {