#ifndef RAGE_THREADS_H #define RAGE_THREADS_H struct ThreadSlot; class RageTimer; /** @brief Thread, mutex, semaphore, and event classes. */ class RageThread { public: RageThread(); RageThread( const RageThread &cpy ); ~RageThread(); void SetName( const RString &n ) { m_sName = n; } RString GetName() const { return m_sName; } void Create( int (*fn)(void *), void *data ); void Halt( bool Kill=false); void Resume(); /* For crash handlers: kill or suspend all threads (except for * the running one) immediately. */ static void HaltAllThreads( bool Kill=false ); /* If HaltAllThreads was called (with Kill==false), resume. */ static void ResumeAllThreads(); static uint64_t GetCurrentThreadID(); static const char *GetCurrentThreadName(); static const char *GetThreadNameByID( uint64_t iID ); static bool EnumThreadIDs( int n, uint64_t &iID ); int Wait(); bool IsCreated() const { return m_pSlot != NULL; } /* A system can define HAVE_TLS, indicating that it can compile thread_local * code, but an individual environment may not actually have functional TLS. * If this returns false, thread_local variables are considered undefined. */ static bool GetSupportsTLS() { return s_bSystemSupportsTLS; } static void SetSupportsTLS( bool b ) { s_bSystemSupportsTLS = b; } static bool GetIsShowingDialog() { return s_bIsShowingDialog; } static void SetIsShowingDialog( bool b ) { s_bIsShowingDialog = b; } static uint64_t GetInvalidThreadID(); private: ThreadSlot *m_pSlot; RString m_sName; static bool s_bSystemSupportsTLS; static bool s_bIsShowingDialog; // Swallow up warnings. If they must be used, define them. RageThread& operator=(const RageThread& rhs); }; /** * @brief Register a thread created outside of RageThread. * * This gives it a name for RageThread::GetCurrentThreadName, * and allocates a slot for checkpoints. */ class RageThreadRegister { public: RageThreadRegister( const RString &sName ); ~RageThreadRegister(); private: ThreadSlot *m_pSlot; // Swallow up warnings. If they must be used, define them. RageThreadRegister& operator=(const RageThreadRegister& rhs); RageThreadRegister(const RageThreadRegister& rhs); }; namespace Checkpoints { void LogCheckpoints( bool yes=true ); void SetCheckpoint( const char *file, int line, const char *message ); void GetLogs( char *pBuf, int iSize, const char *delim ); }; #define CHECKPOINT (Checkpoints::SetCheckpoint(__FILE__, __LINE__, NULL)) #define CHECKPOINT_M(m) (Checkpoints::SetCheckpoint(__FILE__, __LINE__, m)) /* Mutex class that follows the behavior of Windows mutexes: if the same * thread locks the same mutex twice, we just increase a refcount; a mutex * is considered unlocked when the refcount reaches zero. This is more * convenient, though much slower on some archs. (We don't have any tightly- * coupled threads, so that's OK.) */ class MutexImpl; class RageMutex { public: RString GetName() const { return m_sName; } void SetName( const RString &s ) { m_sName = s; } virtual void Lock(); virtual bool TryLock(); virtual void Unlock(); virtual bool IsLockedByThisThread() const; RageMutex( const RString &name ); virtual ~RageMutex(); protected: MutexImpl *m_pMutex; RString m_sName; int m_UniqueID; uint64_t m_LockedBy; int m_LockCnt; void MarkLockedMutex(); private: // Swallow up warnings. If they must be used, define them. RageMutex& operator=(const RageMutex& rhs); RageMutex(const RageMutex& rhs); }; /** * @brief Lock a mutex on construction, unlock it on destruction. * * Helps for functions with more than one return path. */ class LockMutex { RageMutex &mutex; const char *file; int line; float locked_at; bool locked; public: LockMutex(RageMutex &mut, const char *file, int line); LockMutex(RageMutex &mut): mutex(mut), file(NULL), line(-1), locked_at(-1), locked(true) { mutex.Lock(); } ~LockMutex(); LockMutex(LockMutex &cpy): mutex(cpy.mutex), file(NULL), line(-1), locked_at(cpy.locked_at), locked(true) { mutex.Lock(); } /** * @brief Unlock the mutex (before this would normally go out of scope). * * This can only be called once. */ void Unlock(); private: // Swallow up warnings. If they must be used, define them. LockMutex& operator=(const LockMutex& rhs); }; #define LockMut(m) LockMutex UNIQUE_NAME(LocalLock) (m, __FILE__, __LINE__) class EventImpl; class RageEvent: public RageMutex { public: RageEvent( RString name ); ~RageEvent(); /* * If pTimeout is non-NULL, the event will be automatically signalled at the given * time. Note that implementing this timeout is optional; not all archs support it. * If false is returned, the wait timed out (and the mutex is locked, as if the * event had been signalled). */ bool Wait( RageTimer *pTimeout = NULL ); void Signal(); void Broadcast(); bool WaitTimeoutSupported() const; // Swallow up warnings. If they must be used, define them. RageEvent& operator=(const RageEvent& rhs); RageEvent(const RageEvent& rhs); private: EventImpl *m_pEvent; }; class SemaImpl; class RageSemaphore { public: RageSemaphore( RString sName, int iInitialValue = 0 ); ~RageSemaphore(); RString GetName() const { return m_sName; } int GetValue() const; void Post(); void Wait( bool bFailOnTimeout=true ); bool TryWait(); private: SemaImpl *m_pSema; RString m_sName; // Swallow up warnings. If they must be used, define them. RageSemaphore& operator=(const RageSemaphore& rhs); RageSemaphore(const RageSemaphore& rhs); }; #endif /** * @file * @author Glenn Maynard (c) 2001-2004 * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, and/or sell copies of the Software, and to permit persons to * whom the Software is furnished to do so, provided that the above * copyright notice(s) and this permission notice appear in all copies of * the Software and that both the above copyright notice(s) and this * permission notice appear in supporting documentation. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */