From 37c8ea54ebfe28b0d84756b88fdf97600a096ea4 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 9 Aug 2012 06:30:31 +0200 Subject: [PATCH] Add AIThreadID - Cleanup of apr_os_thread* related code. Apart from just really cleaning things up and moving everything into one class regarding thread IDs (ie, is_main_thread(), comparing ID's etc), this also fixes an obscure bug where LL was casting thread ID's to U32 and then compared those to find out if it the same thread. It's theoretically possible that such fails on a 64bit OS. By generalizing the interface, I adopted the use of a thread-local cache for the current thread ID as used by LLMutex et al, so now all code benefits from that. The idea was even extended to now also be used for is_main_thread() tests and even resetting a thread ID to the ID of the current thread. --- indra/cwdebug/debug.h | 15 +-- indra/llcommon/CMakeLists.txt | 8 +- indra/llcommon/aithreadid.cpp | 70 ++++++++++++++ indra/llcommon/aithreadid.h | 91 +++++++++++++++++++ indra/llcommon/aithreadsafe.h | 6 +- indra/llcommon/llaprpool.cpp | 6 +- indra/llcommon/llaprpool.h | 16 ++-- indra/llcommon/llerror.h | 4 - indra/llcommon/llframetimer.h | 3 + indra/llcommon/llthread.cpp | 83 ++++++++--------- indra/llcommon/llthread.h | 38 ++------ indra/newview/statemachine/aistatemachine.cpp | 10 +- indra/newview/statemachine/aistatemachine.h | 6 +- 13 files changed, 246 insertions(+), 110 deletions(-) create mode 100644 indra/llcommon/aithreadid.cpp create mode 100644 indra/llcommon/aithreadid.h diff --git a/indra/cwdebug/debug.h b/indra/cwdebug/debug.h index 4161e18f7..b704c811d 100644 --- a/indra/cwdebug/debug.h +++ b/indra/cwdebug/debug.h @@ -49,6 +49,7 @@ #else // LL_COMMON_LINK_SHARED #error LL_COMMON_LINK_SHARED not defined #endif // LL_COMMON_LINK_SHARED +#include "aithreadid.h" // If CWDEBUG is not defined, but DEBUG_CURLIO is, then replace // some of the cwd macro's with something that generates viewer @@ -104,23 +105,23 @@ struct fake_channel { void on() const { } void off() const { } }; -extern CWD_API fake_channel const warning; -extern CWD_API fake_channel const curl; -extern CWD_API fake_channel const curlio; -extern CWD_API fake_channel const statemachine; -extern CWD_API fake_channel const notice; +extern LL_COMMON_API fake_channel const warning; +extern LL_COMMON_API fake_channel const curl; +extern LL_COMMON_API fake_channel const curlio; +extern LL_COMMON_API fake_channel const statemachine; +extern LL_COMMON_API fake_channel const notice; } // namespace dc } // namespace debug #define Debug(x) do { using namespace debug; x; } while(0) -#define Dout(a, b) do { using namespace debug; if ((a).mOn) { llinfos_nf << (a).mLabel << ": " << Indent::print << b << llendl; } } while(0) +#define Dout(a, b) do { using namespace debug; if ((a).mOn) { llinfos_nf << AIThreadID::DoutPrint << (a).mLabel << ": " << Indent::print << b << llendl; } } while(0) #define DoutEntering(a, b) \ int __slviewer_debug_indentation = 2; \ { \ using namespace debug; \ if ((a).mOn) \ - llinfos_nf << (a).mLabel << ": " << Indent::print << "Entering " << b << llendl; \ + llinfos_nf << AIThreadID::DoutPrint << (a).mLabel << ": " << Indent::print << "Entering " << b << llendl; \ else \ __slviewer_debug_indentation = 0; \ } \ diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 4be690734..cf1e564ae 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -15,8 +15,9 @@ include_directories( ) set(llcommon_SOURCE_FILES - aiframetimer.cpp - imageids.cpp + aiframetimer.cpp + aithreadid.cpp + imageids.cpp indra_constants.cpp llallocator.cpp llallocator_heap_profile.cpp @@ -24,7 +25,7 @@ set(llcommon_SOURCE_FILES llapr.cpp llaprpool.cpp llassettype.cpp - llavatarname.cpp + llavatarname.cpp llbase32.cpp llbase64.cpp llcommon.cpp @@ -103,6 +104,7 @@ set(llcommon_HEADER_FILES CMakeLists.txt aiframetimer.h + aithreadid.h aithreadsafe.h bitpack.h ctype_workaround.h diff --git a/indra/llcommon/aithreadid.cpp b/indra/llcommon/aithreadid.cpp new file mode 100644 index 000000000..dfb4a2660 --- /dev/null +++ b/indra/llcommon/aithreadid.cpp @@ -0,0 +1,70 @@ +/** + * @file aithreadid.cpp + * + * Copyright (c) 2012, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 08/08/2012 + * - Initial version, written by Aleric Inglewood @ SL + */ + +#include "sys.h" +#include +#include +#include "aithreadid.h" + +AIThreadID const AIThreadID::sNone(AIThreadID::none); +apr_os_thread_t AIThreadID::sMainThreadID; +#ifndef LL_DARWIN +apr_os_thread_t ll_thread_local AIThreadID::lCurrentThread = AIThreadID::undefinedID; +#endif + +void AIThreadID::set_main_thread_id(void) +{ + sMainThreadID = apr_os_thread_current(); +} + +void AIThreadID::set_current_thread_id(void) +{ +#ifndef LL_DARWIN + lCurrentThread = apr_os_thread_current(); +#endif +} + +std::ostream& operator<<(std::ostream& os, AIThreadID const& id) +{ + return os << id.mID; +} + +std::ostream& operator<<(std::ostream& os, AIThreadID::dout_print_t) +{ + if (!AIThreadID::in_main_thread()) + { +#ifdef LL_DARWIN + os << std::hex << (size_t)apr_os_thread_current() << std::dec << ' '; +#else + os << std::hex << (size_t)AIThreadID::lCurrentThread << std::dec << ' '; +#endif + } + return os; +} + diff --git a/indra/llcommon/aithreadid.h b/indra/llcommon/aithreadid.h new file mode 100644 index 000000000..c565b5913 --- /dev/null +++ b/indra/llcommon/aithreadid.h @@ -0,0 +1,91 @@ +/** + * @file aithreadid.h + * @brief Declaration of AIThreadID. + * + * Copyright (c) 2012, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 08/08/2012 + * Initial version, written by Aleric Inglewood @ SL + */ + +#ifndef AI_THREAD_ID +#define AI_THREAD_ID + +#include // apr_os_thread_t, apr_os_thread_current(), apr_os_thread_equal(). +#include // std::ostream. +#include "llpreprocessor.h" // LL_COMMON_API +#include "llerror.h" + +#if LL_WINDOWS +#define ll_thread_local __declspec(thread) +#else +#define ll_thread_local __thread +#endif + +// Lightweight wrapper around apr_os_thread_t. +// This class introduces no extra assembly code after optimization; it's only intend is to provide type-safety. +class LL_COMMON_API AIThreadID +{ +private: + apr_os_thread_t mID; + static apr_os_thread_t sMainThreadID; + static apr_os_thread_t const undefinedID = (apr_os_thread_t)-1; +#ifndef LL_DARWIN + static ll_thread_local apr_os_thread_t lCurrentThread; +#endif +public: + static AIThreadID const sNone; + enum undefined_thread_t { none }; + enum dout_print_t { DoutPrint }; + +public: + AIThreadID(void) : mID(apr_os_thread_current()) { } + explicit AIThreadID(undefined_thread_t) : mID(undefinedID) { } // Used for sNone. + AIThreadID(AIThreadID const& id) : mID(id.mID) { } + AIThreadID& operator=(AIThreadID const& id) { mID = id.mID; return *this; } + bool is_main_thread(void) const { return apr_os_thread_equal(mID, sMainThreadID); } + bool is_no_thread(void) const { return apr_os_thread_equal(mID, sNone.mID); } + friend LL_COMMON_API bool operator==(AIThreadID const& id1, AIThreadID const& id2) { return apr_os_thread_equal(id1.mID, id2.mID); } + friend LL_COMMON_API bool operator!=(AIThreadID const& id1, AIThreadID const& id2) { return !apr_os_thread_equal(id1.mID, id2.mID); } + friend LL_COMMON_API std::ostream& operator<<(std::ostream& os, AIThreadID const& id); + friend LL_COMMON_API std::ostream& operator<<(std::ostream& os, dout_print_t); + static void set_main_thread_id(void); // Called once to set sMainThreadID. + static void set_current_thread_id(void); // Called once for every thread to set lCurrentThread. +#ifdef LL_DARWIN + void reset(void) { mID = apr_os_thread_current(); } + bool equals_current_thread(void) const { return apr_os_thread_equal(mID, apr_os_thread_current()); } + static bool in_main_thread(void) { return apr_os_thread_equal(apr_os_thread_current(), sMainThreadID); } +#else + void reset(void) { mID = lCurrentThread; } + bool equals_current_thread(void) const { return apr_os_thread_equal(mID, lCurrentThread); } + static bool in_main_thread(void) { return apr_os_thread_equal(lCurrentThread, sMainThreadID); } +#endif +}; + +// Legacy function. +inline bool is_main_thread(void) +{ + return AIThreadID::in_main_thread(); +} + +#endif // AI_THREAD_ID diff --git a/indra/llcommon/aithreadsafe.h b/indra/llcommon/aithreadsafe.h index b7d0045cb..02bfa8cd7 100644 --- a/indra/llcommon/aithreadsafe.h +++ b/indra/llcommon/aithreadsafe.h @@ -673,18 +673,18 @@ protected: #ifdef LL_DEBUG mutable bool mAccessed; - mutable apr_os_thread_t mTheadID; + mutable AIThreadID mTheadID; void accessed(void) const { if (!mAccessed) { mAccessed = true; - mTheadID = apr_os_thread_current(); + mTheadID.reset(); } else { - llassert_always(apr_os_thread_equal(mTheadID, apr_os_thread_current())); + llassert_always(mTheadID.equals_current_thread()); } } #endif diff --git a/indra/llcommon/llaprpool.cpp b/indra/llcommon/llaprpool.cpp index 3559ff430..de5761157 100644 --- a/indra/llcommon/llaprpool.cpp +++ b/indra/llcommon/llaprpool.cpp @@ -60,10 +60,10 @@ void LLAPRPool::create(LLAPRPool& parent) // // In other words, it's safe for any thread to create a (sub)pool, independent of who // owns the parent pool. - mOwner = apr_os_thread_current(); + mOwner.reset(); #else mOwner = mParent->mOwner; - llassert(apr_os_thread_equal(mOwner, apr_os_thread_current())); + llassert(mOwner.equals_current_thread()); #endif apr_status_t const apr_pool_create_status = apr_pool_create(&mPool, mParent->mPool); llassert_always(apr_pool_create_status == APR_SUCCESS); @@ -83,7 +83,7 @@ void LLAPRPool::destroy(void) // of course. Otherwise, if we are a subpool, only the thread that owns // the parent may destruct us, since that is the pool that is still alive, // possibly being used by others and being altered here. - llassert(!mParent || apr_os_thread_equal(mParent->mOwner, apr_os_thread_current())); + llassert(!mParent || mParent->mOwner.equals_current_thread()); #endif apr_pool_t* pool = mPool; mPool = NULL; // Mark that we are BEING destructed. diff --git a/indra/llcommon/llaprpool.h b/indra/llcommon/llaprpool.h index dc123e942..4c9f36893 100644 --- a/indra/llcommon/llaprpool.h +++ b/indra/llcommon/llaprpool.h @@ -62,22 +62,22 @@ class LL_COMMON_API LLAPRPool protected: apr_pool_t* mPool; //!< Pointer to the underlaying pool. NULL if not initialized. LLAPRPool* mParent; //!< Pointer to the parent pool, if any. Only valid when mPool is non-zero. - apr_os_thread_t mOwner; //!< The thread that owns this memory pool. Only valid when mPool is non-zero. + AIThreadID mOwner; //!< The thread that owns this memory pool. Only valid when mPool is non-zero. public: //! Construct an uninitialized (destructed) pool. - LLAPRPool(void) : mPool(NULL) { } + LLAPRPool(void) : mPool(NULL), mOwner(AIThreadID::none) { } //! Construct a subpool from an existing pool. // This is not a copy-constructor, this class doesn't have one! - LLAPRPool(LLAPRPool& parent) : mPool(NULL) { create(parent); } + LLAPRPool(LLAPRPool& parent) : mPool(NULL), mOwner(AIThreadID::none) { create(parent); } //! Destruct the memory pool (free all of it's subpools and allocated memory). ~LLAPRPool() { destroy(); } protected: // Create a pool that is allocated from the Operating System. Only used by LLAPRRootPool. - LLAPRPool(int) : mPool(NULL), mParent(NULL), mOwner(apr_os_thread_current()) + LLAPRPool(int) : mPool(NULL), mParent(NULL) { apr_status_t const apr_pool_create_status = apr_pool_create(&mPool, NULL); llassert_always(apr_pool_create_status == APR_SUCCESS); @@ -104,7 +104,7 @@ public: apr_pool_t* operator()(void) const { llassert(mPool); - llassert(apr_os_thread_equal(mOwner, apr_os_thread_current())); + llassert(mOwner.equals_current_thread()); return mPool; } @@ -112,7 +112,7 @@ public: void clear(void) { llassert(mPool); - llassert(apr_os_thread_equal(mOwner, apr_os_thread_current())); + llassert(mOwner.equals_current_thread()); apr_pool_clear(mPool); } @@ -124,13 +124,13 @@ public: void* palloc(size_t size) { llassert(mPool); - llassert(apr_os_thread_equal(mOwner, apr_os_thread_current())); + llassert(mOwner.equals_current_thread()); return apr_palloc(mPool, size); } void* pcalloc(size_t size) { llassert(mPool); - llassert(apr_os_thread_equal(mOwner, apr_os_thread_current())); + llassert(mOwner.equals_current_thread()); return apr_pcalloc(mPool, size); } #endif diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index d0279f866..c4865e947 100644 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -308,8 +308,4 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; Such computation is done iff the message will be logged. */ -#ifdef SHOW_ASSERT -extern LL_COMMON_API bool is_main_thread(); -#endif - #endif // LL_LLERROR_H diff --git a/indra/llcommon/llframetimer.h b/indra/llcommon/llframetimer.h index bae3e5615..2bb1943c8 100644 --- a/indra/llcommon/llframetimer.h +++ b/indra/llcommon/llframetimer.h @@ -44,6 +44,9 @@ #include "lltimer.h" #include "timing.h" #include +#ifdef SHOW_ASSERT +#include "aithreadid.h" // is_main_thread() +#endif class LL_COMMON_API LLFrameTimer { diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index dd0efb422..c8d0be2f4 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -67,18 +67,12 @@ // //---------------------------------------------------------------------------- -#if !LL_DARWIN -U32 ll_thread_local local_thread_ID = 0; -#endif - -U32 LLThread::sIDIter = 0; LLAtomicS32 LLThread::sCount = 0; LLAtomicS32 LLThread::sRunning = 0; LL_COMMON_API void assert_main_thread() { - static U32 s_thread_id = LLThread::currentID(); - if (LLThread::currentID() != s_thread_id) + if (!AIThreadID::in_main_thread()) { llerrs << "Illegal execution outside main thread." << llendl; } @@ -95,9 +89,8 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap LLThread *threadp = (LLThread *)datap; -#if !LL_DARWIN - local_thread_ID = threadp->mID; -#endif + // Initialize thread-local cache of current thread ID (if supported). + AIThreadID::set_current_thread_id(); // Create a thread local data. LLThreadLocalData::create(threadp); @@ -137,7 +130,6 @@ LLThread::LLThread(std::string const& name) : mStatus(STOPPED), mThreadLocalData(NULL) { - mID = ++sIDIter; sCount++; llassert(sCount <= 50); mRunCondition = new LLCondition; @@ -281,12 +273,6 @@ void LLThread::setQuitting() wake(); } -// static -U32 LLThread::currentID() -{ - return (U32)apr_os_thread_current(); -} - // static void LLThread::yield() { @@ -315,14 +301,6 @@ void LLThread::wakeLocked() } } -//static -apr_os_thread_t LLThread::sMainThreadID; - -void LLThread::set_main_thread_id(void) -{ - sMainThreadID = apr_os_thread_current(); -} - // The thread private handle to access the LLThreadLocalData instance. apr_threadkey_t* LLThreadLocalData::sThreadLocalDataKey; @@ -345,6 +323,10 @@ void LLThreadLocalData::init(void) return; } + // This function is called by the main thread (these values are also needed in the next line). + AIThreadID::set_main_thread_id(); + AIThreadID::set_current_thread_id(); + apr_status_t status = apr_threadkey_private_create(&sThreadLocalDataKey, &LLThreadLocalData::destroy, LLAPRRootPool::get()()); ll_apr_assert_status(status); // Or out of memory, or system-imposed limit on the // total number of keys per process {PTHREAD_KEYS_MAX} @@ -352,9 +334,6 @@ void LLThreadLocalData::init(void) // Create the thread-local data for the main thread (this function is called by the main thread). LLThreadLocalData::create(NULL); - - // This function is called by the main thread. - LLThread::set_main_thread_id(); } // This is called once for every thread when the thread is destructed. @@ -421,27 +400,19 @@ void LLCondition::broadcast() //============================================================================ LLMutexBase::LLMutexBase() : - mLockingThread(NO_THREAD), + mLockingThread(AIThreadID::sNone), mCount(0) { } bool LLMutexBase::isSelfLocked() const { -#if LL_DARWIN - return mLockingThread == LLThread::currentID(); -#else - return mLockingThread == local_thread_ID; -#endif + return mLockingThread.equals_current_thread(); } void LLMutexBase::lock() { -#if LL_DARWIN - if (mLockingThread == LLThread::currentID()) -#else - if (mLockingThread == local_thread_ID) -#endif + if (mLockingThread.equals_current_thread()) { //redundant lock mCount++; return; @@ -449,11 +420,33 @@ void LLMutexBase::lock() apr_thread_mutex_lock(mAPRMutexp); -#if LL_DARWIN - mLockingThread = LLThread::currentID(); -#else - mLockingThread = local_thread_ID; -#endif + mLockingThread.reset(); +} + +bool LLMutexBase::tryLock() +{ + if (mLockingThread.equals_current_thread()) + { //redundant lock + mCount++; + return true; + } + bool success = !APR_STATUS_IS_EBUSY(apr_thread_mutex_trylock(mAPRMutexp)); + if (success) + { + mLockingThread.reset(); + } + return success; +} + +// non-blocking, but does do a lock/unlock so not free +bool LLMutexBase::isLocked() const +{ + if (mLockingThread.equals_current_thread()) + return false; // A call to lock() won't block. + if (APR_STATUS_IS_EBUSY(apr_thread_mutex_trylock(mAPRMutexp))) + return true; + apr_thread_mutex_unlock(mAPRMutexp); + return false; } void LLMutexBase::unlock() @@ -463,7 +456,7 @@ void LLMutexBase::unlock() mCount--; return; } - mLockingThread = NO_THREAD; + mLockingThread = AIThreadID::sNone; apr_thread_mutex_unlock(mAPRMutexp); } diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index ef4303a02..549a090ec 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -45,17 +45,12 @@ #include "apr_thread_cond.h" #include "llaprpool.h" #include "llatomic.h" +#include "aithreadid.h" class LLThread; class LLMutex; class LLCondition; -#if LL_WINDOWS -#define ll_thread_local __declspec(thread) -#else -#define ll_thread_local __thread -#endif - class LL_COMMON_API LLThreadLocalDataMember { public: @@ -85,10 +80,12 @@ private: ~LLThreadLocalData(); }; +// Print to llerrs if the current thread is not the main thread. +LL_COMMON_API void assert_main_thread(); + class LL_COMMON_API LLThread { private: - static apr_os_thread_t sMainThreadID; static U32 sIDIter; static LLAtomicS32 sCount; static LLAtomicS32 sRunning; @@ -108,11 +105,9 @@ public: bool isQuitting() const { return (QUITTING == mStatus); } bool isStopped() const { return (STOPPED == mStatus); } - static U32 currentID(); // Return ID of current thread static S32 getCount() { return sCount; } static S32 getRunning() { return sRunning; } static void yield(); // Static because it can be called by the main thread, which doesn't have an LLThread data structure. - static bool is_main_thread(void) { return apr_os_thread_equal(LLThread::sMainThreadID, apr_os_thread_current()); } public: // PAUSE / RESUME functionality. See source code for important usage notes. @@ -136,11 +131,6 @@ public: // Return thread-local data for the current thread. static LLThreadLocalData& tldata(void) { return LLThreadLocalData::tldata(); } - // Called once, from LLThreadLocalData::init(). - static void set_main_thread_id(void); - - U32 getID() const { return mID; } - private: bool mPaused; @@ -153,7 +143,6 @@ protected: apr_thread_t *mAPRThreadp; volatile EThreadStatus mStatus; - U32 mID; friend void LLThreadLocalData::create(LLThread* threadp); LLThreadLocalData* mThreadLocalData; @@ -183,8 +172,7 @@ protected: }; #ifdef SHOW_ASSERT -LL_COMMON_API inline bool is_main_thread(void) { return LLThread::is_main_thread(); } -#define ASSERT_SINGLE_THREAD do { static apr_os_thread_t first_thread_id = apr_os_thread_current(); llassert(apr_os_thread_equal(first_thread_id, apr_os_thread_current())); } while(0) +#define ASSERT_SINGLE_THREAD do { static AIThreadID first_thread_id; llassert(first_thread_id.equals_current_thread()); } while(0) #else #define ASSERT_SINGLE_THREAD do { } while(0) #endif @@ -204,32 +192,24 @@ LL_COMMON_API inline bool is_main_thread(void) { return LLThread::is_main_thread class LL_COMMON_API LLMutexBase { public: - typedef enum - { - NO_THREAD = 0xFFFFFFFF - } e_locking_thread; - LLMutexBase() ; void lock(); // blocks void unlock(); // Returns true if lock was obtained successfully. - bool tryLock() { return !APR_STATUS_IS_EBUSY(apr_thread_mutex_trylock(mAPRMutexp)); } + bool tryLock(); - // non-blocking, but does do a lock/unlock so not free - bool isLocked() { bool is_not_locked = tryLock(); if (is_not_locked) unlock(); return !is_not_locked; } + // Returns true if a call to lock() would block (returns false if self-locked()). + bool isLocked() const; // Returns true if locked by this thread. bool isSelfLocked() const; - // get ID of locking thread - U32 lockingThread() const { return mLockingThread; } - protected: // mAPRMutexp is initialized and uninitialized in the derived class. apr_thread_mutex_t* mAPRMutexp; mutable U32 mCount; - mutable U32 mLockingThread; + mutable AIThreadID mLockingThread; private: // Disallow copy construction and assignment. diff --git a/indra/newview/statemachine/aistatemachine.cpp b/indra/newview/statemachine/aistatemachine.cpp index 675317cb1..f008a4873 100644 --- a/indra/newview/statemachine/aistatemachine.cpp +++ b/indra/newview/statemachine/aistatemachine.cpp @@ -206,7 +206,7 @@ void AIStateMachine::locked_cont(void) // Atomic test mActive and change mIdle. mIdleActive.lock(); #ifdef SHOW_ASSERT - mContThread = apr_os_thread_current(); + mContThread.reset(); #endif mIdle = false; bool not_active = mActive == as_idle; @@ -253,7 +253,7 @@ void AIStateMachine::set_state(state_type state) mSetStateLock.lock(); // Do not call set_state() unless running. - llassert(mState == bs_run || !LLThread::is_main_thread()); + llassert(mState == bs_run || !is_main_thread()); // If this function is called from another thread than the main thread, then we have to ignore // it if we're not idle and the state is less than the current state. The main thread must @@ -279,12 +279,12 @@ void AIStateMachine::set_state(state_type state) // state is less than the current state, ignore it. // Also, if abort() or finish() was called, then we should just ignore it. if (mState != bs_run || - (!mIdle && state <= mRunState && !LLThread::is_main_thread())) + (!mIdle && state <= mRunState && !AIThreadID::in_main_thread())) { #ifdef SHOW_ASSERT // It's a bit weird if the same thread does two calls on a row where the second call // has a smaller value: warn about that. - if (mState == bs_run && mContThread == apr_os_thread_current()) + if (mState == bs_run && mContThread.equals_current_thread()) { llwarns << "Ignoring call to set_state(" << state_str(state) << ") by non-main thread before main-thread could react on previous call, " @@ -296,7 +296,7 @@ void AIStateMachine::set_state(state_type state) } // Do not call idle() when set_state is called from another thread; use idle(state_type) instead. - llassert(!mCalledThreadUnsafeIdle || LLThread::is_main_thread()); + llassert(!mCalledThreadUnsafeIdle || is_main_thread()); // Change mRunState to the requested value. if (mRunState != state) diff --git a/indra/newview/statemachine/aistatemachine.h b/indra/newview/statemachine/aistatemachine.h index 13da6fd3d..55028232b 100644 --- a/indra/newview/statemachine/aistatemachine.h +++ b/indra/newview/statemachine/aistatemachine.h @@ -208,7 +208,7 @@ class AIStateMachine { S64 mSleep; //!< Non-zero while the state machine is sleeping. LLMutex mIdleActive; //!< Used for atomic operations on the pair mIdle / mActive. #ifdef SHOW_ASSERT - apr_os_thread_t mContThread; //!< Thread that last called locked_cont(). + AIThreadID mContThread; //!< Thread that last called locked_cont(). bool mCalledThreadUnsafeIdle; //!< Set to true when idle() is called. #endif @@ -242,7 +242,7 @@ class AIStateMachine { //! Create a non-running state machine. AIStateMachine(void) : mState(bs_initialize), mIdle(true), mAborted(true), mActive(as_idle), mSleep(0), mParent(NULL), mCallback(NULL) #ifdef SHOW_ASSERT - , mContThread(0), mCalledThreadUnsafeIdle(false) + , mContThread(AIThreadID::none), mCalledThreadUnsafeIdle(false) #endif { updateSettings(); } @@ -269,7 +269,7 @@ class AIStateMachine { mSetStateLock.lock(); // Ignore calls to cont() if the statemachine isn't idle. See comments in set_state(). // Calling cont() twice or after calling set_state(), without first calling idle(), is an error. - if (mState != bs_run || !mIdle) { llassert(mState != bs_run || mContThread != apr_os_thread_current()); mSetStateLock.unlock(); return; } + if (mState != bs_run || !mIdle) { llassert(mState != bs_run || !mContThread.equals_current_thread()); mSetStateLock.unlock(); return; } locked_cont(); } private: