fix various races
This commit is contained in:
@@ -124,6 +124,7 @@ static int FindEmptyThreadSlot()
|
|||||||
if( g_ThreadSlots[entry].used )
|
if( g_ThreadSlots[entry].used )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
g_ThreadSlots[entry].used = true;
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,7 +155,6 @@ static void InitThreads()
|
|||||||
strcpy( g_ThreadSlots[slot].name, "Unknown thread" );
|
strcpy( g_ThreadSlots[slot].name, "Unknown thread" );
|
||||||
g_ThreadSlots[slot].id = GetInvalidThreadId();
|
g_ThreadSlots[slot].id = GetInvalidThreadId();
|
||||||
sprintf( g_ThreadSlots[slot].ThreadFormattedOutput, "Unknown thread" );
|
sprintf( g_ThreadSlots[slot].ThreadFormattedOutput, "Unknown thread" );
|
||||||
g_ThreadSlots[slot].used = true;
|
|
||||||
g_pUnknownThreadSlot = &g_ThreadSlots[slot];
|
g_pUnknownThreadSlot = &g_ThreadSlots[slot];
|
||||||
|
|
||||||
g_ThreadSlotsLock.Unlock();
|
g_ThreadSlotsLock.Unlock();
|
||||||
@@ -227,14 +227,12 @@ void RageThread::Create( int (*fn)(void *), void *data )
|
|||||||
strcpy( m_pSlot->name, name.c_str() );
|
strcpy( m_pSlot->name, name.c_str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Start a thread using our own startup function. */
|
|
||||||
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
|
/* Start a thread using our own startup function. We pass the id to fill in,
|
||||||
* "used" slots have a valid pImpl. */
|
* to make sure it's set before the thread actually starts. (Otherwise, early
|
||||||
g_ThreadSlots[slotno].used = true;
|
* checkpoints might not have a completely set-up thread slot.) */
|
||||||
|
m_pSlot->pImpl = MakeThread( fn, data, &m_pSlot->id );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* On startup, register the main thread's slot. We do this in a static constructor,
|
/* On startup, register the main thread's slot. We do this in a static constructor,
|
||||||
@@ -249,7 +247,6 @@ static struct SetupMainThread
|
|||||||
sprintf( g_ThreadSlots[slot].ThreadFormattedOutput, "Thread: %s", g_ThreadSlots[slot].name );
|
sprintf( g_ThreadSlots[slot].ThreadFormattedOutput, "Thread: %s", g_ThreadSlots[slot].name );
|
||||||
g_ThreadSlots[slot].pImpl = MakeThisThread();
|
g_ThreadSlots[slot].pImpl = MakeThisThread();
|
||||||
g_ThreadSlots[slot].id = RageThread::GetCurrentThreadID();
|
g_ThreadSlots[slot].id = RageThread::GetCurrentThreadID();
|
||||||
g_ThreadSlots[slot].used = true;
|
|
||||||
}
|
}
|
||||||
} SetupMainThreadObj;
|
} SetupMainThreadObj;
|
||||||
|
|
||||||
@@ -552,7 +549,7 @@ void RageMutex::Lock()
|
|||||||
#if defined(CRASH_HANDLER) && !defined(DARWIN)
|
#if defined(CRASH_HANDLER) && !defined(DARWIN)
|
||||||
/* Don't leave g_ThreadSlotsLock when we call ForceCrashHandlerDeadlock. */
|
/* Don't leave g_ThreadSlotsLock when we call ForceCrashHandlerDeadlock. */
|
||||||
g_ThreadSlotsLock.Lock();
|
g_ThreadSlotsLock.Lock();
|
||||||
uint64_t CrashHandle = OtherSlot? OtherSlot->pImpl->GetCrashHandle():0;
|
uint64_t CrashHandle = OtherSlot && OtherSlot->pImpl? OtherSlot->pImpl->GetCrashHandle():0;
|
||||||
g_ThreadSlotsLock.Unlock();
|
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. */
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* These functions must be implemented by the thread implementation. */
|
/* These functions must be implemented by the thread implementation. */
|
||||||
ThreadImpl *MakeThread( int (*fn)(void *), void *data );
|
ThreadImpl *MakeThread( int (*fn)(void *), void *data, uint64_t *piThreadID );
|
||||||
ThreadImpl *MakeThisThread();
|
ThreadImpl *MakeThisThread();
|
||||||
MutexImpl *MakeMutex( RageMutex *pParent );
|
MutexImpl *MakeMutex( RageMutex *pParent );
|
||||||
SemaImpl *MakeSemaphore( int iInitialValue );
|
SemaImpl *MakeSemaphore( int iInitialValue );
|
||||||
|
|||||||
@@ -93,20 +93,32 @@ static void *StartThread( void *pData )
|
|||||||
pThis->MachThreadHandle = mach_thread_self();
|
pThis->MachThreadHandle = mach_thread_self();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
*pThis->m_piThreadID = pThis->GetThreadId();
|
||||||
|
|
||||||
|
fprintf(stderr, "set %i\n", (int) pThis->GetThreadId() );
|
||||||
|
/* Tell MakeThread that we've set m_piThreadID, so it's safe to return. */
|
||||||
|
sem_post( &pThis->m_StartFinishedSem );
|
||||||
|
|
||||||
return (void *) pThis->m_pFunc( pThis->m_pData );
|
return (void *) pThis->m_pFunc( pThis->m_pData );
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadImpl *MakeThread( int (*pFunc)(void *pData), void *pData )
|
ThreadImpl *MakeThread( int (*pFunc)(void *pData), void *pData, uint64_t *piThreadID )
|
||||||
{
|
{
|
||||||
ThreadImpl_Pthreads *thread = new ThreadImpl_Pthreads;
|
ThreadImpl_Pthreads *thread = new ThreadImpl_Pthreads;
|
||||||
thread->m_pFunc = pFunc;
|
thread->m_pFunc = pFunc;
|
||||||
thread->m_pData = pData;
|
thread->m_pData = pData;
|
||||||
|
thread->m_piThreadID = piThreadID;
|
||||||
|
sem_init( &thread->m_StartFinishedSem, 0, 0 );
|
||||||
|
|
||||||
int ret = pthread_create( &thread->thread, NULL, StartThread, thread );
|
int ret = pthread_create( &thread->thread, NULL, StartThread, thread );
|
||||||
if( ret )
|
if( ret )
|
||||||
RageException::Throw( "pthread_create: %s", strerror(ret) );
|
RageException::Throw( "pthread_create: %s", strerror(ret) );
|
||||||
|
|
||||||
/* XXX: don't return until StartThread sets pid, etc */
|
/* Don't return until StartThread sets m_piThreadID. */
|
||||||
|
ret = sem_wait( &thread->m_StartFinishedSem );
|
||||||
|
if( ret )
|
||||||
|
RageException::Throw( "MakeThread(): sem_wait: %s", strerror(ret) );
|
||||||
|
sem_destroy( &thread->m_StartFinishedSem );
|
||||||
|
|
||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
@@ -168,7 +180,6 @@ bool MutexImpl_Pthreads::Lock()
|
|||||||
int ret;
|
int ret;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
CHECKPOINT;
|
|
||||||
ret = pthread_mutex_lock( &mutex );
|
ret = pthread_mutex_lock( &mutex );
|
||||||
}
|
}
|
||||||
while( ret == -1 && ret == EINTR );
|
while( ret == -1 && ret == EINTR );
|
||||||
@@ -240,7 +251,6 @@ bool SemaImpl_Pthreads::Wait()
|
|||||||
int ret;
|
int ret;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
CHECKPOINT;
|
|
||||||
ret = sem_wait( &sem );
|
ret = sem_wait( &sem );
|
||||||
}
|
}
|
||||||
while( ret == -1 && errno == EINTR );
|
while( ret == -1 && errno == EINTR );
|
||||||
|
|||||||
@@ -26,8 +26,11 @@ public:
|
|||||||
thread_act_t MachThreadHandle;
|
thread_act_t MachThreadHandle;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* These are only used during initialization. */
|
||||||
int (*m_pFunc)( void *pData );
|
int (*m_pFunc)( void *pData );
|
||||||
void *m_pData;
|
void *m_pData;
|
||||||
|
uint64_t *m_piThreadID;
|
||||||
|
sem_t m_StartFinishedSem;
|
||||||
|
|
||||||
void Halt( bool Kill );
|
void Halt( bool Kill );
|
||||||
void Resume();
|
void Resume();
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ ThreadImpl *MakeThisThread()
|
|||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadImpl *MakeThread( int (*pFunc)(void *pData), void *pData )
|
ThreadImpl *MakeThread( int (*pFunc)(void *pData), void *pData, uint64_t *piThreadID )
|
||||||
{
|
{
|
||||||
ThreadImpl_Win32 *thread = new ThreadImpl_Win32;
|
ThreadImpl_Win32 *thread = new ThreadImpl_Win32;
|
||||||
thread->m_pFunc = pFunc;
|
thread->m_pFunc = pFunc;
|
||||||
|
|||||||
Reference in New Issue
Block a user