Skip to content
Snippets Groups Projects
Commit 1709f1ef authored by David Parks's avatar David Parks
Browse files

Resolved timeout issues in mesh HTTP transfer.

parent 35e25272
No related branches found
No related tags found
No related merge requests found
/** /**
* @file llthread.h * @file llthread.h
* @brief Base classes for thread, mutex and condition handling. * @brief Base classes for thread, mutex and condition handling.
* *
* $LicenseInfo:firstyear=2004&license=viewergpl$ * $LicenseInfo:firstyear=2004&license=viewergpl$
* *
* Copyright (c) 2004-2009, Linden Research, Inc. * Copyright (c) 2004-2009, Linden Research, Inc.
* *
* Second Life Viewer Source Code * Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab * The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0 * to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement * ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of * ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or * the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* *
* There are special exceptions to the terms and conditions of the GPL as * 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 * 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, or * in the file doc/FLOSS-exception.txt in this software distribution, or
* online at * online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception * http://secondlifegrid.net/programs/open_source/licensing/flossexception
* *
* By copying, modifying or distributing this software, you acknowledge * By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above, * that you have read and understood your obligations described above,
* and agree to abide by those obligations. * and agree to abide by those obligations.
* *
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE. * COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$ * $/LicenseInfo$
*/ */
#ifndef LL_LLTHREAD_H #ifndef LL_LLTHREAD_H
#define LL_LLTHREAD_H #define LL_LLTHREAD_H
#include "llapp.h" #include "llapp.h"
#include "apr_thread_cond.h" #include "apr_thread_cond.h"
class LLThread; class LLThread;
class LLMutex; class LLMutex;
class LLCondition; class LLCondition;
#if LL_WINDOWS #if LL_WINDOWS
#define ll_thread_local __declspec(thread) #define ll_thread_local __declspec(thread)
#else #else
#define ll_thread_local __thread #define ll_thread_local __thread
#endif #endif
class LL_COMMON_API LLThread class LL_COMMON_API LLThread
{ {
private: private:
static U32 sIDIter; static U32 sIDIter;
public: public:
typedef enum e_thread_status typedef enum e_thread_status
{ {
STOPPED = 0, // The thread is not running. Not started, or has exited its run function STOPPED = 0, // The thread is not running. Not started, or has exited its run function
RUNNING = 1, // The thread is currently running RUNNING = 1, // The thread is currently running
QUITTING= 2 // Someone wants this thread to quit QUITTING= 2 // Someone wants this thread to quit
} EThreadStatus; } EThreadStatus;
LLThread(const std::string& name, apr_pool_t *poolp = NULL); LLThread(const std::string& name, apr_pool_t *poolp = NULL);
virtual ~LLThread(); // Warning! You almost NEVER want to destroy a thread unless it's in the STOPPED state. virtual ~LLThread(); // Warning! You almost NEVER want to destroy a thread unless it's in the STOPPED state.
virtual void shutdown(); // stops the thread virtual void shutdown(); // stops the thread
bool isQuitting() const { return (QUITTING == mStatus); } bool isQuitting() const { return (QUITTING == mStatus); }
bool isStopped() const { return (STOPPED == mStatus); } bool isStopped() const { return (STOPPED == mStatus); }
static U32 currentID(); // Return ID of current thread static U32 currentID(); // Return ID of current thread
static void yield(); // Static because it can be called by the main thread, which doesn't have an LLThread data structure. static void yield(); // Static because it can be called by the main thread, which doesn't have an LLThread data structure.
public: public:
// PAUSE / RESUME functionality. See source code for important usage notes. // PAUSE / RESUME functionality. See source code for important usage notes.
// Called from MAIN THREAD. // Called from MAIN THREAD.
void pause(); void pause();
void unpause(); void unpause();
bool isPaused() { return isStopped() || mPaused == TRUE; } bool isPaused() { return isStopped() || mPaused == TRUE; }
// Cause the thread to wake up and check its condition // Cause the thread to wake up and check its condition
void wake(); void wake();
// Same as above, but to be used when the condition is already locked. // Same as above, but to be used when the condition is already locked.
void wakeLocked(); void wakeLocked();
// Called from run() (CHILD THREAD). Pause the thread if requested until unpaused. // Called from run() (CHILD THREAD). Pause the thread if requested until unpaused.
void checkPause(); void checkPause();
// this kicks off the apr thread // this kicks off the apr thread
void start(void); void start(void);
apr_pool_t *getAPRPool() { return mAPRPoolp; } apr_pool_t *getAPRPool() { return mAPRPoolp; }
LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; } LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; }
U32 getID() const { return mID; } U32 getID() const { return mID; }
private: private:
BOOL mPaused; BOOL mPaused;
// static function passed to APR thread creation routine // static function passed to APR thread creation routine
static void *APR_THREAD_FUNC staticRun(apr_thread_t *apr_threadp, void *datap); static void *APR_THREAD_FUNC staticRun(apr_thread_t *apr_threadp, void *datap);
protected: protected:
std::string mName; std::string mName;
LLCondition* mRunCondition; LLCondition* mRunCondition;
apr_thread_t *mAPRThreadp; apr_thread_t *mAPRThreadp;
apr_pool_t *mAPRPoolp; apr_pool_t *mAPRPoolp;
BOOL mIsLocalPool; BOOL mIsLocalPool;
EThreadStatus mStatus; EThreadStatus mStatus;
U32 mID; U32 mID;
//a local apr_pool for APRFile operations in this thread. If it exists, LLAPRFile::sAPRFilePoolp should not be used. //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. //Note: this pool is used by APRFile ONLY, do NOT use it for any other purposes.
// otherwise it will cause severe memory leaking!!! --bao // otherwise it will cause severe memory leaking!!! --bao
LLVolatileAPRPool *mLocalAPRFilePoolp ; LLVolatileAPRPool *mLocalAPRFilePoolp ;
void setQuitting(); void setQuitting();
// virtual function overridden by subclass -- this will be called when the thread runs // virtual function overridden by subclass -- this will be called when the thread runs
virtual void run(void) = 0; virtual void run(void) = 0;
// virtual predicate function -- returns true if the thread should wake up, false if it should sleep. // virtual predicate function -- returns true if the thread should wake up, false if it should sleep.
virtual bool runCondition(void); virtual bool runCondition(void);
// Lock/Unlock Run Condition -- use around modification of any variable used in runCondition() // Lock/Unlock Run Condition -- use around modification of any variable used in runCondition()
inline void lockData(); inline void lockData();
inline void unlockData(); inline void unlockData();
// This is the predicate that decides whether the thread should sleep. // This is the predicate that decides whether the thread should sleep.
// It should only be called with mRunCondition locked, since the virtual runCondition() function may need to access // It should only be called with mRunCondition locked, since the virtual runCondition() function may need to access
// data structures that are thread-unsafe. // data structures that are thread-unsafe.
bool shouldSleep(void) { return (mStatus == RUNNING) && (isPaused() || (!runCondition())); } bool shouldSleep(void) { return (mStatus == RUNNING) && (isPaused() || (!runCondition())); }
// To avoid spurious signals (and the associated context switches) when the condition may or may not have changed, you can do the following: // To avoid spurious signals (and the associated context switches) when the condition may or may not have changed, you can do the following:
// mRunCondition->lock(); // mRunCondition->lock();
// if(!shouldSleep()) // if(!shouldSleep())
// mRunCondition->signal(); // mRunCondition->signal();
// mRunCondition->unlock(); // mRunCondition->unlock();
}; };
//============================================================================ //============================================================================
#define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO) #define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO)
class LL_COMMON_API LLMutex class LL_COMMON_API LLMutex
{ {
public: public:
typedef enum typedef enum
{ {
NO_THREAD = 0xFFFFFFFF NO_THREAD = 0xFFFFFFFF
} e_locking_thread; } e_locking_thread;
LLMutex(apr_pool_t *apr_poolp); // NULL pool constructs a new pool for the mutex LLMutex(apr_pool_t *apr_poolp); // NULL pool constructs a new pool for the mutex
~LLMutex(); ~LLMutex();
void lock(); // blocks void lock(); // blocks
void unlock(); void unlock();
bool isLocked(); // non-blocking, but does do a lock/unlock so not free bool isLocked(); // non-blocking, but does do a lock/unlock so not free
U32 lockingThread() const; //get ID of locking thread U32 lockingThread() const; //get ID of locking thread
protected: protected:
apr_thread_mutex_t *mAPRMutexp; apr_thread_mutex_t *mAPRMutexp;
mutable U32 mCount; mutable U32 mCount;
mutable U32 mLockingThread; mutable U32 mLockingThread;
apr_pool_t *mAPRPoolp; apr_pool_t *mAPRPoolp;
BOOL mIsLocalPool; BOOL mIsLocalPool;
S32 mLockCount; S32 mLockCount;
#if MUTEX_DEBUG #if MUTEX_DEBUG
std::map<U32, BOOL> mIsLocked; std::map<U32, BOOL> mIsLocked;
#endif #endif
}; };
// Actually a condition/mutex pair (since each condition needs to be associated with a mutex). // Actually a condition/mutex pair (since each condition needs to be associated with a mutex).
class LL_COMMON_API LLCondition : public LLMutex class LL_COMMON_API LLCondition : public LLMutex
{ {
public: public:
LLCondition(apr_pool_t *apr_poolp); // Defaults to global pool, could use the thread pool as well. LLCondition(apr_pool_t *apr_poolp); // Defaults to global pool, could use the thread pool as well.
~LLCondition(); ~LLCondition();
void wait(); // blocks void wait(); // blocks
void signal(); void signal();
void broadcast(); void broadcast();
protected: protected:
apr_thread_cond_t *mAPRCondp; apr_thread_cond_t *mAPRCondp;
}; };
class LLMutexLock class LLMutexLock
{ {
public: public:
LLMutexLock(LLMutex* mutex) LLMutexLock(LLMutex* mutex)
{ {
mMutex = mutex; mMutex = mutex;
mMutex->lock(); mMutex->lock();
} }
~LLMutexLock() ~LLMutexLock()
{ {
mMutex->unlock(); mMutex->unlock();
} }
private: private:
LLMutex* mMutex; LLMutex* mMutex;
}; };
//============================================================================ //============================================================================
void LLThread::lockData() void LLThread::lockData()
{ {
mRunCondition->lock(); mRunCondition->lock();
} }
void LLThread::unlockData() void LLThread::unlockData()
{ {
mRunCondition->unlock(); mRunCondition->unlock();
} }
//============================================================================ //============================================================================
// see llmemory.h for LLPointer<> definition // see llmemory.h for LLPointer<> definition
class LL_COMMON_API LLThreadSafeRefCount class LL_COMMON_API LLThreadSafeRefCount
{ {
public: public:
static void initThreadSafeRefCount(); // creates sMutex static void initThreadSafeRefCount(); // creates sMutex
static void cleanupThreadSafeRefCount(); // destroys sMutex static void cleanupThreadSafeRefCount(); // destroys sMutex
private: private:
static LLMutex* sMutex; static LLMutex* sMutex;
private: private:
LLThreadSafeRefCount(const LLThreadSafeRefCount&); // not implemented LLThreadSafeRefCount(const LLThreadSafeRefCount&); // not implemented
LLThreadSafeRefCount&operator=(const LLThreadSafeRefCount&); // not implemented LLThreadSafeRefCount&operator=(const LLThreadSafeRefCount&); // not implemented
protected: protected:
virtual ~LLThreadSafeRefCount(); // use unref() virtual ~LLThreadSafeRefCount(); // use unref()
public: public:
LLThreadSafeRefCount(); LLThreadSafeRefCount();
void ref() void ref()
{ {
if (sMutex) sMutex->lock(); if (sMutex) sMutex->lock();
mRef++; mRef++;
if (sMutex) sMutex->unlock(); if (sMutex) sMutex->unlock();
} }
S32 unref() S32 unref()
{ {
llassert(mRef >= 1); llassert(mRef >= 1);
if (sMutex) sMutex->lock(); if (sMutex) sMutex->lock();
S32 res = --mRef; S32 res = --mRef;
if (sMutex) sMutex->unlock(); if (sMutex) sMutex->unlock();
if (0 == res) if (0 == res)
{ {
delete this; delete this;
return 0; return 0;
} }
return res; return res;
} }
S32 getNumRefs() const S32 getNumRefs() const
{ {
return mRef; return mRef;
} }
private: private:
S32 mRef; S32 mRef;
}; };
//============================================================================ //============================================================================
// Simple responder for self destructing callbacks // Simple responder for self destructing callbacks
// Pure virtual class // Pure virtual class
class LL_COMMON_API LLResponder : public LLThreadSafeRefCount class LL_COMMON_API LLResponder : public LLThreadSafeRefCount
{ {
protected: protected:
virtual ~LLResponder(); virtual ~LLResponder();
public: public:
virtual void completed(bool success) = 0; virtual void completed(bool success) = 0;
}; };
//============================================================================ //============================================================================
#endif // LL_LLTHREAD_H #endif // LL_LLTHREAD_H
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment