summaryrefslogtreecommitdiff
path: root/indra/llcommon/llthread.h
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon/llthread.h')
-rw-r--r--indra/llcommon/llthread.h124
1 files changed, 96 insertions, 28 deletions
diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h
index f1c6cd75af..757832b8ca 100644
--- a/indra/llcommon/llthread.h
+++ b/indra/llcommon/llthread.h
@@ -29,12 +29,34 @@
#include "llapp.h"
#include "llapr.h"
+#include "llmemory.h"
#include "apr_thread_cond.h"
+#include "llaprpool.h"
+
+#ifdef SHOW_ASSERT
+extern LL_COMMON_API bool is_main_thread(void);
+#endif
class LLThread;
class LLMutex;
class LLCondition;
+class LL_COMMON_API LLThreadLocalData
+{
+private:
+ static apr_threadkey_t* sThreadLocalDataKey;
+
+public:
+ // Thread-local memory pools.
+ LLAPRRootPool mRootPool;
+ LLVolatileAPRPool mVolatileAPRPool;
+
+ static void init(void);
+ static void destroy(void* thread_local_data);
+ static void create(LLThread* pthread);
+ static LLThreadLocalData& tldata(void);
+};
+
class LL_COMMON_API LLThread
{
public:
@@ -45,7 +67,7 @@ public:
QUITTING= 2 // Someone wants this thread to quit
} EThreadStatus;
- LLThread(const std::string& name, apr_pool_t *poolp = NULL);
+ LLThread(std::string const& name);
virtual ~LLThread(); // Warning! You almost NEVER want to destroy a thread unless it's in the STOPPED state.
virtual void shutdown(); // stops the thread
@@ -60,7 +82,7 @@ public:
// Called from MAIN THREAD.
void pause();
void unpause();
- bool isPaused() { return isStopped() || mPaused == TRUE; }
+ bool isPaused() { return isStopped() || mPaused; }
// Cause the thread to wake up and check its condition
void wake();
@@ -74,11 +96,11 @@ public:
// this kicks off the apr thread
void start(void);
- apr_pool_t *getAPRPool() { return mAPRPoolp; }
- LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; }
+ // Return thread-local data for the current thread.
+ static LLThreadLocalData& tldata(void) { return LLThreadLocalData::tldata(); }
private:
- BOOL mPaused;
+ bool mPaused;
// static function passed to APR thread creation routine
static void *APR_THREAD_FUNC staticRun(apr_thread_t *apr_threadp, void *datap);
@@ -88,14 +110,10 @@ protected:
LLCondition* mRunCondition;
apr_thread_t *mAPRThreadp;
- apr_pool_t *mAPRPoolp;
- BOOL mIsLocalPool;
EThreadStatus mStatus;
- //a local apr_pool for APRFile operations in this thread. If it exists, LLAPRFile::sAPRFilePoolp should not be used.
- //Note: this pool is used by APRFile ONLY, do NOT use it for any other purposes.
- // otherwise it will cause severe memory leaking!!! --bao
- LLVolatileAPRPool *mLocalAPRFilePoolp ;
+ friend void LLThreadLocalData::create(LLThread* threadp);
+ LLThreadLocalData* mThreadLocalData;
void setQuitting();
@@ -125,30 +143,80 @@ protected:
#define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO)
-class LL_COMMON_API LLMutex
+#ifdef MUTEX_DEBUG
+// We really shouldn't be using recursive locks. Make sure of that in debug mode.
+#define MUTEX_FLAG APR_THREAD_MUTEX_UNNESTED
+#else
+// Use the fastest platform-optimal lock behavior (can be recursive or non-recursive).
+#define MUTEX_FLAG APR_THREAD_MUTEX_DEFAULT
+#endif
+
+class LL_COMMON_API LLMutexBase
{
public:
- LLMutex(apr_pool_t *apr_poolp); // NULL pool constructs a new pool for the mutex
- virtual ~LLMutex();
-
- void lock(); // blocks
- void unlock();
- bool isLocked(); // non-blocking, but does do a lock/unlock so not free
-
+ void lock() { apr_thread_mutex_lock(mAPRMutexp); }
+ void unlock() { apr_thread_mutex_unlock(mAPRMutexp); }
+ // Returns true if lock was obtained successfully.
+ bool trylock() { return !APR_STATUS_IS_EBUSY(apr_thread_mutex_trylock(mAPRMutexp)); }
+
+ // 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; }
+
+protected:
+ // mAPRMutexp is initialized and uninitialized in the derived class.
+ apr_thread_mutex_t* mAPRMutexp;
+};
+
+class LL_COMMON_API LLMutex : public LLMutexBase
+{
+public:
+ LLMutex(LLAPRPool& parent = LLThread::tldata().mRootPool) : mPool(parent)
+ {
+ apr_thread_mutex_create(&mAPRMutexp, MUTEX_FLAG, mPool());
+ }
+ ~LLMutex()
+ {
+ llassert(!isLocked()); // better not be locked!
+ apr_thread_mutex_destroy(mAPRMutexp);
+ mAPRMutexp = NULL;
+ }
+
protected:
- apr_thread_mutex_t *mAPRMutexp;
- apr_pool_t *mAPRPoolp;
- BOOL mIsLocalPool;
-#if MUTEX_DEBUG
- std::map<U32, BOOL> mIsLocked;
+ LLAPRPool mPool;
+};
+
+#if APR_HAS_THREADS
+// No need to use a root pool in this case.
+typedef LLMutex LLMutexRootPool;
+#else // APR_HAS_THREADS
+class LL_COMMON_API LLMutexRootPool : public LLMutexBase
+{
+public:
+ LLMutexRootPool(void)
+ {
+ apr_thread_mutex_create(&mAPRMutexp, MUTEX_FLAG, mRootPool());
+ }
+ ~LLMutexRootPool()
+ {
+#if APR_POOL_DEBUG
+ // It is allowed to destruct root pools from a different thread.
+ mRootPool.grab_ownership();
#endif
+ llassert(!isLocked());
+ apr_thread_mutex_destroy(mAPRMutexp);
+ mAPRMutexp = NULL;
+ }
+
+protected:
+ LLAPRRootPool mRootPool;
};
+#endif // APR_HAS_THREADS
// Actually a condition/mutex pair (since each condition needs to be associated with a mutex).
class LL_COMMON_API LLCondition : public LLMutex
{
public:
- LLCondition(apr_pool_t *apr_poolp); // Defaults to global pool, could use the thread pool as well.
+ LLCondition(LLAPRPool& parent = LLThread::tldata().mRootPool);
~LLCondition();
void wait(); // blocks
@@ -159,10 +227,10 @@ protected:
apr_thread_cond_t *mAPRCondp;
};
-class LLMutexLock
+class LL_COMMON_API LLMutexLock
{
public:
- LLMutexLock(LLMutex* mutex)
+ LLMutexLock(LLMutexBase* mutex)
{
mMutex = mutex;
mMutex->lock();
@@ -172,7 +240,7 @@ public:
mMutex->unlock();
}
private:
- LLMutex* mMutex;
+ LLMutexBase* mMutex;
};
//============================================================================