diff options
Diffstat (limited to 'indra/llcommon')
-rw-r--r-- | indra/llcommon/linden_common.h | 4 | ||||
-rw-r--r-- | indra/llcommon/llapp.cpp | 3 | ||||
-rw-r--r-- | indra/llcommon/llapr.h | 2 | ||||
-rw-r--r-- | indra/llcommon/llfasttimer.cpp | 18 | ||||
-rw-r--r-- | indra/llcommon/llfasttimer.h | 8 | ||||
-rw-r--r-- | indra/llcommon/llmemory.cpp | 31 | ||||
-rw-r--r-- | indra/llcommon/llmemory.h | 37 | ||||
-rw-r--r-- | indra/llcommon/llmutex.cpp | 49 | ||||
-rw-r--r-- | indra/llcommon/llmutex.h | 67 | ||||
-rw-r--r-- | indra/llcommon/llsdserialize.cpp | 5 | ||||
-rw-r--r-- | indra/llcommon/llstring.cpp | 3 | ||||
-rw-r--r-- | indra/llcommon/llthread.cpp | 93 | ||||
-rw-r--r-- | indra/llcommon/llthread.h | 94 | ||||
-rw-r--r-- | indra/llcommon/lltrace.h | 1 | ||||
-rw-r--r-- | indra/llcommon/lltracerecording.cpp | 5 | ||||
-rw-r--r-- | indra/llcommon/lltracethreadrecorder.cpp | 4 | ||||
-rw-r--r-- | indra/llcommon/llunit.h | 40 | ||||
-rw-r--r-- | indra/llcommon/lluri.cpp | 36 | ||||
-rw-r--r-- | indra/llcommon/llversionviewer.h | 2 | ||||
-rw-r--r-- | indra/llcommon/tests/bitpack_test.cpp | 1 | ||||
-rw-r--r-- | indra/llcommon/tests/lluri_test.cpp | 94 | ||||
-rw-r--r-- | indra/llcommon/tests/reflection_test.cpp | 2 |
22 files changed, 359 insertions, 240 deletions
diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h index 5cfcdab41c..f0a5603d06 100644 --- a/indra/llcommon/linden_common.h +++ b/indra/llcommon/linden_common.h @@ -59,4 +59,8 @@ #include "llerror.h" #include "llfile.h" +// Boost 1.45 had version 2 as the default for the filesystem library, +// 1.48 has version 3 as the default. Keep compatibility for now. +#define BOOST_FILESYSTEM_VERSION 2 + #endif diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index ed192a9975..ca258900c7 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -289,6 +289,7 @@ void LLApp::setupErrorHandling() // occasionally checks to see if the app is in an error state, and sees if it needs to be run. #if LL_WINDOWS +#if LL_SEND_CRASH_REPORTS // This sets a callback to handle w32 signals to the console window. // The viewer shouldn't be affected, sicne its a windowed app. SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ConsoleCtrlHandler, TRUE); @@ -300,7 +301,7 @@ void LLApp::setupErrorHandling() mExceptionHandler = new google_breakpad::ExceptionHandler( L"C:\\Temp\\", 0, windows_post_minidump_callback, 0, google_breakpad::ExceptionHandler::HANDLER_ALL); } - +#endif #else // // Start up signal handling. diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index d9fe257e86..7ca0f505ef 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -162,7 +162,7 @@ public: void operator -=(Type x) { apr_atomic_sub32(&mData, apr_uint32_t(x)); } void operator +=(Type x) { apr_atomic_add32(&mData, apr_uint32_t(x)); } Type operator ++(int) { return apr_atomic_inc32(&mData); } // Type++ - Type operator --(int) { return apr_atomic_dec32(&mData); } // Type-- + Type operator --(int) { return apr_atomic_dec32(&mData); } // approximately --Type (0 if final is 0, non-zero otherwise) private: apr_uint32_t mData; diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp index 9701a41dc5..e88a5a9ed1 100644 --- a/indra/llcommon/llfasttimer.cpp +++ b/indra/llcommon/llfasttimer.cpp @@ -177,8 +177,8 @@ BlockTimer::BlockTimer(const char* name, bool open, BlockTimer* parent) mParent = this; } - mCountHistory = new U32[HISTORY_NUM]; - memset(mCountHistory, 0, sizeof(U32) * HISTORY_NUM); + mCountHistory = new U64[HISTORY_NUM]; + memset(mCountHistory, 0, sizeof(U64) * HISTORY_NUM); mCallHistory = new U32[HISTORY_NUM]; memset(mCallHistory, 0, sizeof(U32) * HISTORY_NUM); } @@ -266,9 +266,12 @@ void BlockTimer::buildHierarchy() // bootstrap tree construction by attaching to last timer to be on stack // when this timer was called - if (timer.getPrimaryAccumulator().mLastCaller && timer.mParent == &BlockTimer::getRootTimer()) + if (timer.mParent == &BlockTimer::getRootTimer()) + { + if (timer.getPrimaryAccumulator().mLastCaller) { timer.setParent(timer.getPrimaryAccumulator().mLastCaller); + } // no need to push up tree on first use, flag can be set spuriously timer.getPrimaryAccumulator().mMoveUpTree = false; } @@ -326,8 +329,8 @@ void BlockTimer::accumulateTimings() TimerAccumulator& accumulator = sCurTimerData->mTimerData->getPrimaryAccumulator(); while(cur_timer && cur_timer->mLastTimerData.mCurTimer != cur_timer) { - U32 cumulative_time_delta = cur_time - cur_timer->mStartTime; - U32 self_time_delta = cumulative_time_delta - cur_data->mChildTime; + U64 cumulative_time_delta = cur_time - cur_timer->mStartTime; + U64 self_time_delta = cumulative_time_delta - cur_data->mChildTime; cur_data->mChildTime = 0; accumulator.mSelfTimeCounter += self_time_delta; accumulator.mTotalTimeCounter += cumulative_time_delta; @@ -429,6 +432,7 @@ void BlockTimer::resetFrame() BlockTimer& timer = *it; TimerAccumulator& accumulator = timer.getPrimaryAccumulator(); accumulator.mSelfTimeCounter = 0; + accumulator.mTotalTimeCounter = 0; accumulator.mCalls = 0; accumulator.mLastCaller = NULL; accumulator.mMoveUpTree = false; @@ -471,7 +475,7 @@ void BlockTimer::reset() timer.mCountAverage = 0; timer.mCallAverage = 0; - memset(timer.mCountHistory, 0, sizeof(U32) * HISTORY_NUM); + memset(timer.mCountHistory, 0, sizeof(U64) * HISTORY_NUM); memset(timer.mCallHistory, 0, sizeof(U32) * HISTORY_NUM); } } @@ -480,7 +484,7 @@ void BlockTimer::reset() sCurFrameIndex = 0; } -U32 BlockTimer::getHistoricalCount(S32 history_index) const +U64 BlockTimer::getHistoricalCount(S32 history_index) const { S32 history_idx = (getLastFrameIndex() + history_index) % HISTORY_NUM; return mCountHistory[history_idx]; diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index af9b360e01..cfe2cf5371 100644 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -93,7 +93,7 @@ public: U32 getCountAverage() const { return mCountAverage; } U32 getCallAverage() const { return mCallAverage; } - U32 getHistoricalCount(S32 history_index = 0) const; + U64 getHistoricalCount(S32 history_index = 0) const; U32 getHistoricalCalls(S32 history_index = 0) const; static BlockTimer& getRootTimer(); @@ -258,12 +258,12 @@ public: // sum of recorded self time and tree time of all children timers (might not match actual recorded time of children if topology is incomplete - U32 mTreeTimeCounter; + U64 mTreeTimeCounter; - U32 mCountAverage; + U64 mCountAverage; U32 mCallAverage; - U32* mCountHistory; + U64* mCountHistory; U32* mCallHistory; // tree structure diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 7c4ab6cf98..c6b02df939 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -251,21 +251,6 @@ U32 LLMemory::getAllocatedMemKB() return sAllocatedMemInKB ; } -void* ll_allocate (size_t size) -{ - if (size == 0) - { - llwarns << "Null allocation" << llendl; - } - void *p = malloc(size); - if (p == NULL) - { - LLMemory::freeReserve(); - llerrs << "Out of memory Error" << llendl; - } - return p; -} - //---------------------------------------------------------------------------- #if defined(LL_WINDOWS) @@ -1364,7 +1349,7 @@ char* LLPrivateMemoryPool::allocate(U32 size) //if the asked size larger than MAX_BLOCK_SIZE, fetch from heap directly, the pool does not manage it if(size >= CHUNK_SIZE) { - return (char*)malloc(size) ; + return (char*)ll_aligned_malloc_16(size) ; } char* p = NULL ; @@ -1421,7 +1406,7 @@ char* LLPrivateMemoryPool::allocate(U32 size) to_log = false ; } - return (char*)malloc(size) ; + return (char*)ll_aligned_malloc_16(size) ; } return p ; @@ -1440,7 +1425,7 @@ void LLPrivateMemoryPool::freeMem(void* addr) if(!chunk) { - free(addr) ; //release from heap + ll_aligned_free_16(addr) ; //release from heap } else { @@ -1564,7 +1549,7 @@ LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::addChunk(S32 chunk_inde mReservedPoolSize += preferred_size + overhead ; - char* buffer = (char*)malloc(preferred_size + overhead) ; + char* buffer = (char*)ll_aligned_malloc_16(preferred_size + overhead) ; if(!buffer) { return NULL ; @@ -1632,7 +1617,7 @@ void LLPrivateMemoryPool::removeChunk(LLMemoryChunk* chunk) mReservedPoolSize -= chunk->getBufferSize() ; //release memory - free(chunk->getBuffer()) ; + ll_aligned_free_16(chunk->getBuffer()) ; } U16 LLPrivateMemoryPool::findHashKey(const char* addr) @@ -1976,7 +1961,7 @@ char* LLPrivateMemoryPoolManager::allocate(LLPrivateMemoryPool* poolp, U32 size, if(!poolp) { - p = (char*)malloc(size) ; + p = (char*)ll_aligned_malloc_16(size) ; } else { @@ -2005,7 +1990,7 @@ char* LLPrivateMemoryPoolManager::allocate(LLPrivateMemoryPool* poolp, U32 size) } else { - return (char*)malloc(size) ; + return (char*)ll_aligned_malloc_16(size) ; } } #endif @@ -2030,7 +2015,7 @@ void LLPrivateMemoryPoolManager::freeMem(LLPrivateMemoryPool* poolp, void* addr { if(!sPrivatePoolEnabled) { - free(addr) ; //private pool is disabled. + ll_aligned_free_16(addr) ; //private pool is disabled. } else if(!sInstance) //the private memory manager is destroyed, try the dangling list { diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 4480e381e8..e725bdd9fa 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -30,11 +30,12 @@ class LLMutex ; -#ifdef LL_WINDOWS -#define LL_ALIGNED(x) __declspec(align(x)) +#if LL_WINDOWS && LL_DEBUG +#define LL_CHECK_MEMORY llassert(_CrtCheckMemory()); #else -#define LL_ALIGNED(x) __attribute__ ((aligned (16))) +#define LL_CHECK_MEMORY #endif + inline void* ll_aligned_malloc( size_t size, int align ) { void* mem = malloc( size + (align - 1) + sizeof(void*) ); @@ -66,31 +67,43 @@ inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed wi #endif } -inline void* ll_aligned_realloc_16(void* ptr, size_t size) // returned hunk MUST be freed with ll_aligned_free_16(). +inline void ll_aligned_free_16(void *p) { #if defined(LL_WINDOWS) - return _aligned_realloc(ptr, size, 16); + _aligned_free(p); #elif defined(LL_DARWIN) - return realloc(ptr,size); // default osx malloc is 16 byte aligned. + return free(p); #else - return realloc(ptr,size); // FIXME not guaranteed to be aligned. + free(p); // posix_memalign() is compatible with heap deallocator #endif } -inline void ll_aligned_free_16(void *p) +inline void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size) // returned hunk MUST be freed with ll_aligned_free_16(). { #if defined(LL_WINDOWS) - _aligned_free(p); + return _aligned_realloc(ptr, size, 16); #elif defined(LL_DARWIN) - return free(p); + return realloc(ptr,size); // default osx malloc is 16 byte aligned. #else - free(p); // posix_memalign() is compatible with heap deallocator + //FIXME: memcpy is SLOW + void* ret = ll_aligned_malloc_16(size); + if (ptr) + { + if (ret) + { + // Only copy the size of the smallest memory block to avoid memory corruption. + memcpy(ret, ptr, llmin(old_size, size)); + } + ll_aligned_free_16(ptr); + } + return ret; #endif } + #else // USE_TCMALLOC // ll_aligned_foo_16 are not needed with tcmalloc #define ll_aligned_malloc_16 malloc -#define ll_aligned_realloc_16 realloc +#define ll_aligned_realloc_16(a,b,c) realloc(a,b) #define ll_aligned_free_16 free #endif // USE_TCMALLOC diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp index 2ce14b3a2e..e6beb9e680 100644 --- a/indra/llcommon/llmutex.cpp +++ b/indra/llcommon/llmutex.cpp @@ -86,7 +86,7 @@ void LLMutex::lock() #if LL_DARWIN mLockingThread = LLThread::currentID(); #else - mLockingThread = LLThread::sThreadIndex; + mLockingThread = LLThread::sThreadID; #endif } @@ -129,7 +129,7 @@ bool LLMutex::isSelfLocked() #if LL_DARWIN return mLockingThread == LLThread::currentID(); #else - return mLockingThread == LLThread::sThreadIndex; + return mLockingThread == LLThread::sThreadID; #endif } @@ -182,48 +182,3 @@ void LLCondition::broadcast() //============================================================================ - -//---------------------------------------------------------------------------- - -//static -LLMutex* LLThreadSafeRefCount::sMutex = 0; - -//static -void LLThreadSafeRefCount::initThreadSafeRefCount() -{ - if (!sMutex) - { - sMutex = new LLMutex(0); - } -} - -//static -void LLThreadSafeRefCount::cleanupThreadSafeRefCount() -{ - delete sMutex; - sMutex = NULL; -} - - -//---------------------------------------------------------------------------- - -LLThreadSafeRefCount::LLThreadSafeRefCount() : -mRef(0) -{ -} - -LLThreadSafeRefCount::~LLThreadSafeRefCount() -{ - if (mRef != 0) - { - llerrs << "deleting non-zero reference" << llendl; - } -} - -//============================================================================ - -LLResponder::~LLResponder() -{ -} - -//============================================================================ diff --git a/indra/llcommon/llmutex.h b/indra/llcommon/llmutex.h index bd0a59b577..cbde4c47a9 100644 --- a/indra/llcommon/llmutex.h +++ b/indra/llcommon/llmutex.h @@ -98,71 +98,4 @@ private: LLMutex* mMutex; }; - -//============================================================================ - -// see llmemory.h for LLPointer<> definition - -class LL_COMMON_API LLThreadSafeRefCount -{ -public: - static void initThreadSafeRefCount(); // creates sMutex - static void cleanupThreadSafeRefCount(); // destroys sMutex - -private: - static LLMutex* sMutex; - -private: - LLThreadSafeRefCount(const LLThreadSafeRefCount&); // not implemented - LLThreadSafeRefCount&operator=(const LLThreadSafeRefCount&); // not implemented - -protected: - virtual ~LLThreadSafeRefCount(); // use unref() - -public: - LLThreadSafeRefCount(); - - void ref() - { - if (sMutex) sMutex->lock(); - mRef++; - if (sMutex) sMutex->unlock(); - } - - S32 unref() - { - llassert(mRef >= 1); - if (sMutex) sMutex->lock(); - S32 res = --mRef; - if (sMutex) sMutex->unlock(); - if (0 == res) - { - delete this; - return 0; - } - return res; - } - S32 getNumRefs() const - { - return mRef; - } - -private: - S32 mRef; -}; - - -//============================================================================ - -// Simple responder for self destructing callbacks -// Pure virtual class -class LL_COMMON_API LLResponder : public LLThreadSafeRefCount -{ -protected: - virtual ~LLResponder(); -public: - virtual void completed(bool success) = 0; -}; - - #endif // LL_LLTHREAD_H diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index 7f4f670ed0..6b549e4b6f 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -1451,9 +1451,12 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option } case LLSD::TypeUUID: + { ostr.put('u'); - ostr.write((const char*)(&(data.asUUID().mData)), UUID_BYTES); + LLSD::UUID value = data.asUUID(); + ostr.write((const char*)(&value.mData), UUID_BYTES); break; + } case LLSD::TypeString: ostr.put('s'); diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index 9600928ad5..67bbc58bf5 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -46,7 +46,8 @@ std::string ll_safe_string(const char* in) std::string ll_safe_string(const char* in, S32 maxlen) { - if(in) return std::string(in, maxlen); + if(in && maxlen > 0 ) return std::string(in, maxlen); + return std::string(); } diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index cc661bab59..8ce739bf23 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -62,10 +62,10 @@ #if LL_DARWIN // statically allocated thread local storage not supported in Darwin executable formats #elif LL_WINDOWS -U32 __declspec(thread) LLThread::sThreadIndex = 0; +U32 __declspec(thread) LLThread::sThreadID = 0; #elif LL_LINUX U32 __thread LLThread::sThreadID = 0; -#endif +#endif U32 LLThread::sIDIter = 0; @@ -79,6 +79,13 @@ LL_COMMON_API void assert_main_thread() } } +void LLThread::registerThreadID() +{ +#if !LL_DARWIN + sThreadID = ++sIDIter; +#endif +} + // // Handed to the APR thread creation function // @@ -89,7 +96,7 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap LLTrace::ThreadRecorder* thread_recorder = new LLTrace::SlaveThreadRecorder(); #if !LL_DARWIN - sThreadIndex = threadp->mID; + sThreadID = threadp->mID; #endif // Run the user supplied function @@ -126,7 +133,7 @@ LLThread::LLThread(const std::string& name, apr_pool_t *poolp) : apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread } mRunCondition = new LLCondition(mAPRPoolp); - + mDataLock = new LLMutex(mAPRPoolp); mLocalAPRFilePoolp = NULL ; } @@ -185,7 +192,10 @@ void LLThread::shutdown() } delete mRunCondition; - mRunCondition = 0; + mRunCondition = NULL; + + delete mDataLock; + mDataLock = NULL; if (mIsLocalPool && mAPRPoolp) { @@ -254,28 +264,30 @@ bool LLThread::runCondition(void) // Stop thread execution if requested until unpaused. void LLThread::checkPause() { - mRunCondition->lock(); + mDataLock->lock(); // This is in a while loop because the pthread API allows for spurious wakeups. while(shouldSleep()) { + mDataLock->unlock(); mRunCondition->wait(); // unlocks mRunCondition + mDataLock->lock(); // mRunCondition is locked when the thread wakes up } - mRunCondition->unlock(); + mDataLock->unlock(); } //============================================================================ void LLThread::setQuitting() { - mRunCondition->lock(); + mDataLock->lock(); if (mStatus == RUNNING) { mStatus = QUITTING; } - mRunCondition->unlock(); + mDataLock->unlock(); wake(); } @@ -297,12 +309,12 @@ void LLThread::yield() void LLThread::wake() { - mRunCondition->lock(); + mDataLock->lock(); if(!shouldSleep()) { mRunCondition->signal(); } - mRunCondition->unlock(); + mDataLock->unlock(); } void LLThread::wakeLocked() @@ -313,3 +325,62 @@ void LLThread::wakeLocked() } } +//============================================================================ + +//---------------------------------------------------------------------------- + +//static +LLMutex* LLThreadSafeRefCount::sMutex = 0; + +//static +void LLThreadSafeRefCount::initThreadSafeRefCount() +{ + if (!sMutex) + { + sMutex = new LLMutex(0); + } +} + +//static +void LLThreadSafeRefCount::cleanupThreadSafeRefCount() +{ + delete sMutex; + sMutex = NULL; +} + + +//---------------------------------------------------------------------------- + +LLThreadSafeRefCount::LLThreadSafeRefCount() : + mRef(0) +{ +} + +LLThreadSafeRefCount::LLThreadSafeRefCount(const LLThreadSafeRefCount& src) +{ + if (sMutex) + { + sMutex->lock(); + } + mRef = 0; + if (sMutex) + { + sMutex->unlock(); + } +} + +LLThreadSafeRefCount::~LLThreadSafeRefCount() +{ + if (mRef != 0) + { + llerrs << "deleting non-zero reference" << llendl; + } +} + +//============================================================================ + +LLResponder::~LLResponder() +{ +} + +//============================================================================ diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index 93c752754d..75222c83f9 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -42,7 +42,7 @@ private: #if LL_DARWIN // statically allocated thread local storage not supported in Darwin executable formats #elif LL_WINDOWS - static U32 __declspec(thread) LLThread::sThreadIndex; + static U32 __declspec(thread) LLThread::sThreadID; #elif LL_LINUX static U32 __thread LLThread::sThreadID ; #endif @@ -89,6 +89,11 @@ public: U32 getID() const { return mID; } + // Called by threads *not* created via LLThread to register some + // internal state used by LLMutex. You must call this once early + // in the running thread to prevent collisions with the main thread. + static void registerThreadID(); + private: BOOL mPaused; @@ -98,6 +103,7 @@ private: protected: std::string mName; class LLCondition* mRunCondition; + LLMutex* mDataLock; apr_thread_t *mAPRThreadp; apr_pool_t *mAPRPoolp; @@ -123,29 +129,105 @@ protected: inline void unlockData(); // 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 mDataLock locked, since the virtual runCondition() function may need to access // data structures that are thread-unsafe. 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: - // mRunCondition->lock(); + // mDataLock->lock(); // if(!shouldSleep()) // mRunCondition->signal(); - // mRunCondition->unlock(); + // mDataLock->unlock(); }; void LLThread::lockData() { - mRunCondition->lock(); + mDataLock->lock(); } void LLThread::unlockData() { - mRunCondition->unlock(); + mDataLock->unlock(); } //============================================================================ +// see llmemory.h for LLPointer<> definition + +class LL_COMMON_API LLThreadSafeRefCount +{ +public: + static void initThreadSafeRefCount(); // creates sMutex + static void cleanupThreadSafeRefCount(); // destroys sMutex + +private: + static LLMutex* sMutex; + +protected: + virtual ~LLThreadSafeRefCount(); // use unref() + +public: + LLThreadSafeRefCount(); + LLThreadSafeRefCount(const LLThreadSafeRefCount&); + LLThreadSafeRefCount& operator=(const LLThreadSafeRefCount& ref) + { + if (sMutex) + { + sMutex->lock(); + } + mRef = 0; + if (sMutex) + { + sMutex->unlock(); + } + return *this; + } + + + + void ref() + { + if (sMutex) sMutex->lock(); + mRef++; + if (sMutex) sMutex->unlock(); + } + + S32 unref() + { + llassert(mRef >= 1); + if (sMutex) sMutex->lock(); + S32 res = --mRef; + if (sMutex) sMutex->unlock(); + if (0 == res) + { + delete this; + return 0; + } + return res; + } + S32 getNumRefs() const + { + return mRef; + } + +private: + S32 mRef; +}; + +//============================================================================ + +// Simple responder for self destructing callbacks +// Pure virtual class +class LL_COMMON_API LLResponder : public LLThreadSafeRefCount +{ +protected: + virtual ~LLResponder(); +public: + virtual void completed(bool success) = 0; +}; + +//============================================================================ + #endif // LL_LLTHREAD_H diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h index 61d14569cd..11651ef953 100644 --- a/indra/llcommon/lltrace.h +++ b/indra/llcommon/lltrace.h @@ -107,6 +107,7 @@ namespace LLTrace //TODO pick another primary? sPrimaryStorage = NULL; } + delete[] mStorage; } LL_FORCE_INLINE ACCUMULATOR& operator[](size_t index) diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp index 4252ed57dc..e7ed55e8ae 100644 --- a/indra/llcommon/lltracerecording.cpp +++ b/indra/llcommon/lltracerecording.cpp @@ -66,7 +66,10 @@ Recording::Recording( const Recording& other ) Recording::~Recording() -{} +{ + stop(); + llassert(isStopped()); +} void Recording::update() { diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp index c2fefe2957..faaab4c8e7 100644 --- a/indra/llcommon/lltracethreadrecorder.cpp +++ b/indra/llcommon/lltracethreadrecorder.cpp @@ -53,6 +53,10 @@ ThreadRecorder::ThreadRecorder( const ThreadRecorder& other ) ThreadRecorder::~ThreadRecorder() { + while(mActiveRecordings.size()) + { + mActiveRecordings.front().mTargetRecording->stop(); + } get_thread_recorder() = NULL; delete BlockTimer::sCurTimerData.get(); BlockTimer::sCurTimerData = NULL; diff --git a/indra/llcommon/llunit.h b/indra/llcommon/llunit.h index 1fe492fdce..53570779fc 100644 --- a/indra/llcommon/llunit.h +++ b/indra/llcommon/llunit.h @@ -109,9 +109,9 @@ struct LLUnit return mValue; } - template<typename NEW_UNIT_TYPE> LLUnit<NEW_UNIT_TYPE, STORAGE_TYPE> as() + template<typename NEW_UNIT_TYPE, typename NEW_STORAGE_TYPE> LLUnit<NEW_UNIT_TYPE, NEW_STORAGE_TYPE> as() { - return LLUnit<NEW_UNIT_TYPE, STORAGE_TYPE>(*this); + return LLUnit<NEW_UNIT_TYPE, NEW_STORAGE_TYPE>(*this); } void operator += (storage_t value) @@ -332,21 +332,27 @@ struct HighestPrecisionType<LLUnit<UNIT_TYPE, STORAGE_TYPE> > typedef typename HighestPrecisionType<STORAGE_TYPE>::type_t type_t; }; -#define LL_DECLARE_DERIVED_UNIT(base_unit_name, unit_name, conversion_factor) \ -struct unit_name \ -{ \ - typedef base_unit_name base_unit_t; \ -}; \ -template<typename STORAGE_TYPE> \ -struct ConversionFactor<unit_name, base_unit_name, STORAGE_TYPE> \ -{ \ - static typename HighestPrecisionType<STORAGE_TYPE>::type_t get() { return typename HighestPrecisionType<STORAGE_TYPE>::type_t(conversion_factor); } \ -}; \ - \ -template<typename STORAGE_TYPE> \ -struct ConversionFactor<base_unit_name, unit_name, STORAGE_TYPE> \ -{ \ - static typename HighestPrecisionType<STORAGE_TYPE>::type_t get() { return typename HighestPrecisionType<STORAGE_TYPE>::type_t(1.0 / (conversion_factor)); } \ +#define LL_DECLARE_DERIVED_UNIT(base_unit_name, unit_name, conversion_factor) \ +struct unit_name \ +{ \ + typedef base_unit_name base_unit_t; \ +}; \ +template<typename STORAGE_TYPE> \ +struct ConversionFactor<unit_name, base_unit_name, STORAGE_TYPE> \ +{ \ + static typename HighestPrecisionType<STORAGE_TYPE>::type_t get() \ + { \ + return typename HighestPrecisionType<STORAGE_TYPE>::type_t(conversion_factor); \ + } \ +}; \ + \ +template<typename STORAGE_TYPE> \ +struct ConversionFactor<base_unit_name, unit_name, STORAGE_TYPE> \ +{ \ + static typename HighestPrecisionType<STORAGE_TYPE>::type_t get() \ + { \ + return typename HighestPrecisionType<STORAGE_TYPE>::type_t(1.0 / (conversion_factor)); \ + } \ } struct Bytes { typedef Bytes base_unit_t; }; diff --git a/indra/llcommon/lluri.cpp b/indra/llcommon/lluri.cpp index b39ea0c6f2..21456a599b 100644 --- a/indra/llcommon/lluri.cpp +++ b/indra/llcommon/lluri.cpp @@ -37,6 +37,8 @@ // system includes #include <boost/tokenizer.hpp> +#include <boost/algorithm/string/find_iterator.hpp> +#include <boost/algorithm/string/finder.hpp> void encode_character(std::ostream& ostr, std::string::value_type val) { @@ -317,7 +319,7 @@ LLURI LLURI::buildHTTP(const std::string& prefix, const LLSD& path) { LLURI result; - + // TODO: deal with '/' '?' '#' in host_port if (prefix.find("://") != prefix.npos) { @@ -342,15 +344,41 @@ LLURI LLURI::buildHTTP(const std::string& prefix, result.mEscapedPath += "/" + escapePathComponent(it->asString()); } } - else if(path.isString()) + else if (path.isString()) { - result.mEscapedPath += "/" + escapePathComponent(path.asString()); + std::string pathstr(path); + // Trailing slash is significant in HTTP land. If caller specified, + // make a point of preserving. + std::string last_slash; + std::string::size_type len(pathstr.length()); + if (len && pathstr[len-1] == '/') + { + last_slash = "/"; + } + + // Escape every individual path component, recombining with slashes. + for (boost::split_iterator<std::string::const_iterator> + ti(pathstr, boost::first_finder("/")), tend; + ti != tend; ++ti) + { + // Eliminate a leading slash or duplicate slashes anywhere. (Extra + // slashes show up here as empty components.) This test also + // eliminates a trailing slash, hence last_slash above. + if (! ti->empty()) + { + result.mEscapedPath + += "/" + escapePathComponent(std::string(ti->begin(), ti->end())); + } + } + + // Reinstate trailing slash, if any. + result.mEscapedPath += last_slash; } else if(path.isUndefined()) { // do nothing } - else + else { llwarns << "Valid path arguments to buildHTTP are array, string, or undef, you passed type" << path.type() << llendl; diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h index bcc661a920..8585af0a29 100644 --- a/indra/llcommon/llversionviewer.h +++ b/indra/llcommon/llversionviewer.h @@ -29,7 +29,7 @@ const S32 LL_VERSION_MAJOR = 3; const S32 LL_VERSION_MINOR = 4; -const S32 LL_VERSION_PATCH = 1; +const S32 LL_VERSION_PATCH = 4; const S32 LL_VERSION_BUILD = 0; const char * const LL_CHANNEL = "Second Life Developer"; diff --git a/indra/llcommon/tests/bitpack_test.cpp b/indra/llcommon/tests/bitpack_test.cpp index 05289881d0..4c3bc674af 100644 --- a/indra/llcommon/tests/bitpack_test.cpp +++ b/indra/llcommon/tests/bitpack_test.cpp @@ -95,6 +95,7 @@ namespace tut ensure("bitPack: individual unpack: 5", unpackbuffer[0] == (U8) str[5]); unpack_bufsize = bitunpack.bitUnpack(unpackbuffer, 8*4); // Life ensure_memory_matches("bitPack: 4 bytes unpack:", unpackbuffer, 4, str+6, 4); + ensure("keep compiler quiet", unpack_bufsize == unpack_bufsize); } // U32 packing diff --git a/indra/llcommon/tests/lluri_test.cpp b/indra/llcommon/tests/lluri_test.cpp index f6d4221256..4c64f15ca7 100644 --- a/indra/llcommon/tests/lluri_test.cpp +++ b/indra/llcommon/tests/lluri_test.cpp @@ -58,12 +58,12 @@ namespace tut ensure_equals("escape/unescape escaped", uri_esc_2, uri_esc_1); } }; - + typedef test_group<URITestData> URITestGroup; typedef URITestGroup::object URITestObject; URITestGroup uriTestGroup("LLURI"); - + template<> template<> void URITestObject::test<1>() { @@ -89,14 +89,14 @@ namespace tut template<> template<> void URITestObject::test<2>() { - // empty string + set_test_name("empty string"); checkParts(LLURI(""), "", "", "", ""); } - + template<> template<> void URITestObject::test<3>() { - // no scheme + set_test_name("no scheme"); checkParts(LLURI("foo"), "", "foo", "", ""); checkParts(LLURI("foo%3A"), "", "foo:", "", ""); } @@ -104,7 +104,7 @@ namespace tut template<> template<> void URITestObject::test<4>() { - // scheme w/o paths + set_test_name("scheme w/o paths"); checkParts(LLURI("mailto:zero@ll.com"), "mailto", "zero@ll.com", "", ""); checkParts(LLURI("silly://abc/def?foo"), @@ -114,16 +114,16 @@ namespace tut template<> template<> void URITestObject::test<5>() { - // authority section + set_test_name("authority section"); checkParts(LLURI("http:///"), "http", "///", "", "/"); - + checkParts(LLURI("http://abc"), "http", "//abc", "abc", ""); - + checkParts(LLURI("http://a%2Fb/cd"), "http", "//a/b/cd", "a/b", "/cd"); - + checkParts(LLURI("http://host?"), "http", "//host?", "host", ""); } @@ -131,13 +131,13 @@ namespace tut template<> template<> void URITestObject::test<6>() { - // path section + set_test_name("path section"); checkParts(LLURI("http://host/a/b/"), "http", "//host/a/b/", "host", "/a/b/"); - + checkParts(LLURI("http://host/a%3Fb/"), "http", "//host/a?b/", "host", "/a?b/"); - + checkParts(LLURI("http://host/a:b/"), "http", "//host/a:b/", "host", "/a:b/"); } @@ -145,16 +145,16 @@ namespace tut template<> template<> void URITestObject::test<7>() { - // query string + set_test_name("query string"); checkParts(LLURI("http://host/?"), "http", "//host/?", "host", "/", ""); - + checkParts(LLURI("http://host/?x"), "http", "//host/?x", "host", "/", "x"); - + checkParts(LLURI("http://host/??"), "http", "//host/??", "host", "/", "?"); - + checkParts(LLURI("http://host/?%3F"), "http", "//host/??", "host", "/", "?"); } @@ -167,19 +167,44 @@ namespace tut path.append("123"); checkParts(LLURI::buildHTTP("host", path), "http", "//host/x/123", "host", "/x/123"); - + LLSD query; query["123"] = "12"; query["abcd"] = "abc"; checkParts(LLURI::buildHTTP("host", path, query), "http", "//host/x/123?123=12&abcd=abc", "host", "/x/123", "123=12&abcd=abc"); + + ensure_equals(LLURI::buildHTTP("host", "").asString(), + "http://host"); + ensure_equals(LLURI::buildHTTP("host", "/").asString(), + "http://host/"); + ensure_equals(LLURI::buildHTTP("host", "//").asString(), + "http://host/"); + ensure_equals(LLURI::buildHTTP("host", "dir name").asString(), + "http://host/dir%20name"); + ensure_equals(LLURI::buildHTTP("host", "dir name/").asString(), + "http://host/dir%20name/"); + ensure_equals(LLURI::buildHTTP("host", "/dir name").asString(), + "http://host/dir%20name"); + ensure_equals(LLURI::buildHTTP("host", "/dir name/").asString(), + "http://host/dir%20name/"); + ensure_equals(LLURI::buildHTTP("host", "dir name/subdir name").asString(), + "http://host/dir%20name/subdir%20name"); + ensure_equals(LLURI::buildHTTP("host", "dir name/subdir name/").asString(), + "http://host/dir%20name/subdir%20name/"); + ensure_equals(LLURI::buildHTTP("host", "/dir name/subdir name").asString(), + "http://host/dir%20name/subdir%20name"); + ensure_equals(LLURI::buildHTTP("host", "/dir name/subdir name/").asString(), + "http://host/dir%20name/subdir%20name/"); + ensure_equals(LLURI::buildHTTP("host", "//dir name//subdir name//").asString(), + "http://host/dir%20name/subdir%20name/"); } template<> template<> void URITestObject::test<9>() { - // test unescaped path components + set_test_name("test unescaped path components"); LLSD path; path.append("x@*//*$&^"); path.append("123"); @@ -190,7 +215,7 @@ namespace tut template<> template<> void URITestObject::test<10>() { - // test unescaped query components + set_test_name("test unescaped query components"); LLSD path; path.append("x"); path.append("123"); @@ -205,7 +230,7 @@ namespace tut template<> template<> void URITestObject::test<11>() { - // test unescaped host components + set_test_name("test unescaped host components"); LLSD path; path.append("x"); path.append("123"); @@ -216,16 +241,16 @@ namespace tut "http", "//hi123*33--}{:portstuffs/x/123?123=12&abcd=abc", "hi123*33--}{:portstuffs", "/x/123", "123=12&abcd=abc"); } - + template<> template<> void URITestObject::test<12>() { - // test funky host_port values that are actually prefixes - + set_test_name("test funky host_port values that are actually prefixes"); + checkParts(LLURI::buildHTTP("http://example.com:8080", LLSD()), "http", "//example.com:8080", "example.com:8080", ""); - + checkParts(LLURI::buildHTTP("http://example.com:8080/", LLSD()), "http", "//example.com:8080/", "example.com:8080", "/"); @@ -242,7 +267,7 @@ namespace tut "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" "0123456789" "-._~"; - // test escape + set_test_name("test escape"); ensure_equals("escaping", LLURI::escape("abcdefg", "abcdef"), "abcdef%67"); ensure_equals("escaping", LLURI::escape("|/&\\+-_!@", ""), "%7C%2F%26%5C%2B%2D%5F%21%40"); ensure_equals("escaping as query variable", @@ -259,13 +284,12 @@ namespace tut cedilla.push_back( (char)0xA7 ); ensure_equals("escape UTF8", LLURI::escape( cedilla, unreserved), "%C3%A7"); } - + template<> template<> void URITestObject::test<14>() { - // make sure escape and unescape of empty strings return empty - // strings. + set_test_name("make sure escape and unescape of empty strings return empty strings."); std::string uri_esc(LLURI::escape("")); ensure("escape string empty", uri_esc.empty()); std::string uri_raw(LLURI::unescape("")); @@ -275,7 +299,7 @@ namespace tut template<> template<> void URITestObject::test<15>() { - // do some round-trip tests + set_test_name("do some round-trip tests"); escapeRoundTrip("http://secondlife.com"); escapeRoundTrip("http://secondlife.com/url with spaces"); escapeRoundTrip("http://bad[domain]name.com/"); @@ -286,7 +310,7 @@ namespace tut template<> template<> void URITestObject::test<16>() { - // Test the default escaping + set_test_name("Test the default escaping"); // yes -- this mangles the url. This is expected behavior std::string simple("http://secondlife.com"); ensure_equals( @@ -302,7 +326,7 @@ namespace tut template<> template<> void URITestObject::test<17>() { - // do some round-trip tests with very long strings. + set_test_name("do some round-trip tests with very long strings."); escapeRoundTrip("Welcome to Second Life.We hope you'll have a richly rewarding experience, filled with creativity, self expression and fun.The goals of the Community Standards are simple: treat each other with respect and without harassment, adhere to local standards as indicated by simulator ratings, and refrain from any hate activity which slurs a real-world individual or real-world community. Behavioral Guidelines - The Big Six"); escapeRoundTrip( "'asset_data':b(12100){'task_id':ucc706f2d-0b68-68f8-11a4-f1043ff35ca0}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444921\n\ttotal_crc\t323\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.368634403\t0.00781063363\t-0.569040775\n\toldpos\t150.117996\t25.8658009\t8.19664001\n\trotation\t-0.06293071806430816650390625\t-0.6995697021484375\t-0.7002241611480712890625\t0.1277817934751510620117188\n\tchildpos\t-0.00499999989\t-0.0359999985\t0.307999998\n\tchildrot\t-0.515492737293243408203125\t-0.46601200103759765625\t0.529055416584014892578125\t0.4870323240756988525390625\n\tscale" @@ -322,7 +346,7 @@ namespace tut "D STRING RW SV 20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\torig_asset_id\t8747acbc-d391-1e59-69f1-41d06830e6c0\n\torig_item_id\t20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tfrom_task_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tlinked\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n"); } - + template<> template<> void URITestObject::test<18>() { @@ -335,7 +359,7 @@ namespace tut ensure_equals("pathmap", u.pathArray()[1].asString(), "login"); ensure_equals("query", u.query(), "first_name=Testert4&last_name=Tester&web_login_key=test"); ensure_equals("query map element", u.queryMap()["last_name"].asString(), "Tester"); - + u = LLURI("secondlife://Da Boom/128/128/128"); // if secondlife is the scheme, LLURI should parse /128/128/128 as path, with Da Boom as authority ensure_equals("scheme", u.scheme(), "secondlife"); @@ -350,7 +374,7 @@ namespace tut template<> template<> void URITestObject::test<19>() { - // Parse about: schemes + set_test_name("Parse about: schemes"); LLURI u("about:blank?redirect-http-hack=secondlife%3A%2F%2F%2Fapp%2Flogin%3Ffirst_name%3DCallum%26last_name%3DLinden%26location%3Dspecify%26grid%3Dvaak%26region%3D%2FMorris%2F128%2F128%26web_login_key%3Defaa4795-c2aa-4c58-8966-763c27931e78"); ensure_equals("scheme", u.scheme(), "about"); ensure_equals("authority", u.authority(), ""); diff --git a/indra/llcommon/tests/reflection_test.cpp b/indra/llcommon/tests/reflection_test.cpp index 59491cd1fe..8980ebb1f1 100644 --- a/indra/llcommon/tests/reflection_test.cpp +++ b/indra/llcommon/tests/reflection_test.cpp @@ -207,7 +207,7 @@ namespace tut const LLReflective* reflective = property->get(aggregated_data); // Wrong reflective type, should throw exception. // useless op to get rid of compiler warning. - reflective = NULL; + reflective = reflective; } catch(...) { |