fix up more obscure races
This commit is contained in:
@@ -41,6 +41,7 @@ struct ThreadSlot
|
|||||||
char ThreadFormattedOutput[1024];
|
char ThreadFormattedOutput[1024];
|
||||||
|
|
||||||
bool used;
|
bool used;
|
||||||
|
uint64_t id;
|
||||||
|
|
||||||
ThreadImpl *pImpl;
|
ThreadImpl *pImpl;
|
||||||
|
|
||||||
@@ -63,9 +64,12 @@ struct ThreadSlot
|
|||||||
ThreadSlot() { Init(); }
|
ThreadSlot() { Init(); }
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
used = false;
|
id = GetInvalidThreadId();
|
||||||
CurCheckpoint = NumCheckpoints = 0;
|
CurCheckpoint = NumCheckpoints = 0;
|
||||||
pImpl = NULL;
|
pImpl = NULL;
|
||||||
|
|
||||||
|
/* Reset used last; otherwise, a thread creation might pick up the slot. */
|
||||||
|
used = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *GetThreadName() const;
|
const char *GetThreadName() const;
|
||||||
@@ -109,11 +113,8 @@ const char *ThreadSlot::GetFormattedCheckpoint( int lineno )
|
|||||||
static ThreadSlot g_ThreadSlots[MAX_THREADS];
|
static ThreadSlot g_ThreadSlots[MAX_THREADS];
|
||||||
struct ThreadSlot *g_pUnknownThreadSlot = NULL;
|
struct ThreadSlot *g_pUnknownThreadSlot = NULL;
|
||||||
|
|
||||||
/* This locks all unused thread slots; once a slot is marked "used", this is no longer
|
/* Lock this mutex before using or modifying pImpl. Other values are just identifiers,
|
||||||
* relevant. A thread must be fully set up before being marked used. This is intended
|
* so possibly racing over them is harmless (simply using a stale thread ID, etc). */
|
||||||
* to allow access to g_ThreadSlots without locking, since GetThreadSlotFromID is called
|
|
||||||
* on every CHECKPOINT. (XXX: there are race conditions on Wait(); I wish TLS was
|
|
||||||
* more standard ...) */
|
|
||||||
static RageMutex g_ThreadSlotsLock("ThreadSlots");
|
static RageMutex g_ThreadSlotsLock("ThreadSlots");
|
||||||
|
|
||||||
static int FindEmptyThreadSlot()
|
static int FindEmptyThreadSlot()
|
||||||
@@ -136,9 +137,7 @@ static ThreadSlot *GetThreadSlotFromID( uint64_t iID )
|
|||||||
{
|
{
|
||||||
if( !g_ThreadSlots[entry].used )
|
if( !g_ThreadSlots[entry].used )
|
||||||
continue;
|
continue;
|
||||||
if( &g_ThreadSlots[entry] == g_pUnknownThreadSlot )
|
if( g_ThreadSlots[entry].id == iID )
|
||||||
continue;
|
|
||||||
if( g_ThreadSlots[entry].pImpl->GetThreadId() == iID )
|
|
||||||
return &g_ThreadSlots[entry];
|
return &g_ThreadSlots[entry];
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -196,6 +195,7 @@ void RageThread::Create( int (*fn)(void *), void *data )
|
|||||||
|
|
||||||
/* Start a thread using our own startup function. */
|
/* Start a thread using our own startup function. */
|
||||||
m_pSlot->pImpl = MakeThread( fn, data );
|
m_pSlot->pImpl = MakeThread( fn, data );
|
||||||
|
m_pSlot->id = m_pSlot->pImpl->GetThreadId();
|
||||||
sprintf( m_pSlot->ThreadFormattedOutput, "Thread: %s", name.c_str() );
|
sprintf( m_pSlot->ThreadFormattedOutput, "Thread: %s", name.c_str() );
|
||||||
|
|
||||||
/* Only after everything in the slot is valid, mark the slot used, so all
|
/* Only after everything in the slot is valid, mark the slot used, so all
|
||||||
@@ -225,6 +225,7 @@ static struct SetupUnknownThread
|
|||||||
LockMut(g_ThreadSlotsLock);
|
LockMut(g_ThreadSlotsLock);
|
||||||
int slot = FindEmptyThreadSlot();
|
int slot = FindEmptyThreadSlot();
|
||||||
strcpy( g_ThreadSlots[slot].name, "Unknown thread" );
|
strcpy( g_ThreadSlots[slot].name, "Unknown thread" );
|
||||||
|
g_ThreadSlots[slot].id = GetInvalidThreadId();
|
||||||
g_pUnknownThreadSlot = &g_ThreadSlots[slot];
|
g_pUnknownThreadSlot = &g_ThreadSlots[slot];
|
||||||
sprintf( g_ThreadSlots[slot].ThreadFormattedOutput, "Unknown thread" );
|
sprintf( g_ThreadSlots[slot].ThreadFormattedOutput, "Unknown thread" );
|
||||||
g_ThreadSlots[slot].used = true;
|
g_ThreadSlots[slot].used = true;
|
||||||
@@ -251,6 +252,8 @@ int RageThread::Wait()
|
|||||||
ASSERT( m_pSlot->pImpl != NULL );
|
ASSERT( m_pSlot->pImpl != NULL );
|
||||||
int ret = m_pSlot->pImpl->Wait();
|
int ret = m_pSlot->pImpl->Wait();
|
||||||
|
|
||||||
|
LockMut(g_ThreadSlotsLock);
|
||||||
|
|
||||||
delete m_pSlot->pImpl;
|
delete m_pSlot->pImpl;
|
||||||
m_pSlot->pImpl = NULL;
|
m_pSlot->pImpl = NULL;
|
||||||
m_pSlot->Init();
|
m_pSlot->Init();
|
||||||
@@ -267,9 +270,7 @@ void RageThread::HaltAllThreads( bool Kill )
|
|||||||
{
|
{
|
||||||
if( !g_ThreadSlots[entry].used )
|
if( !g_ThreadSlots[entry].used )
|
||||||
continue;
|
continue;
|
||||||
if( &g_ThreadSlots[entry] == g_pUnknownThreadSlot )
|
if( ThisThreadID == g_ThreadSlots[entry].id )
|
||||||
continue;
|
|
||||||
if( ThisThreadID == g_ThreadSlots[entry].pImpl->GetThreadId() )
|
|
||||||
continue;
|
continue;
|
||||||
g_ThreadSlots[entry].pImpl->Halt( Kill );
|
g_ThreadSlots[entry].pImpl->Halt( Kill );
|
||||||
}
|
}
|
||||||
@@ -282,9 +283,7 @@ void RageThread::ResumeAllThreads()
|
|||||||
{
|
{
|
||||||
if( !g_ThreadSlots[entry].used )
|
if( !g_ThreadSlots[entry].used )
|
||||||
continue;
|
continue;
|
||||||
if( &g_ThreadSlots[entry] == g_pUnknownThreadSlot )
|
if( ThisThreadID == g_ThreadSlots[entry].id )
|
||||||
continue;
|
|
||||||
if( ThisThreadID == g_ThreadSlots[entry].pImpl->GetThreadId() )
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
g_ThreadSlots[entry].pImpl->Resume();
|
g_ThreadSlots[entry].pImpl->Resume();
|
||||||
@@ -529,8 +528,13 @@ void RageMutex::Lock()
|
|||||||
OtherSlot? OtherSlot->GetThreadName(): "(???" ")" );
|
OtherSlot? OtherSlot->GetThreadName(): "(???" ")" );
|
||||||
|
|
||||||
#if defined(CRASH_HANDLER) && !defined(DARWIN)
|
#if defined(CRASH_HANDLER) && !defined(DARWIN)
|
||||||
|
/* Don't leave g_ThreadSlotsLock when we call ForceCrashHandlerDeadlock. */
|
||||||
|
g_ThreadSlotsLock.Lock();
|
||||||
|
uint64_t CrashHandle = OtherSlot? OtherSlot->pImpl->GetCrashHandle():0;
|
||||||
|
g_ThreadSlotsLock.Unlock();
|
||||||
|
|
||||||
/* Pass the crash handle of the other thread, so it can backtrace that thread. */
|
/* Pass the crash handle of the other thread, so it can backtrace that thread. */
|
||||||
ForceCrashHandlerDeadlock( sReason, OtherSlot? OtherSlot->pImpl->GetCrashHandle():0 );
|
ForceCrashHandlerDeadlock( sReason, CrashHandle );
|
||||||
#else
|
#else
|
||||||
RageException::Throw( "%s", sReason.c_str() );
|
RageException::Throw( "%s", sReason.c_str() );
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user