diff options
Diffstat (limited to 'indra/llcommon')
39 files changed, 992 insertions, 447 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index dd7b8c6eb8..66e2bc9095 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -116,6 +116,7 @@ set(llcommon_HEADER_FILES bitpack.h ctype_workaround.h doublelinkedlist.h + fix_macros.h imageids.h indra_constants.h linden_common.h @@ -174,6 +175,7 @@ set(llcommon_HEADER_FILES llfoldertype.h llformat.h llframetimer.h + llhandle.h llhash.h llheartbeat.h llhttpstatuscodes.h diff --git a/indra/llcommon/fix_macros.h b/indra/llcommon/fix_macros.h new file mode 100644 index 0000000000..ef959decff --- /dev/null +++ b/indra/llcommon/fix_macros.h @@ -0,0 +1,25 @@ +/** + * @file fix_macros.h + * @author Nat Goodspeed + * @date 2012-11-16 + * @brief The Mac system headers seem to #define macros with obnoxiously + * generic names, preventing any library from using those names. We've + * had to fix these in so many places that it's worth making a header + * file to handle it. + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Copyright (c) 2012, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// DON'T use an #include guard: every time we encounter this header, #undef +// these macros all over again. + +// who injects MACROS with such generic names?! Grr. +#ifdef equivalent +#undef equivalent +#endif + +#ifdef check +#undef check +#endif diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index 0745696ef3..0da83720bd 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -62,6 +62,7 @@ enum LAND_STAT_FLAGS STAT_FILTER_BY_PARCEL = 0x00000001, STAT_FILTER_BY_OWNER = 0x00000002, STAT_FILTER_BY_OBJECT = 0x00000004, + STAT_FILTER_BY_PARCEL_NAME = 0x00000008, STAT_REQUEST_LAST_ENTRY = 0x80000000, }; diff --git a/indra/llcommon/llallocator.cpp b/indra/llcommon/llallocator.cpp index 6f6abefc67..87654b5b97 100644 --- a/indra/llcommon/llallocator.cpp +++ b/indra/llcommon/llallocator.cpp @@ -27,7 +27,7 @@ #include "linden_common.h" #include "llallocator.h" -#if LL_USE_TCMALLOC +#if (LL_USE_TCMALLOC && LL_USE_HEAP_PROFILER) #include "google/heap-profiler.h" #include "google/commandlineflags_public.h" 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 af33ce666f..034546c3f3 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -168,7 +168,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/llcursortypes.cpp b/indra/llcommon/llcursortypes.cpp index e987c397bd..ec60097195 100644 --- a/indra/llcommon/llcursortypes.cpp +++ b/indra/llcommon/llcursortypes.cpp @@ -69,6 +69,12 @@ ECursorType getCursorFromString(const std::string& cursor_string) cursor_string_table["UI_CURSOR_TOOLSIT"] = UI_CURSOR_TOOLSIT; cursor_string_table["UI_CURSOR_TOOLBUY"] = UI_CURSOR_TOOLBUY; cursor_string_table["UI_CURSOR_TOOLOPEN"] = UI_CURSOR_TOOLOPEN; + cursor_string_table["UI_CURSOR_TOOLPATHFINDING"] = UI_CURSOR_TOOLPATHFINDING; + cursor_string_table["UI_CURSOR_TOOLPATHFINDINGPATHSTART"] = UI_CURSOR_TOOLPATHFINDING_PATH_START; + cursor_string_table["UI_CURSOR_TOOLPATHFINDINGPATHSTARTADD"] = UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD; + cursor_string_table["UI_CURSOR_TOOLPATHFINDINGPATHEND"] = UI_CURSOR_TOOLPATHFINDING_PATH_END; + cursor_string_table["UI_CURSOR_TOOLPATHFINDINGPATHENDADD"] = UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD; + cursor_string_table["UI_CURSOR_TOOLNO"] = UI_CURSOR_TOOLNO; } std::map<std::string,U32>::const_iterator iter = cursor_string_table.find(cursor_string); diff --git a/indra/llcommon/llcursortypes.h b/indra/llcommon/llcursortypes.h index bacb0a80ba..cb6d6636a0 100644 --- a/indra/llcommon/llcursortypes.h +++ b/indra/llcommon/llcursortypes.h @@ -65,6 +65,12 @@ enum ECursorType { UI_CURSOR_TOOLSIT, UI_CURSOR_TOOLBUY, UI_CURSOR_TOOLOPEN, + UI_CURSOR_TOOLPATHFINDING, + UI_CURSOR_TOOLPATHFINDING_PATH_START, + UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD, + UI_CURSOR_TOOLPATHFINDING_PATH_END, + UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD, + UI_CURSOR_TOOLNO, UI_CURSOR_COUNT // Number of elements in this enum (NOT a cursor) }; diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 7e6eee0f3c..9b0141eb76 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -534,7 +534,7 @@ namespace } - void commonInit(const std::string& dir) + void commonInit(const std::string& dir, bool log_to_stderr = true) { LLError::Settings::reset(); @@ -542,7 +542,8 @@ namespace LLError::setFatalFunction(LLError::crashAndLoop); LLError::setTimeFunction(LLError::utcTime); - if (shouldLogToStderr()) + // log_to_stderr is only false in the unit and integration tests to keep builds quieter + if (log_to_stderr && shouldLogToStderr()) { LLError::addRecorder(new RecordToStderr(stderrLogWantsTime())); } @@ -580,9 +581,9 @@ namespace LLError #endif } - void initForApplication(const std::string& dir) + void initForApplication(const std::string& dir, bool log_to_stderr) { - commonInit(dir); + commonInit(dir, log_to_stderr); } void setPrintLocation(bool print) diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index b3e604f8e8..b65b410153 100644 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -35,7 +35,7 @@ #include "stdtypes.h" -/* Error Logging Facility +/** Error Logging Facility Information for most users: @@ -100,7 +100,6 @@ even release. Which means you can use them to help debug even when deployed to a real grid. */ - namespace LLError { enum ELevel @@ -143,9 +142,13 @@ namespace LLError CallSite(ELevel, const char* file, int line, const std::type_info& class_info, const char* function, const char* broadTag, const char* narrowTag, bool printOnce); +#ifdef LL_LIBRARY_INCLUDE + bool shouldLog(); +#else // LL_LIBRARY_INCLUDE bool shouldLog() { return mCached ? mShouldLog : Log::shouldLog(*this); } // this member function needs to be in-line for efficiency +#endif // LL_LIBRARY_INCLUDE void invalidate(); diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h index d53a819d88..480654b1a2 100644 --- a/indra/llcommon/llerrorcontrol.h +++ b/indra/llcommon/llerrorcontrol.h @@ -62,7 +62,7 @@ namespace LLError // logs to stderr, syslog, and windows debug log // the identity string is used for in the syslog - LL_COMMON_API void initForApplication(const std::string& dir); + LL_COMMON_API void initForApplication(const std::string& dir, bool log_to_stderr = true); // resets all logging settings to defaults needed by applicaitons // logs to stderr and windows debug log // sets up log configuration from the file logcontrol.xml in dir diff --git a/indra/llcommon/llhandle.h b/indra/llcommon/llhandle.h new file mode 100644 index 0000000000..6af5e198d6 --- /dev/null +++ b/indra/llcommon/llhandle.h @@ -0,0 +1,217 @@ +/** +* @file llhandle.h +* @brief "Handle" to an object (usually a floater) whose lifetime you don't +* control. +* +* $LicenseInfo:firstyear=2001&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2010, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ +#ifndef LLHANDLE_H +#define LLHANDLE_H + +#include "llpointer.h" +#include <boost/type_traits/is_convertible.hpp> +#include <boost/utility/enable_if.hpp> + +/** + * Helper object for LLHandle. Don't instantiate these directly, used + * exclusively by LLHandle. + */ +class LLTombStone : public LLRefCount +{ +public: + LLTombStone(void* target = NULL) : mTarget(target) {} + + void setTarget(void* target) { mTarget = target; } + void* getTarget() const { return mTarget; } +private: + mutable void* mTarget; +}; + +/** + * LLHandles are used to refer to objects whose lifetime you do not control or influence. + * Calling get() on a handle will return a pointer to the referenced object or NULL, + * if the object no longer exists. Note that during the lifetime of the returned pointer, + * you are assuming that the object will not be deleted by any action you perform, + * or any other thread, as normal when using pointers, so avoid using that pointer outside of + * the local code block. + * + * https://wiki.lindenlab.com/mediawiki/index.php?title=LLHandle&oldid=79669 + * + * The implementation is like some "weak pointer" implementations. When we + * can't control the lifespan of the referenced object of interest, we can + * still instantiate a proxy object whose lifespan we DO control, and store in + * the proxy object a dumb pointer to the actual target. Then we just have to + * ensure that on destruction of the target object, the proxy's dumb pointer + * is set NULL. + * + * LLTombStone is our proxy object. LLHandle contains an LLPointer to the + * LLTombStone, so every copy of an LLHandle increments the LLTombStone's ref + * count as usual. + * + * One copy of the LLHandle, specifically the LLRootHandle, must be stored in + * the referenced object. Destroying the LLRootHandle is what NULLs the + * proxy's target pointer. + * + * Minor optimization: we want LLHandle's mTombStone to always be a valid + * LLPointer, saving some conditionals in dereferencing. That's the + * getDefaultTombStone() mechanism. The default LLTombStone object's target + * pointer is always NULL, so it's semantically identical to allowing + * mTombStone to be invalid. + */ +template <typename T> +class LLHandle +{ + template <typename U> friend class LLHandle; + template <typename U> friend class LLHandleProvider; +public: + LLHandle() : mTombStone(getDefaultTombStone()) {} + + template<typename U> + LLHandle(const LLHandle<U>& other, typename boost::enable_if< typename boost::is_convertible<U*, T*> >::type* dummy = 0) + : mTombStone(other.mTombStone) + {} + + bool isDead() const + { + return mTombStone->getTarget() == NULL; + } + + void markDead() + { + mTombStone = getDefaultTombStone(); + } + + T* get() const + { + return reinterpret_cast<T*>(mTombStone->getTarget()); + } + + friend bool operator== (const LLHandle<T>& lhs, const LLHandle<T>& rhs) + { + return lhs.mTombStone == rhs.mTombStone; + } + friend bool operator!= (const LLHandle<T>& lhs, const LLHandle<T>& rhs) + { + return !(lhs == rhs); + } + friend bool operator< (const LLHandle<T>& lhs, const LLHandle<T>& rhs) + { + return lhs.mTombStone < rhs.mTombStone; + } + friend bool operator> (const LLHandle<T>& lhs, const LLHandle<T>& rhs) + { + return lhs.mTombStone > rhs.mTombStone; + } + +protected: + LLPointer<LLTombStone> mTombStone; + +private: + typedef T* pointer_t; + static LLPointer<LLTombStone>& getDefaultTombStone() + { + static LLPointer<LLTombStone> sDefaultTombStone = new LLTombStone; + return sDefaultTombStone; + } +}; + +/** + * LLRootHandle isa LLHandle which must be stored in the referenced object. + * You can either store it directly and explicitly bind(this), or derive from + * LLHandleProvider (q.v.) which automates that for you. The essential point + * is that destroying the LLRootHandle (as a consequence of destroying the + * referenced object) calls unbind(), setting the LLTombStone's target pointer + * NULL. + */ +template <typename T> +class LLRootHandle : public LLHandle<T> +{ +public: + typedef LLRootHandle<T> self_t; + typedef LLHandle<T> base_t; + + LLRootHandle(T* object) { bind(object); } + LLRootHandle() {}; + ~LLRootHandle() { unbind(); } + + // this is redundant, since an LLRootHandle *is* an LLHandle + //LLHandle<T> getHandle() { return LLHandle<T>(*this); } + + void bind(T* object) + { + // unbind existing tombstone + if (LLHandle<T>::mTombStone.notNull()) + { + if (LLHandle<T>::mTombStone->getTarget() == (void*)object) return; + LLHandle<T>::mTombStone->setTarget(NULL); + } + // tombstone reference counted, so no paired delete + LLHandle<T>::mTombStone = new LLTombStone((void*)object); + } + + void unbind() + { + LLHandle<T>::mTombStone->setTarget(NULL); + } + + //don't allow copying of root handles, since there should only be one +private: + LLRootHandle(const LLRootHandle& other) {}; +}; + +/** + * Use this as a mixin for simple classes that need handles and when you don't + * want handles at multiple points of the inheritance hierarchy + */ +template <typename T> +class LLHandleProvider +{ +public: + LLHandle<T> getHandle() const + { + // perform lazy binding to avoid small tombstone allocations for handle + // providers whose handles are never referenced + mHandle.bind(static_cast<T*>(const_cast<LLHandleProvider<T>* >(this))); + return mHandle; + } + +protected: + typedef LLHandle<T> handle_type_t; + LLHandleProvider() + { + // provided here to enforce T deriving from LLHandleProvider<T> + } + + template <typename U> + LLHandle<U> getDerivedHandle(typename boost::enable_if< typename boost::is_convertible<U*, T*> >::type* dummy = 0) const + { + LLHandle<U> downcast_handle; + downcast_handle.mTombStone = getHandle().mTombStone; + return downcast_handle; + } + + +private: + mutable LLRootHandle<T> mHandle; +}; + +#endif diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h index 99983a19cb..9a6d1eff5c 100644 --- a/indra/llcommon/llinitparam.h +++ b/indra/llcommon/llinitparam.h @@ -35,7 +35,7 @@ #include <boost/shared_ptr.hpp> #include "llerror.h" -#include "lltypeinfolookup.h" +#include "llstl.h" namespace LLInitParam { @@ -212,14 +212,6 @@ namespace LLInitParam public: - struct CompareTypeID - { - bool operator()(const std::type_info* lhs, const std::type_info* rhs) const - { - return lhs->before(*rhs); - } - }; - typedef std::vector<std::pair<std::string, bool> > name_stack_t; typedef std::pair<name_stack_t::iterator, name_stack_t::iterator> name_stack_range_t; typedef std::vector<std::string> possible_values_t; @@ -228,9 +220,9 @@ namespace LLInitParam typedef bool (*parser_write_func_t)(Parser& parser, const void*, name_stack_t&); typedef boost::function<void (name_stack_t&, S32, S32, const possible_values_t*)> parser_inspect_func_t; - typedef LLTypeInfoLookup<parser_read_func_t> parser_read_func_map_t; - typedef LLTypeInfoLookup<parser_write_func_t> parser_write_func_map_t; - typedef LLTypeInfoLookup<parser_inspect_func_t> parser_inspect_func_map_t; + typedef std::map<const std::type_info*, parser_read_func_t> parser_read_func_map_t; + typedef std::map<const std::type_info*, parser_write_func_t> parser_write_func_map_t; + typedef std::map<const std::type_info*, parser_inspect_func_t> parser_inspect_func_map_t; Parser(parser_read_func_map_t& read_map, parser_write_func_map_t& write_map, parser_inspect_func_map_t& inspect_map) : mParseSilently(false), diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 3b9758f996..70ad10ad55 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -61,6 +61,18 @@ BOOL LLMemory::sEnableMemoryFailurePrevention = FALSE; LLPrivateMemoryPoolManager::mem_allocation_info_t LLPrivateMemoryPoolManager::sMemAllocationTracker; #endif +void ll_assert_aligned_func(uintptr_t ptr,U32 alignment) +{ +#ifdef SHOW_ASSERT + // Redundant, place to set breakpoints. + if (ptr%alignment!=0) + { + llwarns << "alignment check failed" << llendl; + } + llassert(ptr%alignment==0); +#endif +} + //static void LLMemory::initClass() { @@ -240,21 +252,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) @@ -1353,7 +1350,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 ; @@ -1410,7 +1407,7 @@ char* LLPrivateMemoryPool::allocate(U32 size) to_log = false ; } - return (char*)malloc(size) ; + return (char*)ll_aligned_malloc_16(size) ; } return p ; @@ -1429,7 +1426,7 @@ void LLPrivateMemoryPool::freeMem(void* addr) if(!chunk) { - free(addr) ; //release from heap + ll_aligned_free_16(addr) ; //release from heap } else { @@ -1553,7 +1550,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 ; @@ -1621,7 +1618,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) @@ -1965,7 +1962,7 @@ char* LLPrivateMemoryPoolManager::allocate(LLPrivateMemoryPool* poolp, U32 size, if(!poolp) { - p = (char*)malloc(size) ; + p = (char*)ll_aligned_malloc_16(size) ; } else { @@ -1994,7 +1991,7 @@ char* LLPrivateMemoryPoolManager::allocate(LLPrivateMemoryPool* poolp, U32 size) } else { - return (char*)malloc(size) ; + return (char*)ll_aligned_malloc_16(size) ; } } #endif @@ -2019,7 +2016,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 bbbdaa6497..10013e0f92 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -27,7 +27,13 @@ #define LLMEMORY_H #include "llmemtype.h" -#if LL_DEBUG + +#if LL_WINDOWS && LL_DEBUG +#define LL_CHECK_MEMORY llassert(_CrtCheckMemory()); +#else +#define LL_CHECK_MEMORY +#endif + inline void* ll_aligned_malloc( size_t size, int align ) { void* mem = malloc( size + (align - 1) + sizeof(void*) ); @@ -43,10 +49,11 @@ inline void ll_aligned_free( void* ptr ) free( ((void**)ptr)[-1] ); } +#if !LL_USE_TCMALLOC inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed with ll_aligned_free_16(). { #if defined(LL_WINDOWS) - return _mm_malloc(size, 16); + return _aligned_malloc(size, 16); #elif defined(LL_DARWIN) return malloc(size); // default osx malloc is 16 byte aligned. #else @@ -61,7 +68,7 @@ inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed wi inline void ll_aligned_free_16(void *p) { #if defined(LL_WINDOWS) - _mm_free(p); + _aligned_free(p); #elif defined(LL_DARWIN) return free(p); #else @@ -69,10 +76,39 @@ inline void ll_aligned_free_16(void *p) #endif } +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) + return _aligned_realloc(ptr, size, 16); +#elif defined(LL_DARWIN) + return realloc(ptr,size); // default osx malloc is 16 byte aligned. +#else + //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(a,b,c) realloc(a,b) +#define ll_aligned_free_16 free +#endif // USE_TCMALLOC + inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed with ll_aligned_free_32(). { #if defined(LL_WINDOWS) - return _mm_malloc(size, 32); + return _aligned_malloc(size, 32); #elif defined(LL_DARWIN) return ll_aligned_malloc( size, 32 ); #else @@ -87,22 +123,13 @@ inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed wi inline void ll_aligned_free_32(void *p) { #if defined(LL_WINDOWS) - _mm_free(p); + _aligned_free(p); #elif defined(LL_DARWIN) ll_aligned_free( p ); #else free(p); // posix_memalign() is compatible with heap deallocator #endif } -#else // LL_DEBUG -// ll_aligned_foo are noops now that we use tcmalloc everywhere (tcmalloc aligns automatically at appropriate intervals) -#define ll_aligned_malloc( size, align ) malloc(size) -#define ll_aligned_free( ptr ) free(ptr) -#define ll_aligned_malloc_16 malloc -#define ll_aligned_free_16 free -#define ll_aligned_malloc_32 malloc -#define ll_aligned_free_32 free -#endif // LL_DEBUG #ifndef __DEBUG_PRIVATE_MEM__ #define __DEBUG_PRIVATE_MEM__ 0 @@ -512,4 +539,13 @@ void LLPrivateMemoryPoolTester::operator delete[](void* addr) // LLSingleton moved to llsingleton.h +LL_COMMON_API void ll_assert_aligned_func(uintptr_t ptr,U32 alignment); + +#ifdef SHOW_ASSERT +#define ll_assert_aligned(ptr,alignment) ll_assert_aligned_func(reinterpret_cast<uintptr_t>(ptr),((U32)alignment)) +#else +#define ll_assert_aligned(ptr,alignment) +#endif + + #endif diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index affa040602..88c09c8dca 100644 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -140,6 +140,10 @@ public: } protected: +#ifdef LL_LIBRARY_INCLUDE + void ref(); + void unref(); +#else void ref() { if (mPointer) @@ -162,7 +166,7 @@ protected: } } } - +#endif protected: Type* mPointer; }; diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp index 1738c16dea..abf47a0f57 100644 --- a/indra/llcommon/llqueuedthread.cpp +++ b/indra/llcommon/llqueuedthread.cpp @@ -134,8 +134,8 @@ S32 LLQueuedThread::updateQueue(F32 max_time_ms) pending = getPending(); if(pending > 0) { - unpause(); - } + unpause(); + } } else { diff --git a/indra/llcommon/llregistry.h b/indra/llcommon/llregistry.h index 36d7f7a44c..853c427a13 100644 --- a/indra/llcommon/llregistry.h +++ b/indra/llcommon/llregistry.h @@ -31,30 +31,16 @@ #include <boost/type_traits.hpp> #include "llsingleton.h" -#include "lltypeinfolookup.h" +#include "llstl.h" template <typename T> -class LLRegistryDefaultComparator +struct LLRegistryDefaultComparator { - bool operator()(const T& lhs, const T& rhs) { return lhs < rhs; } -}; - -template <typename KEY, typename VALUE> -struct LLRegistryMapSelector -{ - typedef std::map<KEY, VALUE> type; -}; - -template <typename VALUE> -struct LLRegistryMapSelector<std::type_info*, VALUE> -{ - typedef LLTypeInfoLookup<VALUE> type; -}; - -template <typename VALUE> -struct LLRegistryMapSelector<const std::type_info*, VALUE> -{ - typedef LLTypeInfoLookup<VALUE> type; + bool operator()(const T& lhs, const T& rhs) const + { + using std::less; + return less<T>()(lhs, rhs); + } }; template <typename KEY, typename VALUE, typename COMPARATOR = LLRegistryDefaultComparator<KEY> > @@ -72,7 +58,7 @@ public: { friend class LLRegistry<KEY, VALUE, COMPARATOR>; public: - typedef typename LLRegistryMapSelector<KEY, VALUE>::type registry_map_t; + typedef std::map<KEY, VALUE, COMPARATOR> registry_map_t; bool add(ref_const_key_t key, ref_const_value_t value) { diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp index e295e3c621..8276ec836a 100644 --- a/indra/llcommon/llsd.cpp +++ b/indra/llcommon/llsd.cpp @@ -269,6 +269,7 @@ namespace virtual LLSD::UUID asUUID() const { return LLUUID(mValue); } virtual LLSD::Date asDate() const { return LLDate(mValue); } virtual LLSD::URI asURI() const { return LLURI(mValue); } + virtual int size() const { return mValue.size(); } }; LLSD::Integer ImplString::asInteger() const diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index b419101b7e..6b549e4b6f 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -55,6 +55,10 @@ static const char LEGACY_NON_HEADER[] = "<llsd>"; const std::string LLSD_BINARY_HEADER("LLSD/Binary"); const std::string LLSD_XML_HEADER("LLSD/XML"); +//used to deflate a gzipped asset (currently used for navmeshes) +#define windowBits 15 +#define ENABLE_ZLIB_GZIP 32 + /** * LLSDSerialize */ @@ -1447,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'); @@ -2096,7 +2103,7 @@ bool unzip_llsd(LLSD& data, std::istream& is, S32 size) strm.next_in = in; S32 ret = inflateInit(&strm); - + do { strm.avail_out = CHUNK; @@ -2159,12 +2166,87 @@ bool unzip_llsd(LLSD& data, std::istream& is, S32 size) llwarns << "Failed to unzip LLSD block" << llendl; free(result); return false; - } + } } free(result); return true; } +//This unzip function will only work with a gzip header and trailer - while the contents +//of the actual compressed data is the same for either format (gzip vs zlib ), the headers +//and trailers are different for the formats. +U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize, std::istream& is, S32 size ) +{ + U8* result = NULL; + U32 cur_size = 0; + z_stream strm; + + const U32 CHUNK = 0x4000; + + U8 *in = new U8[size]; + is.read((char*) in, size); + + U8 out[CHUNK]; + + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = size; + strm.next_in = in; + + S32 ret = inflateInit2(&strm, windowBits | ENABLE_ZLIB_GZIP ); + do + { + strm.avail_out = CHUNK; + strm.next_out = out; + ret = inflate(&strm, Z_NO_FLUSH); + if (ret == Z_STREAM_ERROR) + { + inflateEnd(&strm); + free(result); + delete [] in; + valid = false; + } + + switch (ret) + { + case Z_NEED_DICT: + ret = Z_DATA_ERROR; + case Z_DATA_ERROR: + case Z_MEM_ERROR: + inflateEnd(&strm); + free(result); + delete [] in; + valid = false; + break; + } + + U32 have = CHUNK-strm.avail_out; + + result = (U8*) realloc(result, cur_size + have); + memcpy(result+cur_size, out, have); + cur_size += have; + + } while (ret == Z_OK); + + inflateEnd(&strm); + delete [] in; + + if (ret != Z_STREAM_END) + { + free(result); + valid = false; + return NULL; + } + + //result now points to the decompressed LLSD block + { + outsize= cur_size; + valid = true; + } + + return result; +} diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h index 99a3ea3cd4..86e3fc864c 100644 --- a/indra/llcommon/llsdserialize.h +++ b/indra/llcommon/llsdserialize.h @@ -793,5 +793,5 @@ public: //dirty little zip functions -- yell at davep LL_COMMON_API std::string zip_llsd(LLSD& data); LL_COMMON_API bool unzip_llsd(LLSD& data, std::istream& is, S32 size); - +LL_COMMON_API U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize,std::istream& is, S32 size); #endif // LL_LLSDSERIALIZE_H diff --git a/indra/llcommon/llstat.cpp b/indra/llcommon/llstat.cpp index 057257057f..b82d52797e 100644 --- a/indra/llcommon/llstat.cpp +++ b/indra/llcommon/llstat.cpp @@ -40,7 +40,6 @@ S32 LLPerfBlock::sStatsFlags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS; // Control what is being recorded LLPerfBlock::stat_map_t LLPerfBlock::sStatMap; // Map full path string to LLStatTime objects, tracks all active objects std::string LLPerfBlock::sCurrentStatPath = ""; // Something like "/total_time/physics/physics step" -LLStat::stat_map_t LLStat::sStatList; //------------------------------------------------------------------------ // Live config file to trigger stats logging @@ -771,13 +770,19 @@ void LLStat::init() if (!mName.empty()) { - stat_map_t::iterator iter = sStatList.find(mName); - if (iter != sStatList.end()) + stat_map_t::iterator iter = getStatList().find(mName); + if (iter != getStatList().end()) llwarns << "LLStat with duplicate name: " << mName << llendl; - sStatList.insert(std::make_pair(mName, this)); + getStatList().insert(std::make_pair(mName, this)); } } +LLStat::stat_map_t& LLStat::getStatList() +{ + static LLStat::stat_map_t stat_list; + return stat_list; +} + LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer) : mUseFrameTimer(use_frame_timer), mNumBins(num_bins) @@ -803,10 +808,10 @@ LLStat::~LLStat() if (!mName.empty()) { // handle multiple entries with the same name - stat_map_t::iterator iter = sStatList.find(mName); - while (iter != sStatList.end() && iter->second != this) + stat_map_t::iterator iter = getStatList().find(mName); + while (iter != getStatList().end() && iter->second != this) ++iter; - sStatList.erase(iter); + getStatList().erase(iter); } } diff --git a/indra/llcommon/llstat.h b/indra/llcommon/llstat.h index b877432e86..1a8404cc07 100644 --- a/indra/llcommon/llstat.h +++ b/indra/llcommon/llstat.h @@ -263,9 +263,9 @@ class LL_COMMON_API LLStat { private: typedef std::multimap<std::string, LLStat*> stat_map_t; - static stat_map_t sStatList; void init(); + static stat_map_t& getStatList(); public: LLStat(U32 num_bins = 32, BOOL use_frame_timer = FALSE); @@ -342,8 +342,8 @@ public: static LLStat* getStat(const std::string& name) { // return the first stat that matches 'name' - stat_map_t::iterator iter = sStatList.find(name); - if (iter != sStatList.end()) + stat_map_t::iterator iter = getStatList().find(name); + if (iter != getStatList().end()) return iter->second; else return NULL; diff --git a/indra/llcommon/llstatenums.h b/indra/llcommon/llstatenums.h index 9033d8eb43..81c4085d16 100644 --- a/indra/llcommon/llstatenums.h +++ b/indra/llcommon/llstatenums.h @@ -28,41 +28,48 @@ enum { - LL_SIM_STAT_TIME_DILATION, // 0 - LL_SIM_STAT_FPS, - LL_SIM_STAT_PHYSFPS, - LL_SIM_STAT_AGENTUPS, - LL_SIM_STAT_FRAMEMS, - LL_SIM_STAT_NETMS, // 5 - LL_SIM_STAT_SIMOTHERMS, - LL_SIM_STAT_SIMPHYSICSMS, - LL_SIM_STAT_AGENTMS, - LL_SIM_STAT_IMAGESMS, - LL_SIM_STAT_SCRIPTMS, // 10 - LL_SIM_STAT_NUMTASKS, - LL_SIM_STAT_NUMTASKSACTIVE, - LL_SIM_STAT_NUMAGENTMAIN, - LL_SIM_STAT_NUMAGENTCHILD, - LL_SIM_STAT_NUMSCRIPTSACTIVE, // 15 - LL_SIM_STAT_LSLIPS, - LL_SIM_STAT_INPPS, - LL_SIM_STAT_OUTPPS, - LL_SIM_STAT_PENDING_DOWNLOADS, - LL_SIM_STAT_PENDING_UPLOADS, // 20 - LL_SIM_STAT_VIRTUAL_SIZE_KB, - LL_SIM_STAT_RESIDENT_SIZE_KB, - LL_SIM_STAT_PENDING_LOCAL_UPLOADS, - LL_SIM_STAT_TOTAL_UNACKED_BYTES, - LL_SIM_STAT_PHYSICS_PINNED_TASKS, // 25 - LL_SIM_STAT_PHYSICS_LOD_TASKS, - LL_SIM_STAT_SIMPHYSICSSTEPMS, - LL_SIM_STAT_SIMPHYSICSSHAPEMS, - LL_SIM_STAT_SIMPHYSICSOTHERMS, - LL_SIM_STAT_SIMPHYSICSMEMORY, // 30 - LL_SIM_STAT_SCRIPT_EPS, - LL_SIM_STAT_SIMSPARETIME, - LL_SIM_STAT_SIMSLEEPTIME, - LL_SIM_STAT_IOPUMPTIME, + LL_SIM_STAT_TIME_DILATION = 0, + LL_SIM_STAT_FPS = 1, + LL_SIM_STAT_PHYSFPS = 2, + LL_SIM_STAT_AGENTUPS = 3, + LL_SIM_STAT_FRAMEMS = 4, + LL_SIM_STAT_NETMS = 5, + LL_SIM_STAT_SIMOTHERMS = 6, + LL_SIM_STAT_SIMPHYSICSMS = 7, + LL_SIM_STAT_AGENTMS = 8, + LL_SIM_STAT_IMAGESMS = 9, + LL_SIM_STAT_SCRIPTMS = 10, + LL_SIM_STAT_NUMTASKS = 11, + LL_SIM_STAT_NUMTASKSACTIVE = 12, + LL_SIM_STAT_NUMAGENTMAIN = 13, + LL_SIM_STAT_NUMAGENTCHILD = 14, + LL_SIM_STAT_NUMSCRIPTSACTIVE = 15, + LL_SIM_STAT_LSLIPS = 16, + LL_SIM_STAT_INPPS = 17, + LL_SIM_STAT_OUTPPS = 18, + LL_SIM_STAT_PENDING_DOWNLOADS = 19, + LL_SIM_STAT_PENDING_UPLOADS = 20, + LL_SIM_STAT_VIRTUAL_SIZE_KB = 21, + LL_SIM_STAT_RESIDENT_SIZE_KB = 22, + LL_SIM_STAT_PENDING_LOCAL_UPLOADS = 23, + LL_SIM_STAT_TOTAL_UNACKED_BYTES = 24, + LL_SIM_STAT_PHYSICS_PINNED_TASKS = 25, + LL_SIM_STAT_PHYSICS_LOD_TASKS = 26, + LL_SIM_STAT_SIMPHYSICSSTEPMS = 27, + LL_SIM_STAT_SIMPHYSICSSHAPEMS = 28, + LL_SIM_STAT_SIMPHYSICSOTHERMS = 29, + LL_SIM_STAT_SIMPHYSICSMEMORY = 30, + LL_SIM_STAT_SCRIPT_EPS = 31, + LL_SIM_STAT_SIMSPARETIME = 32, + LL_SIM_STAT_SIMSLEEPTIME = 33, + LL_SIM_STAT_IOPUMPTIME = 34, + LL_SIM_STAT_PCTSCRIPTSRUN = 35, + LL_SIM_STAT_REGION_IDLE = 36, // dataserver only + LL_SIM_STAT_REGION_IDLE_POSSIBLE = 37, // dataserver only + LL_SIM_STAT_SIMAISTEPTIMEMS = 38, + LL_SIM_STAT_SKIPPEDAISILSTEPS_PS = 39, + LL_SIM_STAT_PCTSTEPPEDCHARACTERS = 40 + }; #endif diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h index 8ad12c9a03..d3941e1bc9 100644 --- a/indra/llcommon/llstl.h +++ b/indra/llcommon/llstl.h @@ -33,6 +33,7 @@ #include <vector> #include <set> #include <deque> +#include <typeinfo> // Use to compare the first element only of a pair // e.g. typedef std::set<std::pair<int, Data*>, compare_pair<int, Data*> > some_pair_set_t; @@ -470,4 +471,54 @@ llbind2nd(const _Operation& __oper, const _Tp& __x) return llbinder2nd<_Operation>(__oper, _Arg2_type(__x)); } +/** + * Compare std::type_info* pointers a la std::less. We break this out as a + * separate function for use in two different std::less specializations. + */ +inline +bool before(const std::type_info* lhs, const std::type_info* rhs) +{ +#if LL_LINUX && defined(__GNUC__) && ((__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 4)) + // If we're building on Linux with gcc, and it's either gcc 3.x or + // 4.{0,1,2,3}, then we have to use a workaround. Note that we use gcc on + // Mac too, and some people build with gcc on Windows (cygwin or mingw). + // On Linux, different load modules may produce different type_info* + // pointers for the same type. Have to compare name strings to get good + // results. + return strcmp(lhs->name(), rhs->name()) < 0; +#else // not Linux, or gcc 4.4+ + // Just use before(), as we normally would + return lhs->before(*rhs); +#endif +} + +/** + * Specialize std::less<std::type_info*> to use std::type_info::before(). + * See MAINT-1175. It is NEVER a good idea to directly compare std::type_info* + * because, on Linux, you might get different std::type_info* pointers for the + * same type (from different load modules)! + */ +namespace std +{ + template <> + struct less<const std::type_info*>: + public std::binary_function<const std::type_info*, const std::type_info*, bool> + { + bool operator()(const std::type_info* lhs, const std::type_info* rhs) const + { + return before(lhs, rhs); + } + }; + + template <> + struct less<std::type_info*>: + public std::binary_function<std::type_info*, std::type_info*, bool> + { + bool operator()(std::type_info* lhs, std::type_info* rhs) const + { + return before(lhs, rhs); + } + }; +} // std + #endif // LL_LLSTL_H diff --git a/indra/llcommon/llstrider.h b/indra/llcommon/llstrider.h index f4c43bac61..ed9284d2c5 100644 --- a/indra/llcommon/llstrider.h +++ b/indra/llcommon/llstrider.h @@ -44,6 +44,15 @@ public: const LLStrider<Object>& operator = (Object *first) { mObjectp = first; return *this;} void setStride (S32 skipBytes) { mSkip = (skipBytes ? skipBytes : sizeof(Object));} + LLStrider<Object> operator+(const S32& index) + { + LLStrider<Object> ret; + ret.mBytep = mBytep + mSkip*index; + ret.mSkip = mSkip; + + return ret; + } + void skip(const U32 index) { mBytep += mSkip*index;} U32 getSkip() const { return mSkip; } Object* get() { return mObjectp; } @@ -51,6 +60,7 @@ public: Object& operator *() { return *mObjectp; } Object* operator ++(int) { Object* old = mObjectp; mBytep += mSkip; return old; } Object* operator +=(int i) { mBytep += mSkip*i; return mObjectp; } + Object& operator[](U32 index) { return *(Object*)(mBytep + (mSkip * index)); } }; diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index fa0eb9f72c..0c32679744 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -47,7 +47,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/llstring.h b/indra/llcommon/llstring.h index 09733e8e2a..119efc7957 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -183,6 +183,9 @@ public: static bool isPunct(char a) { return ispunct((unsigned char)a) != 0; } static bool isPunct(llwchar a) { return iswpunct(a) != 0; } + static bool isAlpha(char a) { return isalpha((unsigned char)a) != 0; } + static bool isAlpha(llwchar a) { return iswalpha(a) != 0; } + static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; } static bool isAlnum(llwchar a) { return iswalnum(a) != 0; } diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 6073bcd0a6..c96f2191f3 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -944,13 +944,15 @@ LLSD LLMemoryInfo::loadStatsMap() state.dwLength = sizeof(state); GlobalMemoryStatusEx(&state); - stats.add("Percent Memory use", state.dwMemoryLoad); - stats.add("Total Physical KB", state.ullTotalPhys/1024); - stats.add("Avail Physical KB", state.ullAvailPhys/1024); - stats.add("Total page KB", state.ullTotalPageFile/1024); - stats.add("Avail page KB", state.ullAvailPageFile/1024); - stats.add("Total Virtual KB", state.ullTotalVirtual/1024); - stats.add("Avail Virtual KB", state.ullAvailVirtual/1024); + DWORDLONG div = 1024; + + stats.add("Percent Memory use", state.dwMemoryLoad/div); + stats.add("Total Physical KB", state.ullTotalPhys/div); + stats.add("Avail Physical KB", state.ullAvailPhys/div); + stats.add("Total page KB", state.ullTotalPageFile/div); + stats.add("Avail page KB", state.ullAvailPageFile/div); + stats.add("Total Virtual KB", state.ullTotalVirtual/div); + stats.add("Avail Virtual KB", state.ullAvailVirtual/div); PERFORMANCE_INFORMATION perf; perf.cb = sizeof(perf); @@ -982,15 +984,15 @@ LLSD LLMemoryInfo::loadStatsMap() GetProcessMemoryInfo(GetCurrentProcess(), PPROCESS_MEMORY_COUNTERS(&pmem), sizeof(pmem)); stats.add("Page Fault Count", pmem.PageFaultCount); - stats.add("PeakWorkingSetSize KB", pmem.PeakWorkingSetSize/1024); - stats.add("WorkingSetSize KB", pmem.WorkingSetSize/1024); - stats.add("QutaPeakPagedPoolUsage KB", pmem.QuotaPeakPagedPoolUsage/1024); - stats.add("QuotaPagedPoolUsage KB", pmem.QuotaPagedPoolUsage/1024); - stats.add("QuotaPeakNonPagedPoolUsage KB", pmem.QuotaPeakNonPagedPoolUsage/1024); - stats.add("QuotaNonPagedPoolUsage KB", pmem.QuotaNonPagedPoolUsage/1024); - stats.add("PagefileUsage KB", pmem.PagefileUsage/1024); - stats.add("PeakPagefileUsage KB", pmem.PeakPagefileUsage/1024); - stats.add("PrivateUsage KB", pmem.PrivateUsage/1024); + stats.add("PeakWorkingSetSize KB", pmem.PeakWorkingSetSize/div); + stats.add("WorkingSetSize KB", pmem.WorkingSetSize/div); + stats.add("QutaPeakPagedPoolUsage KB", pmem.QuotaPeakPagedPoolUsage/div); + stats.add("QuotaPagedPoolUsage KB", pmem.QuotaPagedPoolUsage/div); + stats.add("QuotaPeakNonPagedPoolUsage KB", pmem.QuotaPeakNonPagedPoolUsage/div); + stats.add("QuotaNonPagedPoolUsage KB", pmem.QuotaNonPagedPoolUsage/div); + stats.add("PagefileUsage KB", pmem.PagefileUsage/div); + stats.add("PeakPagefileUsage KB", pmem.PeakPagefileUsage/div); + stats.add("PrivateUsage KB", pmem.PrivateUsage/div); #elif LL_DARWIN diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index a6ad6b125c..1d56a52c32 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -71,6 +71,13 @@ LL_COMMON_API void assert_main_thread() } } +void LLThread::registerThreadID() +{ +#if !LL_DARWIN + sThreadID = ++sIDIter; +#endif +} + // // Handed to the APR thread creation function // @@ -114,7 +121,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 ; } @@ -173,7 +180,10 @@ void LLThread::shutdown() } delete mRunCondition; - mRunCondition = 0; + mRunCondition = NULL; + + delete mDataLock; + mDataLock = NULL; if (mIsLocalPool && mAPRPoolp) { @@ -242,28 +252,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(); } @@ -285,12 +297,12 @@ void LLThread::yield() void LLThread::wake() { - mRunCondition->lock(); + mDataLock->lock(); if(!shouldSleep()) { mRunCondition->signal(); } - mRunCondition->unlock(); + mDataLock->unlock(); } void LLThread::wakeLocked() @@ -481,6 +493,19 @@ LLThreadSafeRefCount::LLThreadSafeRefCount() : { } +LLThreadSafeRefCount::LLThreadSafeRefCount(const LLThreadSafeRefCount& src) +{ + if (sMutex) + { + sMutex->lock(); + } + mRef = 0; + if (sMutex) + { + sMutex->unlock(); + } +} + LLThreadSafeRefCount::~LLThreadSafeRefCount() { if (mRef != 0) @@ -489,6 +514,7 @@ LLThreadSafeRefCount::~LLThreadSafeRefCount() } } + //============================================================================ LLResponder::~LLResponder() diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index b52e70ab2e..5c8bbca2ca 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -88,6 +88,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; @@ -97,6 +102,7 @@ private: protected: std::string mName; LLCondition* mRunCondition; + LLMutex* mDataLock; apr_thread_t *mAPRThreadp; apr_pool_t *mAPRPoolp; @@ -122,15 +128,15 @@ 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(); }; //============================================================================ @@ -205,12 +211,12 @@ private: void LLThread::lockData() { - mRunCondition->lock(); + mDataLock->lock(); } void LLThread::unlockData() { - mRunCondition->unlock(); + mDataLock->unlock(); } @@ -227,15 +233,27 @@ public: private: static LLMutex* sMutex; -private: - LLThreadSafeRefCount(const LLThreadSafeRefCount&); // not implemented - LLThreadSafeRefCount&operator=(const LLThreadSafeRefCount&); // not implemented - 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() { diff --git a/indra/llcommon/lltypeinfolookup.h b/indra/llcommon/lltypeinfolookup.h index 7510cc12ed..0b6862444e 100644 --- a/indra/llcommon/lltypeinfolookup.h +++ b/indra/llcommon/lltypeinfolookup.h @@ -12,10 +12,50 @@ #if ! defined(LL_LLTYPEINFOLOOKUP_H) #define LL_LLTYPEINFOLOOKUP_H -#include "llsortedvector.h" +#include <boost/unordered_map.hpp> +#include <boost/functional/hash.hpp> +#include <boost/optional.hpp> +#include <functional> // std::binary_function #include <typeinfo> /** + * The following helper classes are based on the Boost.Unordered documentation: + * http://www.boost.org/doc/libs/1_45_0/doc/html/unordered/hash_equality.html + */ + +/** + * Compute hash for a string passed as const char* + */ +struct const_char_star_hash: public std::unary_function<const char*, std::size_t> +{ + std::size_t operator()(const char* str) const + { + std::size_t seed = 0; + for ( ; *str; ++str) + { + boost::hash_combine(seed, *str); + } + return seed; + } +}; + +/** + * Compute equality for strings passed as const char* + * + * I (nat) suspect that this is where the default behavior breaks for the + * const char* values returned from std::type_info::name(). If you compare the + * two const char* pointer values, as a naive, unspecialized implementation + * will surely do, they'll compare unequal. + */ +struct const_char_star_equal: public std::binary_function<const char*, const char*, bool> +{ + bool operator()(const char* lhs, const char* rhs) const + { + return strcmp(lhs, rhs) == 0; + } +}; + +/** * LLTypeInfoLookup is specifically designed for use cases for which you might * consider std::map<std::type_info*, VALUE>. We have several such data * structures in the viewer. The trouble with them is that at least on Linux, @@ -23,88 +63,55 @@ * different load modules will produce different std::type_info*. * LLTypeInfoLookup contains a workaround to address this issue. * - * Specifically, when we don't find the passed std::type_info*, - * LLTypeInfoLookup performs a linear search over registered entries to - * compare name() strings. Presuming that this succeeds, we cache the new - * (previously unrecognized) std::type_info* to speed future lookups. - * - * This worst-case fallback search (linear search with string comparison) - * should only happen the first time we look up a given type from a particular - * load module other than the one from which we initially registered types. - * (However, a lookup which wouldn't succeed anyway will always have - * worst-case performance.) This class is probably best used with less than a - * few dozen different types. + * The API deliberately diverges from std::map in several respects: + * * It avoids iterators, not only begin()/end() but also as return values + * from insert() and find(). This bypasses transform_iterator overhead. + * * Since we literally use compile-time types as keys, the essential insert() + * and find() methods accept the key type as a @em template parameter, + * accepting and returning value_type as a normal runtime value. This is to + * permit future optimization (e.g. compile-time type hashing) without + * changing the API. */ template <typename VALUE> class LLTypeInfoLookup { + // Use this for our underlying implementation: lookup by + // std::type_info::name() string. This is one of the rare cases in which I + // dare use const char* directly, rather than std::string, because I'm + // sure that every value returned by std::type_info::name() is static. + // HOWEVER, specify our own hash + equality functors: naively comparing + // distinct const char* values won't work. + typedef boost::unordered_map<const char*, VALUE, + const_char_star_hash, const_char_star_equal> impl_map_type; + public: - typedef LLTypeInfoLookup<VALUE> self; - typedef LLSortedVector<const std::type_info*, VALUE> vector_type; - typedef typename vector_type::key_type key_type; - typedef typename vector_type::mapped_type mapped_type; - typedef typename vector_type::value_type value_type; - typedef typename vector_type::iterator iterator; - typedef typename vector_type::const_iterator const_iterator; + typedef VALUE value_type; LLTypeInfoLookup() {} - iterator begin() { return mVector.begin(); } - iterator end() { return mVector.end(); } - const_iterator begin() const { return mVector.begin(); } - const_iterator end() const { return mVector.end(); } - bool empty() const { return mVector.empty(); } - std::size_t size() const { return mVector.size(); } - - std::pair<iterator, bool> insert(const std::type_info* key, const VALUE& value) - { - return insert(value_type(key, value)); - } - - std::pair<iterator, bool> insert(const value_type& pair) - { - return mVector.insert(pair); - } + bool empty() const { return mMap.empty(); } + std::size_t size() const { return mMap.size(); } - // const find() forwards to non-const find(): this can alter mVector! - const_iterator find(const std::type_info* key) const + template <typename KEY> + bool insert(const value_type& value) { - return const_cast<self*>(this)->find(key); + // Obtain and store the std::type_info::name() string as the key. + // Return just the bool from std::map::insert()'s return pair. + return mMap.insert(typename impl_map_type::value_type(typeid(KEY).name(), value)).second; } - // non-const find() caches previously-unknown type_info* to speed future - // lookups. - iterator find(const std::type_info* key) + template <typename KEY> + boost::optional<value_type> find() const { - iterator found = mVector.find(key); - if (found != mVector.end()) - { - // If LLSortedVector::find() found, great, we're done. - return found; - } - // Here we didn't find the passed type_info*. On Linux, though, even - // for the same type, typeid(sametype) produces a different type_info* - // when used in different load modules. So the fact that we didn't - // find the type_info* we seek doesn't mean this type isn't - // registered. Scan for matching name() string. - for (typename vector_type::iterator ti(mVector.begin()), tend(mVector.end()); - ti != tend; ++ti) - { - if (std::string(ti->first->name()) == key->name()) - { - // This unrecognized 'key' is for the same type as ti->first. - // To speed future lookups, insert a new entry that lets us - // look up ti->second using this same 'key'. - return insert(key, ti->second).first; - } - } - // We simply have never seen a type with this type_info* from any load - // module. - return mVector.end(); + // Use the std::type_info::name() string as the key. + typename impl_map_type::const_iterator found = mMap.find(typeid(KEY).name()); + if (found == mMap.end()) + return boost::optional<value_type>(); + return found->second; } private: - vector_type mVector; + impl_map_type mMap; }; #endif /* ! defined(LL_LLTYPEINFOLOOKUP_H) */ 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/lluuid.cpp b/indra/llcommon/lluuid.cpp index 5d452ac4e4..db8c9c85ab 100644 --- a/indra/llcommon/lluuid.cpp +++ b/indra/llcommon/lluuid.cpp @@ -922,3 +922,174 @@ LLAssetID LLTransactionID::makeAssetID(const LLUUID& session) const } return result; } + +// Construct +LLUUID::LLUUID() +{ + setNull(); +} + + +// Faster than copying from memory + void LLUUID::setNull() +{ + U32 *word = (U32 *)mData; + word[0] = 0; + word[1] = 0; + word[2] = 0; + word[3] = 0; +} + + +// Compare + bool LLUUID::operator==(const LLUUID& rhs) const +{ + U32 *tmp = (U32 *)mData; + U32 *rhstmp = (U32 *)rhs.mData; + // Note: binary & to avoid branching + return + (tmp[0] == rhstmp[0]) & + (tmp[1] == rhstmp[1]) & + (tmp[2] == rhstmp[2]) & + (tmp[3] == rhstmp[3]); +} + + + bool LLUUID::operator!=(const LLUUID& rhs) const +{ + U32 *tmp = (U32 *)mData; + U32 *rhstmp = (U32 *)rhs.mData; + // Note: binary | to avoid branching + return + (tmp[0] != rhstmp[0]) | + (tmp[1] != rhstmp[1]) | + (tmp[2] != rhstmp[2]) | + (tmp[3] != rhstmp[3]); +} + +/* +// JC: This is dangerous. It allows UUIDs to be cast automatically +// to integers, among other things. Use isNull() or notNull(). + LLUUID::operator bool() const +{ + U32 *word = (U32 *)mData; + return (word[0] | word[1] | word[2] | word[3]) > 0; +} +*/ + + BOOL LLUUID::notNull() const +{ + U32 *word = (U32 *)mData; + return (word[0] | word[1] | word[2] | word[3]) > 0; +} + +// Faster than == LLUUID::null because doesn't require +// as much memory access. + BOOL LLUUID::isNull() const +{ + U32 *word = (U32 *)mData; + // If all bits are zero, return !0 == TRUE + return !(word[0] | word[1] | word[2] | word[3]); +} + +// Copy constructor + LLUUID::LLUUID(const LLUUID& rhs) +{ + U32 *tmp = (U32 *)mData; + U32 *rhstmp = (U32 *)rhs.mData; + tmp[0] = rhstmp[0]; + tmp[1] = rhstmp[1]; + tmp[2] = rhstmp[2]; + tmp[3] = rhstmp[3]; +} + + LLUUID::~LLUUID() +{ +} + +// Assignment + LLUUID& LLUUID::operator=(const LLUUID& rhs) +{ + // No need to check the case where this==&rhs. The branch is slower than the write. + U32 *tmp = (U32 *)mData; + U32 *rhstmp = (U32 *)rhs.mData; + tmp[0] = rhstmp[0]; + tmp[1] = rhstmp[1]; + tmp[2] = rhstmp[2]; + tmp[3] = rhstmp[3]; + + return *this; +} + + + LLUUID::LLUUID(const char *in_string) +{ + if (!in_string || in_string[0] == 0) + { + setNull(); + return; + } + + set(in_string); +} + + LLUUID::LLUUID(const std::string& in_string) +{ + if (in_string.empty()) + { + setNull(); + return; + } + + set(in_string); +} + +// IW: DON'T "optimize" these w/ U32s or you'll scoogie the sort order +// IW: this will make me very sad + bool LLUUID::operator<(const LLUUID &rhs) const +{ + U32 i; + for( i = 0; i < (UUID_BYTES - 1); i++ ) + { + if( mData[i] != rhs.mData[i] ) + { + return (mData[i] < rhs.mData[i]); + } + } + return (mData[UUID_BYTES - 1] < rhs.mData[UUID_BYTES - 1]); +} + + bool LLUUID::operator>(const LLUUID &rhs) const +{ + U32 i; + for( i = 0; i < (UUID_BYTES - 1); i++ ) + { + if( mData[i] != rhs.mData[i] ) + { + return (mData[i] > rhs.mData[i]); + } + } + return (mData[UUID_BYTES - 1] > rhs.mData[UUID_BYTES - 1]); +} + + U16 LLUUID::getCRC16() const +{ + // A UUID is 16 bytes, or 8 shorts. + U16 *short_data = (U16*)mData; + U16 out = 0; + out += short_data[0]; + out += short_data[1]; + out += short_data[2]; + out += short_data[3]; + out += short_data[4]; + out += short_data[5]; + out += short_data[6]; + out += short_data[7]; + return out; +} + + U32 LLUUID::getCRC32() const +{ + U32 *tmp = (U32*)mData; + return tmp[0] + tmp[1] + tmp[2] + tmp[3]; +} diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h index 726be4a82d..0b9e7d0cd0 100644 --- a/indra/llcommon/lluuid.h +++ b/indra/llcommon/lluuid.h @@ -129,177 +129,6 @@ public: typedef std::vector<LLUUID> uuid_vec_t; -// Construct -inline LLUUID::LLUUID() -{ - setNull(); -} - - -// Faster than copying from memory -inline void LLUUID::setNull() -{ - U32 *word = (U32 *)mData; - word[0] = 0; - word[1] = 0; - word[2] = 0; - word[3] = 0; -} - - -// Compare -inline bool LLUUID::operator==(const LLUUID& rhs) const -{ - U32 *tmp = (U32 *)mData; - U32 *rhstmp = (U32 *)rhs.mData; - // Note: binary & to avoid branching - return - (tmp[0] == rhstmp[0]) & - (tmp[1] == rhstmp[1]) & - (tmp[2] == rhstmp[2]) & - (tmp[3] == rhstmp[3]); -} - - -inline bool LLUUID::operator!=(const LLUUID& rhs) const -{ - U32 *tmp = (U32 *)mData; - U32 *rhstmp = (U32 *)rhs.mData; - // Note: binary | to avoid branching - return - (tmp[0] != rhstmp[0]) | - (tmp[1] != rhstmp[1]) | - (tmp[2] != rhstmp[2]) | - (tmp[3] != rhstmp[3]); -} - -/* -// JC: This is dangerous. It allows UUIDs to be cast automatically -// to integers, among other things. Use isNull() or notNull(). -inline LLUUID::operator bool() const -{ - U32 *word = (U32 *)mData; - return (word[0] | word[1] | word[2] | word[3]) > 0; -} -*/ - -inline BOOL LLUUID::notNull() const -{ - U32 *word = (U32 *)mData; - return (word[0] | word[1] | word[2] | word[3]) > 0; -} - -// Faster than == LLUUID::null because doesn't require -// as much memory access. -inline BOOL LLUUID::isNull() const -{ - U32 *word = (U32 *)mData; - // If all bits are zero, return !0 == TRUE - return !(word[0] | word[1] | word[2] | word[3]); -} - -// Copy constructor -inline LLUUID::LLUUID(const LLUUID& rhs) -{ - U32 *tmp = (U32 *)mData; - U32 *rhstmp = (U32 *)rhs.mData; - tmp[0] = rhstmp[0]; - tmp[1] = rhstmp[1]; - tmp[2] = rhstmp[2]; - tmp[3] = rhstmp[3]; -} - -inline LLUUID::~LLUUID() -{ -} - -// Assignment -inline LLUUID& LLUUID::operator=(const LLUUID& rhs) -{ - // No need to check the case where this==&rhs. The branch is slower than the write. - U32 *tmp = (U32 *)mData; - U32 *rhstmp = (U32 *)rhs.mData; - tmp[0] = rhstmp[0]; - tmp[1] = rhstmp[1]; - tmp[2] = rhstmp[2]; - tmp[3] = rhstmp[3]; - - return *this; -} - - -inline LLUUID::LLUUID(const char *in_string) -{ - if (!in_string || in_string[0] == 0) - { - setNull(); - return; - } - - set(in_string); -} - -inline LLUUID::LLUUID(const std::string& in_string) -{ - if (in_string.empty()) - { - setNull(); - return; - } - - set(in_string); -} - -// IW: DON'T "optimize" these w/ U32s or you'll scoogie the sort order -// IW: this will make me very sad -inline bool LLUUID::operator<(const LLUUID &rhs) const -{ - U32 i; - for( i = 0; i < (UUID_BYTES - 1); i++ ) - { - if( mData[i] != rhs.mData[i] ) - { - return (mData[i] < rhs.mData[i]); - } - } - return (mData[UUID_BYTES - 1] < rhs.mData[UUID_BYTES - 1]); -} - -inline bool LLUUID::operator>(const LLUUID &rhs) const -{ - U32 i; - for( i = 0; i < (UUID_BYTES - 1); i++ ) - { - if( mData[i] != rhs.mData[i] ) - { - return (mData[i] > rhs.mData[i]); - } - } - return (mData[UUID_BYTES - 1] > rhs.mData[UUID_BYTES - 1]); -} - -inline U16 LLUUID::getCRC16() const -{ - // A UUID is 16 bytes, or 8 shorts. - U16 *short_data = (U16*)mData; - U16 out = 0; - out += short_data[0]; - out += short_data[1]; - out += short_data[2]; - out += short_data[3]; - out += short_data[4]; - out += short_data[5]; - out += short_data[6]; - out += short_data[7]; - return out; -} - -inline U32 LLUUID::getCRC32() const -{ - U32 *tmp = (U32*)mData; - return tmp[0] + tmp[1] + tmp[2] + tmp[3]; -} - // Helper structure for ordering lluuids in stl containers. // eg: std::map<LLUUID, LLWidget*, lluuid_less> widget_map; @@ -329,3 +158,5 @@ public: }; #endif + + diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h index bfb30f900f..8585af0a29 100644 --- a/indra/llcommon/llversionviewer.h +++ b/indra/llcommon/llversionviewer.h @@ -28,8 +28,8 @@ #define LL_LLVERSIONVIEWER_H const S32 LL_VERSION_MAJOR = 3; -const S32 LL_VERSION_MINOR = 3; -const S32 LL_VERSION_PATCH = 3; +const S32 LL_VERSION_MINOR = 4; +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(...) { |