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.
This commit is contained in:
@@ -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
|
||||
|
||||
70
indra/llcommon/aithreadid.cpp
Normal file
70
indra/llcommon/aithreadid.cpp
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 <iostream>
|
||||
#include <iomanip>
|
||||
#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;
|
||||
}
|
||||
|
||||
91
indra/llcommon/aithreadid.h
Normal file
91
indra/llcommon/aithreadid.h
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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_portable.h> // apr_os_thread_t, apr_os_thread_current(), apr_os_thread_equal().
|
||||
#include <iosfwd> // 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
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -44,6 +44,9 @@
|
||||
#include "lltimer.h"
|
||||
#include "timing.h"
|
||||
#include <apr_thread_mutex.h>
|
||||
#ifdef SHOW_ASSERT
|
||||
#include "aithreadid.h" // is_main_thread()
|
||||
#endif
|
||||
|
||||
class LL_COMMON_API LLFrameTimer
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user