static void InitThreads() { /* We don't have to worry about two threads calling this at once, since it's * called when we create a thread. */ static bool bInitialized = false; if( bInitialized ) return; g_ThreadSlotsLock.Lock(); /* Libraries might start threads on their own, which might call user callbacks, * which could come back here. Make sure we don't accidentally initialize twice. */ if( bInitialized ) { g_ThreadSlotsLock.Unlock(); return; } bInitialized = true; /* Register the "unknown thread" slot. */ int slot = FindEmptyThreadSlot(); strcpy( g_ThreadSlots[slot].name, "Unknown thread" ); g_ThreadSlots[slot].id = GetInvalidThreadId(); sprintf( g_ThreadSlots[slot].ThreadFormattedOutput, "Unknown thread" ); g_pUnknownThreadSlot = &g_ThreadSlots[slot]; g_ThreadSlotsLock.Unlock(); }
void CrashHandler::ForceDeadlock( RString reason, uint64_t iID ) { CrashData crash; memset( &crash, 0, sizeof(crash) ); crash.type = CrashData::FORCE_CRASH; GetBacktrace( crash.BacktracePointers[0], BACKTRACE_MAX_SIZE, NULL ); if( iID == GetInvalidThreadId() ) { /* Backtrace all threads. */ BacktraceAllThreads( crash ); } else { BacktraceContext ctx; if( !GetThreadBacktraceContext( iID, &ctx ) ) reason += "; GetThreadBacktraceContext failed"; else GetBacktrace( crash.BacktracePointers[1], BACKTRACE_MAX_SIZE, &ctx ); strncpy( crash.m_ThreadName[1], RageThread::GetThreadNameByID(iID), sizeof(crash.m_ThreadName[0])-1 ); } strncpy( crash.m_ThreadName[0], RageThread::GetCurrentThreadName(), sizeof(crash.m_ThreadName[0])-1 ); strncpy( crash.reason, reason, min(sizeof(crash.reason) - 1, reason.length()) ); crash.reason[ sizeof(crash.reason)-1 ] = 0; RunCrashHandler( &crash ); _exit( 1 ); }
void Init() { id = GetInvalidThreadId(); CurCheckpoint = NumCheckpoints = 0; pImpl = NULL; /* Reset used last; otherwise, a thread creation might pick up the slot. */ used = false; }
void RageMutex::Unlock() { if( m_LockCnt ) { --m_LockCnt; return; } m_LockedBy = GetInvalidThreadId(); m_pMutex->Unlock(); }
bool RageThread::EnumThreadIDs( int n, uint64_t &iID ) { if( n >= MAX_THREADS ) return false; LockMut(g_ThreadSlotsLock); const ThreadSlot *slot = &g_ThreadSlots[n]; if( slot->used ) iID = slot->id; else iID = GetInvalidThreadId(); return true; }
void RageSemaphore::Wait( bool bFailOnTimeout ) { retry: if( m_pSema->Wait() ) return; if( !bFailOnTimeout || Dialog::IsShowingDialog() ) goto retry; /* We waited too long. We're probably deadlocked, though unlike mutexes, we can't * tell which thread we're stuck on. */ const ThreadSlot *ThisSlot = GetThreadSlotFromID( GetThisThreadId() ); const CString sReason = ssprintf( "Semaphore timeout on mutex %s on thread %s", GetName().c_str(), ThisSlot? ThisSlot->GetThreadName(): "(???" ")" ); // stupid trigraph warnings #if defined(CRASH_HANDLER) ForceCrashHandlerDeadlock( sReason, GetInvalidThreadId() ); #else RageException::Throw( "%s", sReason.c_str() ); #endif }
static void BacktraceAllThreads( CrashData& crash ) { int iCnt = 1; uint64_t iID; for( int i = 0; RageThread::EnumThreadIDs(i, iID); ++i ) { if( iID == GetInvalidThreadId() || iID == RageThread::GetCurrentThreadID() ) continue; BacktraceContext ctx; if( GetThreadBacktraceContext( iID, &ctx ) ) GetBacktrace( crash.BacktracePointers[iCnt], BACKTRACE_MAX_SIZE, &ctx ); strncpy( crash.m_ThreadName[iCnt], RageThread::GetThreadNameByID(iID), sizeof(crash.m_ThreadName[0])-1 ); ++iCnt; if( iCnt == CrashData::MAX_BACKTRACE_THREADS ) break; } }
RageMutex::RageMutex( const CString name ): m_sName( name ) { m_pMutex = MakeMutex( this ); m_LockedBy = GetInvalidThreadId(); m_LockCnt = 0; /* if( g_FreeMutexIDs == NULL ) { g_FreeMutexIDs = new set<int>; for( int i = 0; i < MAX_MUTEXES; ++i ) g_FreeMutexIDs->insert( i ); } if( g_FreeMutexIDs->empty() ) { ASSERT_M( g_MutexList, "!g_FreeMutexIDs but !g_MutexList?" ); // doesn't make sense to be out of mutexes yet never created any CString s; for( unsigned i = 0; i < g_MutexList->size(); ++i ) { if( i ) s += ", "; s += ssprintf( "\"%s\"", (*g_MutexList)[i]->GetName().c_str() ); } LOG->Trace( "%s", s.c_str() ); FAIL_M( ssprintf("MAX_MUTEXES exceeded creating \"%s\"", name.c_str() ) ); } m_UniqueID = *g_FreeMutexIDs->begin(); g_FreeMutexIDs->erase( g_FreeMutexIDs->begin() ); if( g_MutexList == NULL ) g_MutexList = new vector<RageMutex*>; g_MutexList->push_back( this ); */ }