diff options
Diffstat (limited to 'indra/llcommon')
55 files changed, 4579 insertions, 1275 deletions
| diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index beac8df636..bf46c2c038 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -3,7 +3,9 @@  project(llcommon)  include(00-Common) +include(LLAddBuildTest)  include(LLCommon) +include(Boost)  include_directories(      ${EXPAT_INCLUDE_DIRS} @@ -11,7 +13,14 @@ include_directories(      ${ZLIB_INCLUDE_DIRS}      ) +# add_executable(lltreeiterators lltreeiterators.cpp) +#  +# target_link_libraries(lltreeiterators +#     ${LLCOMMON_LIBRARIES}) +  set(llcommon_SOURCE_FILES +    llallocator.cpp +    llallocator_heap_profile.cpp      llapp.cpp      llapr.cpp      llassettype.cpp @@ -40,11 +49,14 @@ set(llcommon_SOURCE_FILES      llmd5.cpp      llmemory.cpp      llmemorystream.cpp +    llmemtype.cpp      llmetrics.cpp      llmortician.cpp +    llptrto.cpp       llprocessor.cpp      llqueuedthread.cpp      llrand.cpp +    llrefcount.cpp      llrun.cpp      llsd.cpp      llsdserialize.cpp @@ -52,6 +64,7 @@ set(llcommon_SOURCE_FILES      llsdutil.cpp      llsecondlifeurls.cpp      llstat.cpp +    llstacktrace.cpp      llstreamtools.cpp      llstring.cpp      llstringtable.cpp @@ -78,6 +91,8 @@ set(llcommon_HEADER_FILES      indra_constants.h      linden_common.h      linked_lists.h +    llallocator.h +    llallocator_heap_profile.h      llagentconstants.h      llapp.h      llapr.h @@ -98,8 +113,11 @@ set(llcommon_HEADER_FILES      lldate.h      lldefs.h      lldependencies.h +    lldeleteutils.h      lldepthstack.h +    lldictionary.h      lldlinked.h +    lldoubledispatch.h      lldqueueptr.h      llendianswizzle.h      llenum.h @@ -121,6 +139,7 @@ set(llcommon_HEADER_FILES      llheartbeat.h      llhttpstatuscodes.h      llindexedqueue.h +    llinstancetracker.h      llkeythrottle.h      lllazy.h      lllinkedqueue.h @@ -137,23 +156,30 @@ set(llcommon_HEADER_FILES      llmetrics.h      llmortician.h      llnametable.h +    llpointer.h      llpreprocessor.h      llpriqueuemap.h      llprocessor.h      llptrskiplist.h      llptrskipmap.h +    llptrto.h      llqueuedthread.h      llrand.h +    llrefcount.h      llrun.h +    llrefcount.h +    llsafehandle.h      llsd.h      llsdserialize.h      llsdserialize_xml.h      llsdutil.h      llsecondlifeurls.h      llsimplehash.h +    llsingleton.h      llskiplist.h      llskipmap.h      llstack.h +    llstacktrace.h      llstat.h      llstatenums.h      llstl.h @@ -164,6 +190,7 @@ set(llcommon_HEADER_FILES      llsys.h      llthread.h      lltimer.h +    lltreeiterators.h      lluri.h      lluuid.h      lluuidhashmap.h @@ -199,6 +226,8 @@ target_link_libraries(      ${APR_LIBRARIES}      ${EXPAT_LIBRARIES}      ${ZLIB_LIBRARIES} +    ${BOOST_PROGRAM_OPTIONS_LIBRARY} +    ${BOOST_REGEX_LIBRARY}      )  include(LLAddBuildTest) @@ -208,3 +237,8 @@ SET(llcommon_TEST_SOURCE_FILES    )  LL_ADD_PROJECT_UNIT_TESTS(llcommon "${llcommon_TEST_SOURCE_FILES}") +# *TODO - reenable these once tcmalloc libs no longer break the build. +#ADD_BUILD_TEST(llallocator llcommon) +#ADD_BUILD_TEST(llallocator_heap_profile llcommon) +#ADD_BUILD_TEST(llmemtype llcommon) + diff --git a/indra/llcommon/is_approx_equal_fraction.h b/indra/llcommon/is_approx_equal_fraction.h index f95b148590..d369fbc5b3 100644 --- a/indra/llcommon/is_approx_equal_fraction.h +++ b/indra/llcommon/is_approx_equal_fraction.h @@ -7,7 +7,30 @@   *         making llcommon depend on llmath.   *    * $LicenseInfo:firstyear=2009&license=viewergpl$ + *    * Copyright (c) 2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE.   * $/LicenseInfo$   */ diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h index f9d5877ab2..9adf24a492 100644 --- a/indra/llcommon/linden_common.h +++ b/indra/llcommon/linden_common.h @@ -33,6 +33,11 @@  #ifndef LL_LINDEN_COMMON_H  #define LL_LINDEN_COMMON_H +// *NOTE:  Please keep includes here to a minimum! +// +// Files included here are included in every library .cpp file and +// are not precompiled. +  #if defined(LL_WINDOWS) && defined(_DEBUG)  # if _MSC_VER >= 1400 // Visual C++ 2005 or later  #  define _CRTDBG_MAP_ALLOC @@ -51,23 +56,22 @@  #include <cstdio>  #include <cstdlib>  #include <ctime> -#include <iostream> -#include <fstream> +#include <iosfwd> -// Work Microsoft compiler warnings +// Work around Microsoft compiler warnings in STL headers  #ifdef LL_WINDOWS  #pragma warning (disable : 4702) // unreachable code  #pragma warning (disable : 4244) // conversion from time_t to S32  #endif	//	LL_WINDOWS -#include <algorithm>  #include <list>  #include <map>  #include <vector>  #include <string>  #ifdef LL_WINDOWS -#pragma warning (3 : 4702) // we like level 3, not 4 +// Reenable warnings we disabled above +#pragma warning (3 : 4702) // unreachable code, we like level 3, not 4  // level 4 warnings that we need to disable:  #pragma warning (disable : 4100) // unreferenced formal parameter  #pragma warning (disable : 4127) // conditional expression is constant (e.g. while(1) ) @@ -78,6 +82,7 @@  #endif	//	LL_WINDOWS  // Linden only libs in alpha-order other than stdtypes.h +// *NOTE: Please keep includes here to a minimum, see above.  #include "stdtypes.h"  #include "lldefs.h"  #include "llerror.h" @@ -85,8 +90,5 @@  #include "llfasttimer.h"  #include "llfile.h"  #include "llformat.h" -#include "llstring.h" -#include "llsys.h" -#include "lltimer.h"  #endif diff --git a/indra/llcommon/llallocator.cpp b/indra/llcommon/llallocator.cpp new file mode 100644 index 0000000000..eed9d1e7db --- /dev/null +++ b/indra/llcommon/llallocator.cpp @@ -0,0 +1,140 @@ +/**  + * @file llallocator.cpp + * @brief Implementation of the LLAllocator class. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + *  + * Copyright (c) 2009-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llallocator.h" + +#if LL_USE_TCMALLOC + +#include "google/heap-profiler.h" +#include "google/commandlineflags_public.h" + +DECLARE_bool(heap_profile_use_stack_trace); +//DECLARE_double(tcmalloc_release_rate); + +// static +void LLAllocator::pushMemType(S32 type) +{ +    if(isProfiling()) +    { +    	PushMemType(type); +    } +} + +// static +S32 LLAllocator::popMemType() +{ +    if (isProfiling()) +    { +    	return PopMemType(); +    } +    else +    { +        return -1; +    } +} + +void LLAllocator::setProfilingEnabled(bool should_enable) +{ +    // NULL disables dumping to disk +    static char const * const PREFIX = NULL; +    if(should_enable) +    { +		HeapProfilerSetUseStackTrace(false); +        HeapProfilerStart(PREFIX); +    } +    else +    { +        HeapProfilerStop(); +    } +} + +// static +bool LLAllocator::isProfiling() +{ +    return IsHeapProfilerRunning(); +} + +std::string LLAllocator::getRawProfile() +{ +    // *TODO - fix google-perftools to accept an buffer to avoid this +    // malloc-copy-free cycle. +    char * buffer = GetHeapProfile(); +    std::string ret = buffer; +    free(buffer); +    return ret; +} + +#else // LL_USE_TCMALLOC + +// +// stub implementations for when tcmalloc is disabled +// + +// static +void LLAllocator::pushMemType(S32 type) +{ +} + +// static +S32 LLAllocator::popMemType() +{ +    return -1; +} + +void LLAllocator::setProfilingEnabled(bool should_enable) +{ +} + +// static +bool LLAllocator::isProfiling() +{ +    return false; +} + +std::string LLAllocator::getRawProfile() +{ +    return std::string(); +} + +#endif // LL_USE_TCMALLOC + +LLAllocatorHeapProfile const & LLAllocator::getProfile() +{ +    mProf.mLines.clear(); + +    // *TODO - avoid making all these extra copies of things... +    std::string prof_text = getRawProfile(); +    //std::cout << prof_text << std::endl; +    mProf.parse(prof_text); +    return mProf; +} diff --git a/indra/llcommon/llallocator.h b/indra/llcommon/llallocator.h new file mode 100644 index 0000000000..2b70fee0b8 --- /dev/null +++ b/indra/llcommon/llallocator.h @@ -0,0 +1,63 @@ +/**  + * @file llallocator.h + * @brief Declaration of the LLAllocator class. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + *  + * Copyright (c) 2009-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLALLOCATOR_H +#define LL_LLALLOCATOR_H + +#include <string> + +#include "llmemtype.h" +#include "llallocator_heap_profile.h" + +class LLAllocator { +    friend class LLMemoryView; +    friend class LLMemType; + +private: +	static void pushMemType(S32 type); +	static S32 popMemType(); + +public: +    void setProfilingEnabled(bool should_enable); + +    static bool isProfiling(); + +    LLAllocatorHeapProfile const & getProfile(); + +private: +    std::string getRawProfile(); + +private: +    LLAllocatorHeapProfile mProf; +}; + +#endif // LL_LLALLOCATOR_H diff --git a/indra/llcommon/llallocator_heap_profile.cpp b/indra/llcommon/llallocator_heap_profile.cpp new file mode 100644 index 0000000000..d82ee9ed81 --- /dev/null +++ b/indra/llcommon/llallocator_heap_profile.cpp @@ -0,0 +1,149 @@ +/**  + * @file llallocator_heap_profile.cpp + * @brief Implementation of the parser for tcmalloc heap profile data. + * @author Brad Kittenbrink + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + *  + * Copyright (c) 2009-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llallocator_heap_profile.h" + +#if LL_MSVC +// disable warning about boost::lexical_cast returning uninitialized data +// when it fails to parse the string +#pragma warning (disable:4701) +#endif + +#include <boost/algorithm/string/split.hpp> +#include <boost/bind.hpp> +#include <boost/lexical_cast.hpp> +#include <boost/range/iterator_range.hpp> + +static const std::string HEAP_PROFILE_MAGIC_STR = "heap profile:"; + +static bool is_separator(char c) +{ +    return isspace(c) || c == '[' || c == ']' || c == ':'; +} + +void LLAllocatorHeapProfile::parse(std::string const & prof_text) +{ +    // a typedef for handling a token in the string buffer +    // it's a begin/end pair of string::const_iterators +    typedef boost::iterator_range<std::string::const_iterator> range_t; + +    mLines.clear(); + +    if(prof_text.compare(0, HEAP_PROFILE_MAGIC_STR.length(), HEAP_PROFILE_MAGIC_STR) != 0) +    { +        // *TODO - determine if there should be some better error state than +        // mLines being empty. -brad +        llwarns << "invalid heap profile data passed into parser." << llendl; +        return; +    } + +    std::vector< range_t > prof_lines; + +    std::string::const_iterator prof_begin = prof_text.begin() + HEAP_PROFILE_MAGIC_STR.length(); + +	range_t prof_range(prof_begin, prof_text.end()); +    boost::algorithm::split(prof_lines, +        prof_range, +        boost::bind(std::equal_to<llwchar>(), '\n', _1)); + +    std::vector< range_t >::const_iterator i; +    for(i = prof_lines.begin(); i != prof_lines.end() && !i->empty(); ++i) +    { +        range_t const & line_text = *i; + +        std::vector<range_t> line_elems; + +        boost::algorithm::split(line_elems, +            line_text, +            is_separator); + +        std::vector< range_t >::iterator j; +        j = line_elems.begin(); + +        while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens +        llassert_always(j != line_elems.end()); +        U32 live_count = boost::lexical_cast<U32>(*j); +        ++j; + +        while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens +        llassert_always(j != line_elems.end()); +        U64 live_size = boost::lexical_cast<U64>(*j); +        ++j; + +        while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens +        llassert_always(j != line_elems.end()); +        U32 tot_count = boost::lexical_cast<U32>(*j); +        ++j; + +        while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens +        llassert_always(j != line_elems.end()); +        U64 tot_size = boost::lexical_cast<U64>(*j); +        ++j; + +        while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens +        llassert_always(j != line_elems.end()); +        ++j; // skip the '@' + +        mLines.push_back(line(live_count, live_size, tot_count, tot_size)); +        line & current_line = mLines.back(); + +        for(; j != line_elems.end(); ++j) +        { +            if(!j->empty()) { +                U32 marker = boost::lexical_cast<U32>(*j); +                current_line.mTrace.push_back(marker); +            } +        } +    } + +    // *TODO - parse MAPPED_LIBRARIES section here if we're ever interested in it +} + +void LLAllocatorHeapProfile::dump(std::ostream & out) const +{ +    lines_t::const_iterator i; +    for(i = mLines.begin(); i != mLines.end(); ++i) +    { +        out << i->mLiveCount << ": " << i->mLiveSize << '[' << i->mTotalCount << ": " << i->mTotalSize << "] @"; + +        stack_trace::const_iterator j; +        for(j = i->mTrace.begin(); j != i->mTrace.end(); ++j) +        { +            out << ' ' << *j; +        } +        out << '\n'; +    } +    out.flush(); +} + diff --git a/indra/llcommon/llallocator_heap_profile.h b/indra/llcommon/llallocator_heap_profile.h new file mode 100644 index 0000000000..19758df544 --- /dev/null +++ b/indra/llcommon/llallocator_heap_profile.h @@ -0,0 +1,77 @@ +/**  + * @file llallocator_heap_profile.h + * @brief Declaration of the parser for tcmalloc heap profile data. + * @author Brad Kittenbrink + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + *  + * Copyright (c) 2009-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLALLOCATOR_HEAP_PROFILE_H +#define LL_LLALLOCATOR_HEAP_PROFILE_H + +#include "stdtypes.h" + +#include <map> +#include <vector> + +class LLAllocatorHeapProfile +{ +public: +    typedef int stack_marker; + +    typedef std::vector<stack_marker> stack_trace; + +    struct line { +        line(U32 live_count, U64 live_size, U32 tot_count, U64 tot_size) : +            mLiveSize(live_size), +            mTotalSize(tot_size), +            mLiveCount(live_count), +            mTotalCount(tot_count) +        { +        } +        U64 mLiveSize, mTotalSize; +        U32 mLiveCount, mTotalCount; +        stack_trace mTrace; +    }; + +    typedef std::vector<line> lines_t; + +    LLAllocatorHeapProfile() +    { +    } + +	void parse(std::string const & prof_text); + +    void dump(std::ostream & out) const; + +public: +    lines_t mLines; +}; + + +#endif // LL_LLALLOCATOR_HEAP_PROFILE_H diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index cf3bf89b4f..6715b6722d 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -33,145 +33,112 @@  #include "linden_common.h"  #include "llassettype.h" +#include "lldictionary.h" +#include "llmemory.h" +#include "llsingleton.h" -#include "llstring.h" -#include "lltimer.h" - -// I added lookups for exact text of asset type enums in addition to the ones below, so shoot me. -Steve +///---------------------------------------------------------------------------- +/// Class LLAssetType +///---------------------------------------------------------------------------- +struct AssetEntry : public LLDictionaryEntry +{ +	AssetEntry(const char *desc_name, +			   const char *type_name, // 8 character limit! +			   const char *human_name, +			   const char *category_name, // used by llinventorymodel when creating new categories +			   EDragAndDropType dad_type); + +	// limited to 8 characters +	const char *mTypeName; +	// human readable form.  Put as many printable characters you want in each one. +	// (c.f. llinventory.cpp INVENTORY_TYPE_HUMAN_NAMES). +	const char *mHumanName; +	const char *mCategoryName; +	EDragAndDropType mDadType; +}; -struct asset_info_t +class LLAssetDictionary : public LLSingleton<LLAssetDictionary>, +						  public LLDictionary<LLAssetType::EType, AssetEntry>  { -	LLAssetType::EType type; -	const char* desc; +public: +	LLAssetDictionary();  }; -asset_info_t asset_types[] = +LLAssetDictionary::LLAssetDictionary()  { -	{ LLAssetType::AT_TEXTURE, "TEXTURE" }, -	{ LLAssetType::AT_SOUND, "SOUND" }, -	{ LLAssetType::AT_CALLINGCARD, "CALLINGCARD" }, -	{ LLAssetType::AT_LANDMARK, "LANDMARK" }, -	{ LLAssetType::AT_SCRIPT, "SCRIPT" }, -	{ LLAssetType::AT_CLOTHING, "CLOTHING" }, -	{ LLAssetType::AT_OBJECT, "OBJECT" }, -	{ LLAssetType::AT_NOTECARD, "NOTECARD" }, -	{ LLAssetType::AT_CATEGORY, "CATEGORY" }, -	{ LLAssetType::AT_ROOT_CATEGORY, "ROOT_CATEGORY" }, -	{ LLAssetType::AT_LSL_TEXT, "LSL_TEXT" }, -	{ LLAssetType::AT_LSL_BYTECODE, "LSL_BYTECODE" }, -	{ LLAssetType::AT_TEXTURE_TGA, "TEXTURE_TGA" }, -	{ LLAssetType::AT_BODYPART, "BODYPART" }, -	{ LLAssetType::AT_TRASH, "TRASH" }, -	{ LLAssetType::AT_SNAPSHOT_CATEGORY, "SNAPSHOT_CATEGORY" }, -	{ LLAssetType::AT_LOST_AND_FOUND, "LOST_AND_FOUND" }, -	{ LLAssetType::AT_SOUND_WAV, "SOUND_WAV" }, -	{ LLAssetType::AT_IMAGE_TGA, "IMAGE_TGA" }, -	{ LLAssetType::AT_IMAGE_JPEG, "IMAGE_JPEG" }, -	{ LLAssetType::AT_ANIMATION, "ANIMATION" }, -	{ LLAssetType::AT_GESTURE, "GESTURE" }, -	{ LLAssetType::AT_SIMSTATE, "SIMSTATE" }, -	{ LLAssetType::AT_NONE, "NONE" }, +	addEntry(LLAssetType::AT_TEXTURE, 			new AssetEntry("TEXTURE",			"texture",	"texture",			"Textures", 		DAD_TEXTURE)); +	addEntry(LLAssetType::AT_SOUND, 			new AssetEntry("SOUND",				"sound",	"sound",			"Sounds", 			DAD_SOUND)); +	addEntry(LLAssetType::AT_CALLINGCARD, 		new AssetEntry("CALLINGCARD",		"callcard",	"calling card",		"Calling Cards", 	DAD_CALLINGCARD)); +	addEntry(LLAssetType::AT_LANDMARK, 			new AssetEntry("LANDMARK",			"landmark",	"landmark",			"Landmarks", 		DAD_LANDMARK)); +	addEntry(LLAssetType::AT_SCRIPT, 			new AssetEntry("SCRIPT",			"script",	"legacy script",	"Scripts", 			DAD_NONE)); +	addEntry(LLAssetType::AT_CLOTHING, 			new AssetEntry("CLOTHING",			"clothing",	"clothing",			"Clothing", 		DAD_CLOTHING)); +	addEntry(LLAssetType::AT_OBJECT, 			new AssetEntry("OBJECT",			"object",	"object",			"Objects", 			DAD_OBJECT)); +	addEntry(LLAssetType::AT_NOTECARD, 			new AssetEntry("NOTECARD",			"notecard",	"note card",		"Notecards", 		DAD_NOTECARD)); +	addEntry(LLAssetType::AT_CATEGORY, 			new AssetEntry("CATEGORY",			"category",	"folder",			"New Folder", 		DAD_CATEGORY)); +	addEntry(LLAssetType::AT_ROOT_CATEGORY, 	new AssetEntry("ROOT_CATEGORY",		"root",		"root",				"Inventory", 		DAD_ROOT_CATEGORY)); +	addEntry(LLAssetType::AT_LSL_TEXT, 			new AssetEntry("LSL_TEXT",			"lsltext",	"lsl2 script",		"Scripts", 			DAD_SCRIPT)); +	addEntry(LLAssetType::AT_LSL_BYTECODE, 		new AssetEntry("LSL_BYTECODE",		"lslbyte",	"lsl bytecode",		"Scripts", 			DAD_NONE)); +	addEntry(LLAssetType::AT_TEXTURE_TGA, 		new AssetEntry("TEXTURE_TGA",		"txtr_tga",	"tga texture",		"Uncompressed Images", DAD_NONE)); +	addEntry(LLAssetType::AT_BODYPART, 			new AssetEntry("BODYPART",			"bodypart",	"body part",		"Body Parts", 		DAD_BODYPART)); +	addEntry(LLAssetType::AT_TRASH, 			new AssetEntry("TRASH",				"trash",	"trash",			"Trash", 			DAD_NONE)); +	addEntry(LLAssetType::AT_SNAPSHOT_CATEGORY, new AssetEntry("SNAPSHOT_CATEGORY", "snapshot",	"snapshot",			"Photo Album", 		DAD_NONE)); +	addEntry(LLAssetType::AT_LOST_AND_FOUND, 	new AssetEntry("LOST_AND_FOUND", 	"lstndfnd",	"lost and found",	"Lost And Found", 	DAD_NONE)); +	addEntry(LLAssetType::AT_SOUND_WAV, 		new AssetEntry("SOUND_WAV",			"snd_wav",	"sound",			"Uncompressed Sounds", DAD_NONE)); +	addEntry(LLAssetType::AT_IMAGE_TGA, 		new AssetEntry("IMAGE_TGA",			"img_tga",	"targa image",		"Uncompressed Images", DAD_NONE)); +	addEntry(LLAssetType::AT_IMAGE_JPEG, 		new AssetEntry("IMAGE_JPEG",		"jpeg",		"jpeg image",		"Uncompressed Images", DAD_NONE)); +	addEntry(LLAssetType::AT_ANIMATION, 		new AssetEntry("ANIMATION",			"animatn",	"animation",		"Animations", 		DAD_ANIMATION)); +	addEntry(LLAssetType::AT_GESTURE, 			new AssetEntry("GESTURE",			"gesture",	"gesture",			"Gestures", 		DAD_GESTURE)); +	addEntry(LLAssetType::AT_SIMSTATE, 			new AssetEntry("SIMSTATE",			"simstate",	"simstate",			"New Folder", 		DAD_NONE)); +	addEntry(LLAssetType::AT_LINK, 				new AssetEntry("LINK",				"link",		"symbolic  link",	"New Folder", 		DAD_NONE)); +	addEntry(LLAssetType::AT_FAVORITE, 			new AssetEntry("FAVORITE",			"favorite",	"favorite",			"favorite", 		DAD_NONE)); +	addEntry(LLAssetType::AT_NONE, 				new AssetEntry("NONE",				"-1",		NULL,		  		"New Folder", 		DAD_NONE));  }; -LLAssetType::EType LLAssetType::getType(const std::string& sin) +AssetEntry::AssetEntry(const char *desc_name, +					   const char *type_name, +					   const char *human_name, +					   const char *category_name, +					   EDragAndDropType dad_type) : +	LLDictionaryEntry(desc_name), +	mTypeName(type_name), +	mHumanName(human_name), +	mCategoryName(category_name), +	mDadType(dad_type)  { -	std::string s = sin; -	LLStringUtil::toUpper(s); -	for (S32 idx = 0; ;idx++) -	{ -		asset_info_t* info = asset_types + idx; -		if (info->type == LLAssetType::AT_NONE) -			break; -		if (s == info->desc) -			return info->type; -	} -	return LLAssetType::AT_NONE; +	llassert(strlen(mTypeName) <= 8);  } -std::string LLAssetType::getDesc(LLAssetType::EType type) +// static +LLAssetType::EType LLAssetType::getType(const std::string& desc_name)  { -	for (S32 idx = 0; ;idx++) -	{ -		asset_info_t* info = asset_types + idx; -		if (type == info->type) -			return info->desc; -		if (info->type == LLAssetType::AT_NONE) -			break; -	} -	return "BAD TYPE"; +	std::string s = desc_name; +	LLStringUtil::toUpper(s); +	return LLAssetDictionary::getInstance()->lookup(s);  } -//============================================================================ - -// The asset type names are limited to 8 characters.  // static -const char* LLAssetType::mAssetTypeNames[LLAssetType::AT_COUNT] = -{  -	"texture", -	"sound", -	"callcard", -	"landmark", -	"script", -	"clothing", -	"object", -	"notecard", -	"category", -	"root", -	"lsltext", -	"lslbyte", -	"txtr_tga",// Intentionally spelled this way.  Limited to eight characters. -	"bodypart", -	"trash", -	"snapshot", -	"lstndfnd", -	"snd_wav", -	"img_tga", -	"jpeg", -	"animatn", -	"gesture", -	"simstate" -}; - -// This table is meant for decoding to human readable form. Put any -// and as many printable characters you want in each one. -// See also llinventory.cpp INVENTORY_TYPE_HUMAN_NAMES -const char* LLAssetType::mAssetTypeHumanNames[LLAssetType::AT_COUNT] = +const std::string &LLAssetType::getDesc(LLAssetType::EType asset_type) +{ +	const AssetEntry *entry = LLAssetDictionary::getInstance()->lookup(asset_type); +	if (entry)  {  -	"texture", -	"sound", -	"calling card", -	"landmark", -	"legacy script", -	"clothing", -	"object", -	"note card", -	"folder", -	"root", -	"lsl2 script", -	"lsl bytecode", -	"tga texture", -	"body part", -	"trash", -	"snapshot", -	"lost and found", -	"sound", -	"targa image", -	"jpeg image", -	"animation", -	"gesture", -	"simstate" -}; - -///---------------------------------------------------------------------------- -/// class LLAssetType -///---------------------------------------------------------------------------- +		return entry->mName; +	} +	else +	{  +		static const std::string error_string = "BAD TYPE"; +		return error_string; +	} +}  // static -const char* LLAssetType::lookup( LLAssetType::EType type ) +const char *LLAssetType::lookup(LLAssetType::EType asset_type)  { -	if( (type >= 0) && (type < AT_COUNT )) +	const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); +	const AssetEntry *entry = dict->lookup(asset_type); +	if (entry)  	{ -		return mAssetTypeNames[ S32( type ) ]; +		return entry->mTypeName;  	}  	else  	{ @@ -185,25 +152,30 @@ LLAssetType::EType LLAssetType::lookup( const char* name )  	return lookup(ll_safe_string(name));  } -LLAssetType::EType LLAssetType::lookup( const std::string& name ) +LLAssetType::EType LLAssetType::lookup(const std::string& type_name)  { -	for( S32 i = 0; i < AT_COUNT; i++ ) +	const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); +	for (LLAssetDictionary::const_iterator iter = dict->begin(); +		 iter != dict->end(); +		 iter++)  	{ -		if( name == mAssetTypeNames[i] ) +		const AssetEntry *entry = iter->second; +		if (type_name == entry->mTypeName)  		{ -			// match -			return (EType)i; +			return iter->first;  		}  	}  	return AT_NONE;  }  // static -const char* LLAssetType::lookupHumanReadable(LLAssetType::EType type) +const char *LLAssetType::lookupHumanReadable(LLAssetType::EType asset_type)  { -	if( (type >= 0) && (type < AT_COUNT )) +	const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); +	const AssetEntry *entry = dict->lookup(asset_type); +	if (entry)  	{ -		return mAssetTypeHumanNames[S32(type)]; +		return entry->mHumanName;  	}  	else  	{ @@ -217,44 +189,51 @@ LLAssetType::EType LLAssetType::lookupHumanReadable( const char* name )  	return lookupHumanReadable(ll_safe_string(name));  } -LLAssetType::EType LLAssetType::lookupHumanReadable( const std::string& name ) +LLAssetType::EType LLAssetType::lookupHumanReadable(const std::string& readable_name)  { -	for( S32 i = 0; i < AT_COUNT; i++ ) +	const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); +	for (LLAssetDictionary::const_iterator iter = dict->begin(); +		 iter != dict->end(); +		 iter++)  	{ -		if( name == mAssetTypeHumanNames[i] ) +		const AssetEntry *entry = iter->second; +		if (readable_name == entry->mHumanName)  		{ -			// match -			return (EType)i; +			return iter->first;  		}  	}  	return AT_NONE;  } -EDragAndDropType LLAssetType::lookupDragAndDropType( EType asset ) +// static +const char *LLAssetType::lookupCategoryName(LLAssetType::EType asset_type)  { -	switch( asset ) +	const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); +	const AssetEntry *entry = dict->lookup(asset_type); +	if (entry)  	{ -	case AT_TEXTURE:		return DAD_TEXTURE; -	case AT_SOUND:			return DAD_SOUND; -	case AT_CALLINGCARD:	return DAD_CALLINGCARD; -	case AT_LANDMARK:		return DAD_LANDMARK; -	case AT_SCRIPT:			return DAD_NONE; -	case AT_CLOTHING:		return DAD_CLOTHING; -	case AT_OBJECT:			return DAD_OBJECT; -	case AT_NOTECARD:		return DAD_NOTECARD; -	case AT_CATEGORY:		return DAD_CATEGORY; -	case AT_ROOT_CATEGORY:	return DAD_ROOT_CATEGORY; -	case AT_LSL_TEXT:		return DAD_SCRIPT; -	case AT_BODYPART:		return DAD_BODYPART; -	case AT_ANIMATION:		return DAD_ANIMATION; -	case AT_GESTURE:		return DAD_GESTURE; -	default: 				return DAD_NONE; -	}; +		return entry->mCategoryName; +	} +	else +	{ +		return "New Folder"; +	} +} + +// static +EDragAndDropType LLAssetType::lookupDragAndDropType(EType asset_type) +{ +	const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); +	const AssetEntry *entry = dict->lookup(asset_type); +	if (entry) +		return entry->mDadType; +	else +		return DAD_NONE;  }  // static. Generate a good default description -void LLAssetType::generateDescriptionFor(LLAssetType::EType type, -										 std::string& desc) +void LLAssetType::generateDescriptionFor(LLAssetType::EType asset_type, +										 std::string& description)  {  	const S32 BUF_SIZE = 30;  	char time_str[BUF_SIZE];	/* Flawfinder: ignore */ @@ -262,6 +241,6 @@ void LLAssetType::generateDescriptionFor(LLAssetType::EType type,  	time(&now);  	memset(time_str, '\0', BUF_SIZE);  	strftime(time_str, BUF_SIZE - 1, "%Y-%m-%d %H:%M:%S ", localtime(&now)); -	desc.assign(time_str); -	desc.append(LLAssetType::lookupHumanReadable(type)); +	description.assign(time_str); +	description.append(LLAssetType::lookupHumanReadable(asset_type));  } diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index 4077b8d2c1..2f54031688 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -30,8 +30,8 @@   * $/LicenseInfo$   */ -#ifndef LL_LLASSETTYPE -#define LL_LLASSETTYPE +#ifndef LL_LLASSETTYPE_H +#define LL_LLASSETTYPE_H  #include <string> @@ -42,137 +42,142 @@ class LLAssetType  public:  	enum EType  	{ -		// Used for painting the faces of geometry. -		// Stored in typical j2c stream format  		AT_TEXTURE = 0, +			// Used for painting the faces of geometry. +			// Stored in typical j2c stream format. -		// Used to fill the aural spectrum.  		AT_SOUND = 1,  +			// Used to fill the aural spectrum. -		// Links instant message access to the user on the card. eg, a -		// card for yourself, a card for linden support, a card for -		// the guy you were talking to in the coliseum.  		AT_CALLINGCARD = 2, +		    // Links instant message access to the user on the card. +			// : E.G. A card for yourself, for linden support, for +			// : the guy you were talking to in the coliseum. -		// Links to places in the world with location and a screen -		// shot or image saved. eg, home, linden headquarters, the -		// coliseum, or destinations where we want to increase -		// traffic.  		AT_LANDMARK = 3, +			// Links to places in the world with location and a screen shot or image saved. +			// : E.G. Home, linden headquarters, the coliseum, destinations where  +			// : we want to increase traffic. -		// Valid scripts that can be attached to an object. eg. open a -		// door, jump into the air.  		AT_SCRIPT = 4, +			// Valid scripts that can be attached to an object. +			// : E.G. Open a door, jump into the air. -		// A collection of textures and parameters that can be worn -		// by an avatar.  		AT_CLOTHING = 5, +			// A collection of textures and parameters that can be worn by an avatar. -		// Any combination of textures, sounds, and scripts that are -		// associated with a fixed piece of geometry. eg, a hot tub, a -		// house with working door.  		AT_OBJECT = 6, +			// Any combination of textures, sounds, and scripts that are +			// associated with a fixed piece of geometry. +			// : E.G. A hot tub, a house with working door. -		// Just text  		AT_NOTECARD = 7, +			// Just text. -		// A category holds a collection of inventory items. It's -		// treated as an item in the inventory, and therefore needs a -		// type.  		AT_CATEGORY = 8, +			// Holds a collection of inventory items. +			// It's treated as an item in the inventory and therefore needs a type. -		// A root category is a user's root inventory category. We -		// decided to expose it visually, so it seems logical to fold -		// it into the asset types.  		AT_ROOT_CATEGORY = 9, +			// A user's root inventory category. +			// We decided to expose it visually, so it seems logical to fold +			// it into the asset types. -		// The LSL is the brand spanking new scripting language. We've -		// split it into a text and bytecode representation.  		AT_LSL_TEXT = 10,  		AT_LSL_BYTECODE = 11, +			// The LSL is the scripting language.  +			// We've split it into a text and bytecode representation. -		// uncompressed TGA texture  		AT_TEXTURE_TGA = 12, +			// Uncompressed TGA texture. -		// A collection of textures and parameters that can be worn -		// by an avatar.  		AT_BODYPART = 13, +			// A collection of textures and parameters that can be worn by an avatar. -		// This asset type is meant to only be used as a marker for a -		// category preferred type. Using this, we can throw things in -		// the trash before completely deleting.  		AT_TRASH = 14, +			// Only to be used as a marker for a category preferred type.  +			// Using this, we can throw things in the trash before completely deleting. -		// This is a marker for a folder meant for snapshots. No -		// actual assets will be snapshots, though if there were, you -		// could interpret them as textures.  		AT_SNAPSHOT_CATEGORY = 15, +			// A marker for a folder meant for snapshots.  +			// No actual assets will be snapshots, though if there were, you +			// could interpret them as textures. -		// This is used to stuff lost&found items into  		AT_LOST_AND_FOUND = 16, +			// Used to stuff lost&found items into. -		// uncompressed sound  		AT_SOUND_WAV = 17, +			// Uncompressed sound. -		// uncompressed image, non-square, and not appropriate for use -		// as a texture.  		AT_IMAGE_TGA = 18, +			// Uncompressed image, non-square. +			// Not appropriate for use as a texture. -		// compressed image, non-square, and not appropriate for use -		// as a texture.  		AT_IMAGE_JPEG = 19, +			// Compressed image, non-square. +			// Not appropriate for use as a texture. -		// animation  		AT_ANIMATION = 20, +			// Animation. -		// gesture, sequence of animations, sounds, chat, wait steps  		AT_GESTURE = 21, +			// Gesture, sequence of animations, sounds, chat, wait steps. -		// simstate file  		AT_SIMSTATE = 22, +			// Simstate file. +			 +		AT_LINK = 23, +			// Inventory symbolic link +			 +		AT_FAVORITE = 24, +			// favorite items  		// +*********************************************+  		// |  TO ADD AN ELEMENT TO THIS ENUM:            | -		// +*********************************************+ +			// +************************************************+  		// | 1. INSERT BEFORE AT_COUNT                   |  		// | 2. INCREMENT AT_COUNT BY 1                  |  		// | 3. ADD TO LLAssetType::mAssetTypeNames      |  		// | 4. ADD TO LLAssetType::mAssetTypeHumanNames |  		// +*********************************************+ -		AT_COUNT = 23, +		AT_COUNT = 25,  		AT_NONE = -1  	};  	// machine transation between type and strings  	static EType lookup(const char* name); // safe conversion to std::string, *TODO: deprecate -	static EType lookup(const std::string& name); -	static const char* lookup(EType type); +	static EType 				lookup(const std::string& type_name); +	static const char*			lookup(EType asset_type);  	// translation from a type to a human readable form. -	static EType lookupHumanReadable( const char* name ); // safe conversion to std::string, *TODO: deprecate -	static EType lookupHumanReadable( const std::string& name ); -	static const char* lookupHumanReadable(EType type); +	static EType 				lookupHumanReadable(const char* desc_name); // safe conversion to std::string, *TODO: deprecate +	static EType 				lookupHumanReadable(const std::string& readable_name); +	static const char*			lookupHumanReadable(EType asset_type); -	static EDragAndDropType lookupDragAndDropType( EType ); +	static const char*  		lookupCategoryName(EType asset_type);  	// Generate a good default description. You may want to add a verb  	// or agent name after this depending on your application. -	static void generateDescriptionFor(LLAssetType::EType type, -									   std::string& desc); - -	static EType getType(const std::string& sin); -	static std::string getDesc(EType type); +	static void 				generateDescriptionFor(LLAssetType::EType asset_type, +													   std::string& description); + +	static EType 				getType(const std::string& desc_name); +	static const std::string&	getDesc(EType asset_type); +	static EDragAndDropType   	lookupDragAndDropType(EType asset_type); + +	/* TODO: Change return types from "const char *" to "const std::string &". +	This is fairly straightforward, but requires changing some calls to use .c_str(). +	e.g.: +	-	fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType)); +	+	fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType).c_str()); +	*/  private:  	// don't instantiate or derive one of these objects -	LLAssetType( void ) {} -	~LLAssetType( void ) {} - -private: -	static const char* mAssetTypeNames[]; -	static const char* mAssetTypeHumanNames[]; +	LLAssetType() {} +	~LLAssetType() {}  }; -#endif // LL_LLASSETTYPE +#endif // LL_LLASSETTYPE_H diff --git a/indra/llcommon/llboost.h b/indra/llcommon/llboost.h index 4df9dbf3bd..f4bfc2bfa2 100644 --- a/indra/llcommon/llboost.h +++ b/indra/llcommon/llboost.h @@ -46,4 +46,19 @@  */  typedef boost::tokenizer<boost::char_separator<char> > boost_tokenizer; +// Useful combiner for boost signals that retturn a vool (e.g. validation) +//  returns false if any of the callbacks return false +struct boost_boolean_combiner +{ +	typedef bool result_type; +	template<typename InputIterator> +	bool operator()(InputIterator first, InputIterator last) const +	{ +		bool res = true; +		while (first != last) +			res &= *first++; +		return res; +	} +}; +  #endif // LL_LLBOOST_H diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp index 2cbb71855f..36a0018995 100644 --- a/indra/llcommon/llcommon.cpp +++ b/indra/llcommon/llcommon.cpp @@ -32,6 +32,8 @@  #include "linden_common.h"  #include "llcommon.h" + +#include "llmemory.h"  #include "llthread.h"  //static diff --git a/indra/llcommon/llcommon.h b/indra/llcommon/llcommon.h index 5f77988336..a1808e8a6c 100644 --- a/indra/llcommon/llcommon.h +++ b/indra/llcommon/llcommon.h @@ -32,9 +32,8 @@  #ifndef LL_COMMON_H  #define LL_COMMON_H -#include "llmemory.h" +// *TODO: remove these?  #include "llapr.h" -// #include "llframecallbackmanager.h"  #include "lltimer.h"  #include "llfile.h" diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp index 41a3af398f..7bc9e16bc9 100644 --- a/indra/llcommon/lldate.cpp +++ b/indra/llcommon/lldate.cpp @@ -38,10 +38,13 @@  #include "apr_time.h"  #include <time.h> +#include <locale> +#include <string>  #include <iomanip>  #include <sstream>  #include "lltimer.h" +#include "llstring.h"  static const F64 DATE_EPOCH = 0.0; @@ -88,45 +91,36 @@ std::string LLDate::asString() const  //        is one of the standards used and the prefered format  std::string LLDate::asRFC1123() const  { -    std::ostringstream stream; -    toHTTPDateStream(stream); -    return stream.str(); +	return toHTTPDateString (std::string ("%A, %d %b %Y %H:%M:%S GMT"));  } -void LLDate::toHTTPDateStream(std::ostream& s) const +std::string LLDate::toHTTPDateString (std::string fmt) const  { -    // http://apr.apache.org/docs/apr/0.9/group__apr__time.html -    apr_time_t time = (apr_time_t)(mSecondsSinceEpoch * LL_APR_USEC_PER_SEC); +	std::ostringstream stream; +	time_t locSeconds = (time_t) mSecondsSinceEpoch; +	struct tm * gmt = gmtime (&locSeconds); -    apr_time_exp_t exp_time ; //Apache time module +	stream.imbue (std::locale(LLStringUtil::getLocale().c_str())); +	toHTTPDateStream (stream, gmt, fmt); +	return stream.str(); +} -    if (apr_time_exp_gmt(&exp_time, time) != APR_SUCCESS) -    { -        // Return Epoch UTC date -        s << "Thursday, 01 Jan 1970 00:00:00 GMT" ; -        return; -    } +std::string LLDate::toHTTPDateString (tm * gmt, std::string fmt) +{ +	std::ostringstream stream; +	stream.imbue (std::locale(LLStringUtil::getLocale().c_str())); +	toHTTPDateStream (stream, gmt, fmt); +	return stream.str(); +} -    s << std::dec << std::setfill('0'); -#if( LL_WINDOWS || __GNUC__ > 2) -    s << std::right ; -#else -    s.setf(ios::right); -#endif     -    std::string day = weekdays[exp_time.tm_wday]; -    std::string month = months[exp_time.tm_mon]; - -    s << std::setw(day.length()) << (day) -      << ", " << std::setw(2) << (exp_time.tm_mday) -      << ' ' << std::setw(month.length()) << (month) -      << ' ' << std::setw(4) << (exp_time.tm_year + 1900) -	  << ' ' << std::setw(2) << (exp_time.tm_hour) -	  << ':' << std::setw(2) << (exp_time.tm_min) -	  << ':' << std::setw(2) << (exp_time.tm_sec) -      << " GMT"; +void LLDate::toHTTPDateStream(std::ostream& s, tm * gmt, std::string fmt) +{ +	using namespace std; -    // RFC 1123 date does not use microseconds -    //llinfos << "Date in RFC 1123 format is " << s << llendl; +	const char * pBeg = fmt.c_str(); +	const char * pEnd = pBeg + fmt.length(); +	const time_put<char>& tp = use_facet<time_put<char> >(s.getloc()); +	tp.put (s, s, s.fill(), gmt, pBeg, pEnd);  }  void LLDate::toStream(std::ostream& s) const diff --git a/indra/llcommon/lldate.h b/indra/llcommon/lldate.h index 7cc9c8aceb..23d3b900f8 100644 --- a/indra/llcommon/lldate.h +++ b/indra/llcommon/lldate.h @@ -84,7 +84,9 @@ public:  	std::string asString() const;  	std::string asRFC1123() const;  	void toStream(std::ostream&) const; -	void toHTTPDateStream(std::ostream&) const; +	std::string toHTTPDateString (std::string fmt) const; +	static std::string toHTTPDateString (tm * gmt, std::string fmt); +	static void toHTTPDateStream(std::ostream&, tm *, std::string);  	/**   	 * @brief Set the date from an ISO-8601 string.  	 * diff --git a/indra/llcommon/lldeleteutils.h b/indra/llcommon/lldeleteutils.h new file mode 100644 index 0000000000..d6a0945e46 --- /dev/null +++ b/indra/llcommon/lldeleteutils.h @@ -0,0 +1,53 @@ +/**  + * @file lldeleteutils.h + * @brief Utility functions to simplify some common pointer-munging idioms. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + *  + * Copyright (c) 2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#ifndef LL_DELETE_UTILS_H +#define LL_DELETE_UTILS_H + +// Simple utility functions to eventually replace the common 2-line +// idiom scattered throughout the viewer codebase.  Note that where +// possible we would rather be using smart pointers of some sort. + +template <class T> +inline void deleteAndClear(T*& ptr) +{ +	delete ptr; +	ptr = NULL; +} + +template <class T> +inline void deleteAndClearArray(T*& array_ptr) +{ +	delete[] array_ptr; +	array_ptr = NULL; +} + +#endif diff --git a/indra/llcommon/lldictionary.h b/indra/llcommon/lldictionary.h new file mode 100644 index 0000000000..856947def8 --- /dev/null +++ b/indra/llcommon/lldictionary.h @@ -0,0 +1,102 @@ +/**  + * @file lldictionary.h + * @brief Lldictionary class header file + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + *  + * Copyright (c) 2002-2007, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLDICTIONARY_H +#define LL_LLDICTIONARY_H + +#include <map> + +struct LLDictionaryEntry +{ +	LLDictionaryEntry(const std::string &name) : +		mName(name) +	{ +		mNameCapitalized = mName; +		LLStringUtil::replaceChar(mNameCapitalized, '-', ' '); +		LLStringUtil::replaceChar(mNameCapitalized, '_', ' '); +		for (U32 i=0; i < mNameCapitalized.size(); i++) +		{ +			if (i == 0 || mNameCapitalized[i-1] == ' ') // don't change ordering of this statement or crash +			{ +				mNameCapitalized[i] = toupper(mNameCapitalized[i]); +			} +		} +	} +	virtual ~LLDictionaryEntry() {} +	const std::string mName; +	std::string mNameCapitalized; +}; + +template <class Index, class Entry> +class LLDictionary : public std::map<Index, Entry *> +{ +public: +	typedef std::map<Index, Entry *> map_t; +	typedef typename map_t::iterator iterator_t; +	typedef typename map_t::const_iterator const_iterator_t; +	 +	LLDictionary() {} +	virtual ~LLDictionary() +	{ +		for (iterator_t iter = map_t::begin(); iter != map_t::end(); ++iter) +			delete (iter->second); +	} + +	const Entry *lookup(Index index) const +	{ +		const_iterator_t dictionary_iter = map_t::find(index); +		if (dictionary_iter == map_t::end()) return NULL; +		return dictionary_iter->second; +	} +	const Index lookup(const std::string &name) const  +	{ +		for (const_iterator_t dictionary_iter = map_t::begin(); +			 dictionary_iter != map_t::end(); +			 dictionary_iter++) +		{ +			const Entry *entry = dictionary_iter->second; +			if (entry->mName == name) +			{ +				return dictionary_iter->first; +			} +		} +		llassert(false); +		return Index(-1); +	} + +protected: +	void addEntry(Index index, Entry *entry) +	{ +		(*this)[index] = entry; +	} +}; + +#endif // LL_LLDICTIONARY_H diff --git a/indra/llcommon/lldoubledispatch.h b/indra/llcommon/lldoubledispatch.h new file mode 100755 index 0000000000..60678d44fb --- /dev/null +++ b/indra/llcommon/lldoubledispatch.h @@ -0,0 +1,332 @@ +/** + * @file   lldoubledispatch.h + * @author Nat Goodspeed + * @date   2008-11-11 + * @brief  function calls virtual on more than one parameter + *  + * $LicenseInfo:firstyear=2008&license=viewergpl$ + *  + * Copyright (c) 2008-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLDOUBLEDISPATCH_H) +#define LL_LLDOUBLEDISPATCH_H + +#include <list> +#include <boost/shared_ptr.hpp> +#include <boost/function.hpp> +#include <boost/bind.hpp> +#include <boost/ref.hpp> + +/** + * This class supports function calls which are virtual on the dynamic type of + * more than one parameter. Specifically, we address a limited but useful + * subset of that problem: function calls which accept two parameters, and + * select which particular function to call depending on the dynamic type of + * both. + *  + * Scott Meyers, in More Effective C++ (Item 31), talks about some of the perils + * and pitfalls lurking down this pathway.  He discusses and dismisses the + * straightforward approaches of using single-dispatch virtual functions twice, + * and of using a family of single-dispatch virtual functions which each examine + * RTTI for their other parameter.  He advocates using a registry in which you + * look up the actual types of both parameters (he uses the classes' string names, + * via typeid(param).name()) to obtain a pointer to a free (non-member) function + * that will accept this pair of parameters. + *  + * He does point out that his approach doesn't handle inheritance.  If you have a + * registry entry for SpaceShip, and you have in hand a MilitaryShip (subclass of + * SpaceShip) and an Asteroid, you'd like to call the function appropriate for + * SpaceShips and Asteroids -- but alas, his lookup fails because the class name + * for your MilitaryShip subclass isn't in the registry. + *  + * This class extends his idea to build a registry whose entries can examine the + * dynamic type of the parameter in a more flexible way -- using dynamic_cast<> + * -- thereby supporting inheritance relationships. + *  + * Of course we must allow for the ambiguity this permits. We choose to use a + * sequence container rather than a map, and require that the client code + * specify the order in which dispatch-table entries should be searched. The + * result resembles the semantics of the catch clauses for a try/catch block: + * you must code catch clauses in decreasing order of specificity, because if + * you catch ErrorBaseClass before you catch ErrorSubclass, then any + * ErrorSubclass exceptions thrown by the protected code will always match + * ErrorBaseClass, and you will never reach your catch(ErrorSubclass) clause. + *  + * So, in a similar way, if you have a specific routine to process + * MilitaryShip and Asteroid, you'd better place that in the table @em before + * your more general routine that processes SpaceShip and Asteroid, or else + * the MilitaryShip variant will never be called. + * + * @todo This implementation doesn't attempt to deal with + * <tt>const</tt>-correctness of arguments. Our container stores templated + * objects into which the specific parameter types have been "frozen." But to + * store all these in the same container, they are all instances of a base + * class with a virtual invocation method. Naturally the base-class virtual + * method definition cannot know the <tt>const</tt>-ness of the particular + * types with which its template subclass is instantiated. + * + * One is tempted to suggest four different virtual methods, one for each + * combination of @c const and non-<tt>const</tt> arguments. Then the client + * will select the particular virtual method that best fits the + * <tt>const</tt>-ness of the arguments in hand. The trouble with that idea is + * that in order to instantiate the subclass instance, we must compile all + * four of its virtual method overrides, which means we must be prepared to + * pass all four combinations of @c const and non-<tt>const</tt> arguments to + * the registered callable. That only works when the registered callable + * accepts both parameters as @c const. + * + * Of course the virtual method overrides could use @c const_cast to force + * them to compile correctly regardless of the <tt>const</tt>-ness of the + * registered callable's parameter declarations. But if we're going to force + * the issue with @c const_cast anyway, why bother with the four different + * virtual methods? Why not just require canonical parameter + * <tt>const</tt>-ness for any callables used with this mechanism? + * + * We therefore require that your callable accept both params as + * non-<tt>const</tt>. (This is more general than @c const: you can perform @c + * const operations on a non-<tt>const</tt> parameter, but you can't perform + * non-<tt>const</tt> operations on a @c const parameter.) + * + * For ease of use, though, our invocation method accepts both params as @c + * const. Again, you can pass a non-<tt>const</tt> object to a @c const param, + * but not the other way around. We take care of the @c const_cast for you. + */ +// LLDoubleDispatch is a template because we have to assume that all parameter +// types are subclasses of some common base class -- but we don't have to +// impose that base class on client code.  Instead, we let IT tell US the +// common parameter base class. +template<class ReturnType, class ParamBaseType> +class LLDoubleDispatch +{ +    typedef LLDoubleDispatch<ReturnType, ParamBaseType> self_type; + +public: +    LLDoubleDispatch() {} + +    /** +     * Call the first matching entry.  If there's no registered Functor +     * appropriate for this pair of parameter types, this call will do +     * @em nothing!  (If you want notification in this case, simply add a new +     * Functor for (ParamBaseType&, ParamBaseType&) at the end of the table. +     * The two base-class entries should match anything that isn't matched by +     * any more specific entry.) +     * +     * See note in class documentation about <tt>const</tt>-correctness. +     */ +    inline +    ReturnType operator()(const ParamBaseType& param1, const ParamBaseType& param2) const; + +    // Borrow a trick from Alexandrescu:  use a Type class to "wrap" a type +    // for purposes of passing the type itself into a template method. +    template<typename T> +    struct Type {}; + +    /** +     * Add a new Entry for a given @a Functor. As mentioned above, the order +     * in which you add these entries is very important. +     * +     * If you want symmetrical entries -- that is, if a B and an A can call +     * the same Functor as an A and a B -- then pass @c true for the last +     * parameter, and we'll add a (B, A) entry as well as an (A, B) entry. But +     * your @a Functor can still be written to expect exactly the pair of types +     * you've explicitly specified, because the Entry with the reversed params +     * will call a special thunk that swaps params before calling your @a +     * Functor. +     */ +    template<typename Type1, typename Type2, class Functor> +    void add(const Type<Type1>& t1, const Type<Type2>& t2, Functor func, bool symmetrical=false) +    { +        insert(t1, t2, func); +        if (symmetrical) +        { +            // Use boost::bind() to construct a param-swapping thunk. Don't +            // forget to reverse the parameters too. +            insert(t2, t1, boost::bind(func, _2, _1)); +        } +    } + +    /** +     * Add a new Entry for a given @a Functor, explicitly passing instances of +     * the Functor's leaf param types to help us figure out where to insert. +     * Because it can use RTTI, this add() method isn't order-sensitive like +     * the other one. +     * +     * If you want symmetrical entries -- that is, if a B and an A can call +     * the same Functor as an A and a B -- then pass @c true for the last +     * parameter, and we'll add a (B, A) entry as well as an (A, B) entry. But +     * your @a Functor can still be written to expect exactly the pair of types +     * you've explicitly specified, because the Entry with the reversed params +     * will call a special thunk that swaps params before calling your @a +     * Functor. +     */ +    template <typename Type1, typename Type2, class Functor> +    void add(const Type1& prototype1, const Type2& prototype2, Functor func, bool symmetrical=false) +    { +        // Because we expect our caller to pass leaf param types, we can just +        // perform an ordinary search to find the first matching iterator. If +        // we find an existing Entry that matches both params, either the +        // param types are the same, or the existing Entry uses the base class +        // for one or both params, and the new Entry must precede that. Assume +        // our client won't register two callables with exactly the SAME set +        // of types; in that case we'll insert the new one before any earlier +        // ones, meaning the last one registered will "win." Note that if +        // find() doesn't find any matching Entry, it will return end(), +        // meaning the new Entry will be last, which is fine. +        typename DispatchTable::iterator insertion = find(prototype1, prototype2); +        insert(Type<Type1>(), Type<Type2>(), func, insertion); +        if (symmetrical) +        { +            insert(Type<Type2>(), Type<Type1>(), boost::bind(func, _2, _1), insertion); +        } +    } + +    /** +     * Add a new Entry for a given @a Functor, specifying the Functor's leaf +     * param types as explicit template arguments. This will instantiate +     * temporary objects of each of these types, which requires that they have +     * a lightweight default constructor. +     * +     * If you want symmetrical entries -- that is, if a B and an A can call +     * the same Functor as an A and a B -- then pass @c true for the last +     * parameter, and we'll add a (B, A) entry as well as an (A, B) entry. But +     * your @a Functor can still be written to expect exactly the pair of types +     * you've explicitly specified, because the Entry with the reversed params +     * will call a special thunk that swaps params before calling your @a +     * Functor. +     */ +    template <typename Type1, typename Type2, class Functor> +    void add(Functor func, bool symmetrical=false) +    { +        // This is a convenience wrapper for the add() variant taking explicit +        // instances. +        add(Type1(), Type2(), func, symmetrical); +    } + +private: +    /// This is the base class for each entry in our dispatch table. +    struct EntryBase +    { +        virtual ~EntryBase() {} +        virtual bool matches(const ParamBaseType& param1, const ParamBaseType& param2) const = 0; +        virtual ReturnType operator()(ParamBaseType& param1, ParamBaseType& param2) const = 0; +    }; + +    /// Here's the template subclass that actually creates each entry. +    template<typename Type1, typename Type2, class Functor> +    class Entry: public EntryBase +    { +    public: +        Entry(Functor func): mFunc(func) {} +        /// Is this entry appropriate for these arguments? +        virtual bool matches(const ParamBaseType& param1, const ParamBaseType& param2) const +        { +            return (dynamic_cast<const Type1*>(¶m1) && +                    dynamic_cast<const Type2*>(¶m2)); +        } +        /// invocation +        virtual ReturnType operator()(ParamBaseType& param1, ParamBaseType& param2) const +        { +            // We perform the downcast so callable can accept leaf param +            // types, instead of accepting ParamBaseType and downcasting +            // explicitly. +            return mFunc(dynamic_cast<Type1&>(param1), dynamic_cast<Type2&>(param2)); +        } +    private: +        /// Bind whatever function or function object the instantiator passed. +        Functor mFunc; +    }; + +    /// shared_ptr manages Entry lifespan for us +    typedef boost::shared_ptr<EntryBase> EntryPtr; +    /// use a @c list to make it easy to insert +    typedef std::list<EntryPtr> DispatchTable; +    DispatchTable mDispatch; + +    /// Look up the location of the first matching entry. +    typename DispatchTable::const_iterator find(const ParamBaseType& param1, const ParamBaseType& param2) const +    { +        // We assert that it's safe to call the non-const find() method on a +        // const LLDoubleDispatch instance. Cast away the const-ness of 'this'. +        return const_cast<self_type*>(this)->find(param1, param2); +    } + +    /// Look up the location of the first matching entry. +    typename DispatchTable::iterator find(const ParamBaseType& param1, const ParamBaseType& param2) +    { +        return std::find_if(mDispatch.begin(), mDispatch.end(), +                            boost::bind(&EntryBase::matches, _1, +                                        boost::ref(param1), boost::ref(param2))); +    } + +    /// Look up the first matching entry. +    EntryPtr lookup(const ParamBaseType& param1, const ParamBaseType& param2) const +    { +        typename DispatchTable::const_iterator found = find(param1, param2);             +        if (found != mDispatch.end()) +        { +            // Dereferencing the list iterator gets us an EntryPtr +            return *found; +        } +        // not found +        return EntryPtr(); +    } + +    // Break out the actual insert operation so the public add() template +    // function can avoid calling itself recursively.  See add() comments. +    template<typename Type1, typename Type2, class Functor> +    void insert(const Type<Type1>& param1, const Type<Type2>& param2, Functor func) +    { +        insert(param1, param2, func, mDispatch.end()); +    } + +    // Break out the actual insert operation so the public add() template +    // function can avoid calling itself recursively.  See add() comments. +    template<typename Type1, typename Type2, class Functor> +    void insert(const Type<Type1>&, const Type<Type2>&, Functor func, +                typename DispatchTable::iterator where) +    { +        mDispatch.insert(where, EntryPtr(new Entry<Type1, Type2, Functor>(func))); +    } + +    /// Don't implement the copy ctor.  Everyone will be happier if the +    /// LLDoubleDispatch object isn't copied. +    LLDoubleDispatch(const LLDoubleDispatch& src); +}; + +template <class ReturnType, class ParamBaseType> +ReturnType LLDoubleDispatch<ReturnType, ParamBaseType>::operator()(const ParamBaseType& param1, +                                                                   const ParamBaseType& param2) const +{ +    EntryPtr found = lookup(param1, param2); +    if (found.get() == 0) +        return ReturnType();    // bogus return value + +    // otherwise, call the Functor we found +    return (*found)(const_cast<ParamBaseType&>(param1), const_cast<ParamBaseType&>(param2)); +} + +#endif /* ! defined(LL_LLDOUBLEDISPATCH_H) */ diff --git a/indra/llcommon/llerrorthread.cpp b/indra/llcommon/llerrorthread.cpp index 4c779c58c8..f0e46ae78d 100644 --- a/indra/llcommon/llerrorthread.cpp +++ b/indra/llcommon/llerrorthread.cpp @@ -31,7 +31,9 @@  #include "linden_common.h"  #include "llerrorthread.h" +  #include "llapp.h" +#include "lltimer.h"	// ms_sleep()  LLErrorThread::LLErrorThread()  	: LLThread("Error"), diff --git a/indra/llcommon/llevent.h b/indra/llcommon/llevent.h index a74ddbd091..2cc8577219 100644 --- a/indra/llcommon/llevent.h +++ b/indra/llcommon/llevent.h @@ -35,7 +35,7 @@  #define LL_EVENT_H  #include "llsd.h" -#include "llmemory.h" +#include "llpointer.h"  #include "llthread.h"  namespace LLOldEvents diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index f70d532e4c..2f6515a4cb 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -38,7 +38,7 @@  #include <boost/function.hpp>  #include <boost/static_assert.hpp>  #include "llsd.h" -#include "llmemory.h" +#include "llsingleton.h"  #include "lldependencies.h"  // override this to allow binding free functions with more parameters diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index 94b51119e4..612068b202 100644 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -30,229 +30,323 @@   * $/LicenseInfo$   */ -#ifndef LL_LLFASTTIMER_H -#define LL_LLFASTTIMER_H +#ifndef LL_FASTTIMER_H +#define LL_FASTTIMER_H + +#include "llinstancetracker.h"  #define FAST_TIMER_ON 1  U64 get_cpu_clock_count(); +class LLMutex; + +#include <queue> +#include "llsd.h" + +  class LLFastTimer  {  public: -	enum EFastTimerType +	// stores a "named" timer instance to be reused via multiple LLFastTimer stack instances +	class NamedTimer  +	:	public LLInstanceTracker<NamedTimer>  	{ -		// high level -		FTM_FRAME, -		FTM_UPDATE, -		FTM_RENDER, -		FTM_SWAP, -		FTM_CLIENT_COPY, -		FTM_IDLE, -		FTM_SLEEP, - -		// common messaging components -		FTM_PUMP, -		FTM_CURL, -		 -		// common simulation components -		FTM_UPDATE_ANIMATION, -		FTM_UPDATE_TERRAIN, -		FTM_UPDATE_PRIMITIVES, -		FTM_UPDATE_PARTICLES, -		FTM_SIMULATE_PARTICLES, -		FTM_UPDATE_SKY, -		FTM_UPDATE_TEXTURES, -		FTM_UPDATE_WLPARAM, -		FTM_UPDATE_WATER, -		FTM_UPDATE_CLOUDS, -		FTM_UPDATE_GRASS, -		FTM_UPDATE_TREE, -		FTM_UPDATE_AVATAR, -		 -		// common render components -		FTM_SHADOW_GEOMETRY, -		FTM_SHADOW_RENDER, -		FTM_SHADOW_TERRAIN, -		FTM_SHADOW_AVATAR, -		FTM_SHADOW_SIMPLE, -		FTM_SHADOW_ALPHA, -		FTM_SHADOW_TREE, -		 -		FTM_RENDER_GEOMETRY, -		 FTM_RENDER_TERRAIN, -		 FTM_RENDER_SIMPLE, -		 FTM_RENDER_FULLBRIGHT, -		 FTM_RENDER_GLOW, -		 FTM_RENDER_GRASS, -		 FTM_RENDER_INVISIBLE, -		 FTM_RENDER_SHINY, -		 FTM_RENDER_BUMP, -		 FTM_RENDER_TREES, -		 FTM_RENDER_CHARACTERS, -		 FTM_RENDER_OCCLUSION, -		 FTM_RENDER_ALPHA, -         FTM_RENDER_CLOUDS, -		 FTM_RENDER_HUD, -		 FTM_RENDER_PARTICLES, -		 FTM_RENDER_WATER, -		 FTM_RENDER_WL_SKY, -		 FTM_RENDER_FAKE_VBO_UPDATE, -		FTM_RENDER_TIMER, -		FTM_RENDER_UI, -		FTM_RENDER_BLOOM, -			FTM_RENDER_BLOOM_FBO,		 -		FTM_RENDER_FONTS, -		 -		// newview specific -		FTM_MESSAGES, -		FTM_MOUSEHANDLER, -		FTM_KEYHANDLER, -		FTM_REBUILD, -		FTM_STATESORT, -		FTM_STATESORT_DRAWABLE, -		FTM_STATESORT_POSTSORT, -		FTM_REBUILD_VBO, -		FTM_REBUILD_VOLUME_VB, -		FTM_REBUILD_BRIDGE_VB, -		FTM_REBUILD_HUD_VB, -		FTM_REBUILD_TERRAIN_VB, -		FTM_REBUILD_WATER_VB, -		FTM_REBUILD_TREE_VB, -		FTM_REBUILD_PARTICLE_VB, -		FTM_REBUILD_CLOUD_VB, -		FTM_REBUILD_GRASS_VB, -		FTM_REBUILD_NONE_VB, -		FTM_REBUILD_OCCLUSION_VB, -		FTM_POOLS, -		FTM_POOLRENDER, -		FTM_IDLE_CB, -		FTM_WORLD_UPDATE, -		FTM_UPDATE_MOVE, -		FTM_OCTREE_BALANCE, -		FTM_UPDATE_LIGHTS, -		FTM_CULL, -		FTM_CULL_REBOUND, -		FTM_FRUSTUM_CULL, -		FTM_GEO_UPDATE, -		FTM_GEO_RESERVE, -		FTM_GEO_LIGHT, -		FTM_GEO_SHADOW, -		FTM_GEO_SKY, -		FTM_GEN_VOLUME, -		FTM_GEN_TRIANGLES, -		FTM_GEN_FLEX, -		FTM_AUDIO_UPDATE, -		FTM_RESET_DRAWORDER, -		FTM_OBJECTLIST_UPDATE, -		FTM_AVATAR_UPDATE, -		FTM_JOINT_UPDATE, -		FTM_ATTACHMENT_UPDATE, -		FTM_LOD_UPDATE, -		FTM_REGION_UPDATE, -		FTM_CLEANUP, -		FTM_NETWORK, -		FTM_IDLE_NETWORK, -		FTM_CREATE_OBJECT, -		FTM_LOAD_AVATAR, -		FTM_PROCESS_MESSAGES, -		FTM_PROCESS_OBJECTS, -		FTM_PROCESS_IMAGES, -		FTM_IMAGE_UPDATE, -		FTM_IMAGE_CREATE, -		FTM_IMAGE_DECODE, -		FTM_IMAGE_MARK_DIRTY, -		FTM_PIPELINE, -		FTM_VFILE_WAIT, -		FTM_FLEXIBLE_UPDATE, -		FTM_OCCLUSION_READBACK, -		FTM_HUD_EFFECTS, -		FTM_HUD_UPDATE, -		FTM_INVENTORY, -		FTM_AUTO_SELECT, -		FTM_ARRANGE, -		FTM_FILTER, -		FTM_REFRESH, -		FTM_SORT, -		FTM_PICK, -		 -		// Temp -		FTM_TEMP1, -		FTM_TEMP2, -		FTM_TEMP3, -		FTM_TEMP4, -		FTM_TEMP5, -		FTM_TEMP6, -		FTM_TEMP7, -		FTM_TEMP8, -		 -		FTM_OTHER, // Special, used by display code +	public: +		~NamedTimer(); + +		enum { HISTORY_NUM = 60 }; + +		const std::string& getName() { return mName; } +		NamedTimer* getParent() { return mParent; } +		void setParent(NamedTimer* parent); +		S32 getDepth(); +		std::string getToolTip(S32 history_index = -1); + +		typedef std::vector<NamedTimer*>::const_iterator child_const_iter; +		child_const_iter beginChildren(); +		child_const_iter endChildren(); +		std::vector<NamedTimer*>& getChildren(); + +		void setCollapsed(bool collapsed) { mCollapsed = collapsed; } +		bool getCollapsed() { return mCollapsed; } + +		U64 getCountAverage() { return mCountAverage; } +		U64 getCallAverage() { return mCallAverage; } + +		U64 getHistoricalCount(S32 history_index = 0); +		U64 getHistoricalCalls(S32 history_index = 0); + +		static NamedTimer& getRootNamedTimer(); + +		struct FrameState +		{ +			FrameState(NamedTimer* timerp); + +			U64 		mSelfTimeCounter; +			U64			mLastStartTime;		// most recent time when this timer was started +			U32 		mCalls; +			FrameState*	mParent;		// info for caller timer +			FrameState*	mLastCaller;	// used to bootstrap tree construction +			NamedTimer*	mTimer; +			U16			mActiveCount;	// number of timers with this ID active on stack +			bool		mMoveUpTree;	// needs to be moved up the tree of timers at the end of frame +		}; + +		FrameState& getFrameStateFast() const +		{ +			return (*sTimerInfos)[mFrameStateIndex]; +		} + +		S32 getFrameStateIndex() const { return mFrameStateIndex; } + +		FrameState& getFrameState() const; + + +	private:  +		friend class LLFastTimer; +		friend class NamedTimerFactory; + +		// +		// methods +		// +		NamedTimer(const std::string& name); +		// recursive call to gather total time from children +		static void accumulateTimings(); + +		// called once per frame by LLFastTimer +		static void processFrame(); + +		static void buildHierarchy(); +		static void resetFrame(); +		static void reset(); + +		typedef std::vector<FrameState> info_list_t; +		static info_list_t& getFrameStateList(); +		static void createFrameStateList(); // must call before any call to getFrameStateList() -		FTM_NUM_TYPES +		// +		// members +		// +		S32			mFrameStateIndex; + +		std::string	mName; + +		U64 		mTotalTimeCounter; + +		U64 		mCountAverage; +		U64			mCallAverage; + +		U64*		mCountHistory; +		U64*		mCallHistory; + +		// tree structure +		NamedTimer*					mParent;				// NamedTimer of caller(parent) +		std::vector<NamedTimer*>	mChildren; +		bool						mCollapsed;				// don't show children +		bool						mNeedsSorting;			// sort children whenever child added + +		static info_list_t* sTimerInfos;  	}; -	enum { FTM_HISTORY_NUM = 60 }; -	enum { FTM_MAX_DEPTH = 64 }; -	 + +	// used to statically declare a new named timer +	class DeclareTimer +	{ +	public: +		DeclareTimer(const std::string& name, bool open); +		DeclareTimer(const std::string& name); + +		// convertable to NamedTimer::FrameState for convenient usage of LLFastTimer(declared_timer) +		operator NamedTimer::FrameState&() { return mNamedTimer.getFrameStateFast(); } +	private: +		NamedTimer& mNamedTimer; +	}; + +	static DeclareTimer FTM_ARRANGE; +	static DeclareTimer FTM_ATTACHMENT_UPDATE; +	static DeclareTimer FTM_AUDIO_UPDATE; +	static DeclareTimer FTM_AUTO_SELECT; +	static DeclareTimer FTM_AVATAR_UPDATE; +	static DeclareTimer FTM_CLEANUP; +	static DeclareTimer FTM_CLIENT_COPY; +	static DeclareTimer FTM_CREATE_OBJECT; +	static DeclareTimer FTM_CULL; +	static DeclareTimer FTM_CULL_REBOUND; +	static DeclareTimer FTM_FILTER; +	static DeclareTimer FTM_FLEXIBLE_UPDATE; +	static DeclareTimer FTM_FRAME; +	static DeclareTimer FTM_FRUSTUM_CULL; +	static DeclareTimer FTM_GEN_FLEX; +	static DeclareTimer FTM_GEN_TRIANGLES; +	static DeclareTimer FTM_GEN_VOLUME; +	static DeclareTimer FTM_GEO_SKY; +	static DeclareTimer FTM_GEO_UPDATE; +	static DeclareTimer FTM_HUD_EFFECTS; +	static DeclareTimer FTM_HUD_UPDATE; +	static DeclareTimer FTM_IDLE; +	static DeclareTimer FTM_IDLE_CB; +	static DeclareTimer FTM_IDLE_NETWORK; +	static DeclareTimer FTM_IMAGE_CREATE; +	static DeclareTimer FTM_IMAGE_MARK_DIRTY; +	static DeclareTimer FTM_IMAGE_UPDATE; +	static DeclareTimer FTM_INVENTORY; +	static DeclareTimer FTM_JOINT_UPDATE; +	static DeclareTimer FTM_KEYHANDLER; +	static DeclareTimer FTM_LOAD_AVATAR; +	static DeclareTimer FTM_LOD_UPDATE; +	static DeclareTimer FTM_MESSAGES; +	static DeclareTimer FTM_MOUSEHANDLER; +	static DeclareTimer FTM_NETWORK; +	static DeclareTimer FTM_OBJECTLIST_UPDATE; +	static DeclareTimer FTM_OCCLUSION_READBACK; +	static DeclareTimer FTM_OCTREE_BALANCE; +	static DeclareTimer FTM_PICK; +	static DeclareTimer FTM_PIPELINE; +	static DeclareTimer FTM_POOLRENDER; +	static DeclareTimer FTM_POOLS; +	static DeclareTimer FTM_PROCESS_IMAGES; +	static DeclareTimer FTM_PROCESS_MESSAGES; +	static DeclareTimer FTM_PROCESS_OBJECTS; +	static DeclareTimer FTM_PUMP; +	static DeclareTimer FTM_REBUILD_GRASS_VB; +	static DeclareTimer FTM_REBUILD_PARTICLE_VB; +	static DeclareTimer FTM_REBUILD_TERRAIN_VB; +	static DeclareTimer FTM_REBUILD_VBO; +	static DeclareTimer FTM_REBUILD_VOLUME_VB; +	static DeclareTimer FTM_REFRESH; +	static DeclareTimer FTM_REGION_UPDATE; +	static DeclareTimer FTM_RENDER; +	static DeclareTimer FTM_RENDER_ALPHA; +	static DeclareTimer FTM_RENDER_BLOOM; +	static DeclareTimer FTM_RENDER_BLOOM_FBO; +	static DeclareTimer FTM_RENDER_BUMP; +	static DeclareTimer FTM_RENDER_CHARACTERS; +	static DeclareTimer FTM_RENDER_FAKE_VBO_UPDATE; +	static DeclareTimer FTM_RENDER_FONTS; +	static DeclareTimer FTM_RENDER_FULLBRIGHT; +	static DeclareTimer FTM_RENDER_GEOMETRY; +	static DeclareTimer FTM_RENDER_GLOW; +	static DeclareTimer FTM_RENDER_GRASS; +	static DeclareTimer FTM_RENDER_INVISIBLE; +	static DeclareTimer FTM_RENDER_OCCLUSION; +	static DeclareTimer FTM_RENDER_SHINY; +	static DeclareTimer FTM_RENDER_SIMPLE; +	static DeclareTimer FTM_RENDER_TERRAIN; +	static DeclareTimer FTM_RENDER_TREES; +	static DeclareTimer FTM_RENDER_UI; +	static DeclareTimer FTM_RENDER_WATER; +	static DeclareTimer FTM_RENDER_WL_SKY; +	static DeclareTimer FTM_RESET_DRAWORDER; +	static DeclareTimer FTM_SHADOW_ALPHA; +	static DeclareTimer FTM_SHADOW_AVATAR; +	static DeclareTimer FTM_SHADOW_RENDER; +	static DeclareTimer FTM_SHADOW_SIMPLE; +	static DeclareTimer FTM_SHADOW_TERRAIN; +	static DeclareTimer FTM_SHADOW_TREE; +	static DeclareTimer FTM_SIMULATE_PARTICLES; +	static DeclareTimer FTM_SLEEP; +	static DeclareTimer FTM_SORT; +	static DeclareTimer FTM_STATESORT; +	static DeclareTimer FTM_STATESORT_DRAWABLE; +	static DeclareTimer FTM_STATESORT_POSTSORT; +	static DeclareTimer FTM_SWAP; +	static DeclareTimer FTM_TEMP1; +	static DeclareTimer FTM_TEMP2; +	static DeclareTimer FTM_TEMP3; +	static DeclareTimer FTM_TEMP4; +	static DeclareTimer FTM_TEMP5; +	static DeclareTimer FTM_TEMP6; +	static DeclareTimer FTM_TEMP7; +	static DeclareTimer FTM_TEMP8; +	static DeclareTimer FTM_UPDATE_ANIMATION; +	static DeclareTimer FTM_UPDATE_AVATAR; +	static DeclareTimer FTM_UPDATE_CLOUDS; +	static DeclareTimer FTM_UPDATE_GRASS; +	static DeclareTimer FTM_UPDATE_MOVE; +	static DeclareTimer FTM_UPDATE_PARTICLES; +	static DeclareTimer FTM_UPDATE_PRIMITIVES; +	static DeclareTimer FTM_UPDATE_SKY; +	static DeclareTimer FTM_UPDATE_TERRAIN; +	static DeclareTimer FTM_UPDATE_TEXTURES; +	static DeclareTimer FTM_UPDATE_TREE; +	static DeclareTimer FTM_UPDATE_WATER; +	static DeclareTimer FTM_UPDATE_WLPARAM; +	static DeclareTimer FTM_VFILE_WAIT; +	static DeclareTimer FTM_WORLD_UPDATE; +  public: -	static LLFastTimer::EFastTimerType sCurType; +	enum RootTimerMarker { ROOT }; +	 +	static LLMutex* sLogLock; +	static std::queue<LLSD> sLogQueue; +	static BOOL sLog; +	static BOOL sMetricLog; + +	LLFastTimer(RootTimerMarker); -	LLFastTimer(EFastTimerType type) +	LLFastTimer(NamedTimer::FrameState& timer) +	:	mFrameState(&timer)  	{ -#if FAST_TIMER_ON -		mType = type; -		sCurType = type; -		// These don't get counted, because they use CPU clockticks -		//gTimerBins[gCurTimerBin]++; -		//LLTimer::sNumTimerCalls++; +		NamedTimer::FrameState* frame_state = mFrameState; +		frame_state->mLastStartTime = get_cpu_clock_count(); +		mStartSelfTime = frame_state->mLastStartTime; -		U64 cpu_clocks = get_cpu_clock_count(); +		frame_state->mActiveCount++; +		frame_state->mCalls++; +		// keep current parent as long as it is active when we are +		frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0); +	 +		mLastTimer = sCurTimer; +		sCurTimer = this; +	} -		sStart[sCurDepth] = cpu_clocks; -		sCurDepth++; -#endif -	};  	~LLFastTimer()  	{  #if FAST_TIMER_ON -		U64 end,delta; -		int i; - -		// These don't get counted, because they use CPU clockticks -		//gTimerBins[gCurTimerBin]++; -		//LLTimer::sNumTimerCalls++; -		end = get_cpu_clock_count(); - -		sCurDepth--; -		delta = end - sStart[sCurDepth]; -		sCounter[mType] += delta; -		sCalls[mType]++; -		// Subtract delta from parents -		for (i=0; i<sCurDepth; i++) -			sStart[i] += delta; +		NamedTimer::FrameState* frame_state = mFrameState; +		U64 cur_time = get_cpu_clock_count(); +		frame_state->mSelfTimeCounter += cur_time - mStartSelfTime; + +		frame_state->mActiveCount--; +		LLFastTimer* last_timer = mLastTimer; +		sCurTimer = last_timer; + +		// store last caller to bootstrap tree creation +		frame_state->mLastCaller = last_timer->mFrameState; + +		// we are only tracking self time, so subtract our total time delta from parents +		U64 total_time = cur_time - frame_state->mLastStartTime; +		last_timer->mStartSelfTime += total_time;  #endif  	} + +	// call this once a frame to reset timers +	static void nextFrame(); + +	// call this to reset timer hierarchy, averages, etc.  	static void reset(); +  	static U64 countsPerSecond(); +	static S32 getLastFrameIndex() { return sLastFrameIndex; } +	static S32 getCurFrameIndex() { return sCurFrameIndex; } + +	static void writeLog(std::ostream& os);  public: -	static int sCurDepth; -	static U64 sStart[FTM_MAX_DEPTH]; -	static U64 sCounter[FTM_NUM_TYPES]; -	static U64 sCalls[FTM_NUM_TYPES]; -	static U64 sCountAverage[FTM_NUM_TYPES]; -	static U64 sCallAverage[FTM_NUM_TYPES]; -	static U64 sCountHistory[FTM_HISTORY_NUM][FTM_NUM_TYPES]; -	static U64 sCallHistory[FTM_HISTORY_NUM][FTM_NUM_TYPES]; -	static S32 sCurFrameIndex; -	static S32 sLastFrameIndex; -	static int sPauseHistory; -	static int sResetHistory; -	static F64 sCPUClockFrequency; +	static bool 		sPauseHistory; +	static bool 		sResetHistory;  private: -	EFastTimerType mType; -}; +	typedef std::vector<LLFastTimer*> timer_stack_t; +	static LLFastTimer*		sCurTimer; +	static S32				sCurFrameIndex; +	static S32				sLastFrameIndex; +	static F64				sCPUClockFrequency; +	U64						mStartSelfTime;	// start time + time of all child timers +	NamedTimer::FrameState*	mFrameState; +	LLFastTimer*			mLastTimer; +};  #endif // LL_LLFASTTIMER_H diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h new file mode 100644 index 0000000000..ea50acbbc5 --- /dev/null +++ b/indra/llcommon/llinstancetracker.h @@ -0,0 +1,121 @@ +/**  + * @file llinstancetracker.h + * @brief LLInstanceTracker is a mixin class that automatically tracks object + *        instances with or without an associated key + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + *  + * Copyright (c) 2000-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLINSTANCETRACKER_H +#define LL_LLINSTANCETRACKER_H + +#include <map> + +#include "string_table.h" +#include <boost/utility.hpp> + +// This mix-in class adds support for tracking all instances of the specified class parameter T +// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup +// If KEY is not provided, then instances are stored in a simple set +// *NOTE: see explicit specialization below for default KEY==T* case +template<typename T, typename KEY = T*> +class LLInstanceTracker : boost::noncopyable +{ +public: +	typedef typename std::map<KEY, T*>::iterator instance_iter; +	typedef typename std::map<KEY, T*>::const_iterator instance_const_iter; + +	static T* getInstance(const KEY& k) { instance_iter found = getMap().find(k); return (found == getMap().end()) ? NULL : found->second; } + +	static instance_iter beginInstances() { return getMap().begin(); } +	static instance_iter endInstances() { return getMap().end(); } +	static S32 instanceCount() { return getMap().size(); } +protected: +	LLInstanceTracker(KEY key) { add(key); } +	virtual ~LLInstanceTracker() { remove(); } +	virtual void setKey(KEY key) { remove(); add(key); } +	virtual const KEY& getKey() const { return mKey; } + +private: +	void add(KEY key)  +	{  +		mKey = key;  +		getMap()[key] = static_cast<T*>(this);  +	} +	void remove() { getMap().erase(mKey); } + +    static std::map<KEY, T*>& getMap() +    { +        if (! sInstances) +        { +            sInstances = new std::map<KEY, T*>; +        } +        return *sInstances; +    } + +private: + +	KEY mKey; +	static std::map<KEY, T*>* sInstances; +}; + +// explicit specialization for default case where KEY is T* +// use a simple std::set<T*> +template<typename T> +class LLInstanceTracker<T, T*> +{ +public: +	typedef typename std::set<T*>::iterator instance_iter; +	typedef typename std::set<T*>::const_iterator instance_const_iter; + +	static instance_iter beginInstances() { return getSet().begin(); } +	static instance_iter endInstances() { return getSet().end(); } +	static S32 instanceCount() { return getSet().size(); } + +protected: +	LLInstanceTracker() { getSet().insert(static_cast<T*>(this)); } +	virtual ~LLInstanceTracker() { getSet().erase(static_cast<T*>(this)); } + +	LLInstanceTracker(const LLInstanceTracker& other) { getSet().insert(static_cast<T*>(this)); } + +    static std::set<T*>& getSet()   // called after getReady() but before go() +    { +        if (! sInstances) +        { +            sInstances = new std::set<T*>; +        } +        return *sInstances; +    } + +	static std::set<T*>* sInstances; +}; + +template <typename T, typename KEY> std::map<KEY, T*>* LLInstanceTracker<T, KEY>::sInstances = NULL; +template <typename T> std::set<T*>* LLInstanceTracker<T, T*>::sInstances = NULL; + +#endif diff --git a/indra/llcommon/llmd5.cpp b/indra/llcommon/llmd5.cpp index 14b4f9f4b0..da9cb94e13 100644 --- a/indra/llcommon/llmd5.cpp +++ b/indra/llcommon/llmd5.cpp @@ -83,6 +83,7 @@ documentation and/or software.  #include "llmd5.h"  #include <cassert> +#include <iostream>		// cerr  // how many bytes to grab at a time when checking files  const int LLMD5::BLOCK_LEN = 4096; diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index a6de3d2d69..2a8015e26d 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -44,7 +44,6 @@  #endif  #include "llmemory.h" -#include "llmemtype.h"  //---------------------------------------------------------------------------- @@ -74,162 +73,6 @@ void LLMemory::freeReserve()  	reserveMem = NULL;  } - -//---------------------------------------------------------------------------- - -//static -#if MEM_TRACK_TYPE -S32 LLMemType::sCurDepth = 0; -S32 LLMemType::sCurType = LLMemType::MTYPE_INIT; -S32 LLMemType::sType[LLMemType::MTYPE_MAX_DEPTH]; -S32 LLMemType::sMemCount[LLMemType::MTYPE_NUM_TYPES] = { 0 }; -S32 LLMemType::sMaxMemCount[LLMemType::MTYPE_NUM_TYPES] = { 0 }; -S32 LLMemType::sNewCount[LLMemType::MTYPE_NUM_TYPES] = { 0 }; -S32 LLMemType::sOverheadMem = 0; - -const char* LLMemType::sTypeDesc[LLMemType::MTYPE_NUM_TYPES] = -{ -	"INIT", -	"STARTUP", -	"MAIN", -	 -	"IMAGEBASE", -	"IMAGERAW", -	"IMAGEFORMATTED", -	 -	"APPFMTIMAGE", -	"APPRAWIMAGE", -	"APPAUXRAWIMAGE", -	 -	"DRAWABLE", -	"OBJECT", -	"PIPELINE", -	"AVATAR", -	"PARTICLES", -	"REGIONS", -	"INVENTORY", -	"ANIMATION", -	"NETWORK", -	"PHYSICS", -	"INTERESTLIST", -	 -	"SCRIPT", -	"SCRIPT_RUN", -	"SCRIPT_BYTECODE", -	 -	"IO_PUMP", -	"IO_TCP", -	"IO_BUFFER", -	"IO_HTTP_SERVER" -	"IO_SD_SERVER", -	"IO_SD_CLIENT", -	"IO_URL_REQUEST", - -	"TEMP1", -	"TEMP2", -	"TEMP3", -	"TEMP4", -	"TEMP5", -	"TEMP6", -	"TEMP7", -	"TEMP8", -	"TEMP9" -}; - -#endif -S32 LLMemType::sTotalMem = 0; -S32 LLMemType::sMaxTotalMem = 0; - -//static -void LLMemType::printMem() -{ -	S32 misc_mem = sTotalMem; -#if MEM_TRACK_TYPE -	for (S32 i=0; i<MTYPE_NUM_TYPES; i++) -	{ -		if (sMemCount[i]) -		{ -			llinfos << llformat("MEM: % 20s %03d MB (%03d MB) in %06d News",sTypeDesc[i],sMemCount[i]>>20,sMaxMemCount[i]>>20, sNewCount[i]) << llendl; -		} -		misc_mem -= sMemCount[i]; -	} -#endif -	llinfos << llformat("MEM: % 20s %03d MB","MISC",misc_mem>>20) << llendl; -	llinfos << llformat("MEM: % 20s %03d MB (Max=%d MB)","TOTAL",sTotalMem>>20,sMaxTotalMem>>20) << llendl; -} - -#if MEM_TRACK_MEM - -void* ll_allocate (size_t size) -{ -	if (size == 0) -	{ -		llwarns << "Null allocation" << llendl; -	} -	 -	size = (size+3)&~3; -	S32 alloc_size = size + 4; -#if MEM_TRACK_TYPE -	alloc_size += 4; -#endif -	char* p = (char*)malloc(alloc_size); -	if (p == NULL) -	{ -		LLMemory::freeReserve(); -		llerrs << "Out of memory Error" << llendl; -	} -	LLMemType::sTotalMem += size; -	LLMemType::sMaxTotalMem = llmax(LLMemType::sTotalMem, LLMemType::sMaxTotalMem); -	LLMemType::sOverheadMem += 4; -	*(size_t*)p = size; -	p += 4; -#if MEM_TRACK_TYPE -	if (LLMemType::sCurType < 0 || LLMemType::sCurType >= LLMemType::MTYPE_NUM_TYPES) -	{ -		llerrs << "Memory Type Error: new" << llendl; -	} -	LLMemType::sOverheadMem += 4; -	*(S32*)p = LLMemType::sCurType; -	p += 4; -	LLMemType::sMemCount[LLMemType::sCurType] += size; -	if (LLMemType::sMemCount[LLMemType::sCurType] > LLMemType::sMaxMemCount[LLMemType::sCurType]) -	{ -		LLMemType::sMaxMemCount[LLMemType::sCurType] = LLMemType::sMemCount[LLMemType::sCurType]; -	} -	LLMemType::sNewCount[LLMemType::sCurType]++; -#endif -	return (void*)p; -} - -void ll_release (void *pin) -{ -	if (!pin) -	{ -		return; -	} -	char* p = (char*)pin; -#if MEM_TRACK_TYPE -	p -= 4; -	S32 type = *(S32*)p; -	if (type < 0 || type >= LLMemType::MTYPE_NUM_TYPES) -	{ -		llerrs << "Memory Type Error: delete" << llendl; -	} -#endif -	p -= 4; -	S32 size = *(size_t*)p; -	LLMemType::sOverheadMem -= 4; -#if MEM_TRACK_TYPE -	LLMemType::sMemCount[type] -= size; -	LLMemType::sOverheadMem -= 4; -	LLMemType::sNewCount[type]--; -#endif -	LLMemType::sTotalMem -= size; -	free(p); -} - -#else -  void* ll_allocate (size_t size)  {  	if (size == 0) @@ -250,52 +93,11 @@ void ll_release (void *p)  	free(p);  } -#endif - -#if MEM_TRACK_MEM - -void* operator new (size_t size) -{ -	return ll_allocate(size); -} - -void* operator new[] (size_t size) -{ -	return ll_allocate(size); -} - -void operator delete (void *p) -{ -	ll_release(p); -} - -void operator delete[] (void *p) -{ -	ll_release(p); -} - -#endif - -//---------------------------------------------------------------------------- - -LLRefCount::LLRefCount() : -	mRef(0) -{ -} - -LLRefCount::~LLRefCount() -{  -	if (mRef != 0) -	{ -		llerrs << "deleting non-zero reference" << llendl; -	} -} -	  //----------------------------------------------------------------------------  #if defined(LL_WINDOWS) -U64 getCurrentRSS() +U64 LLMemory::getCurrentRSS()  {  	HANDLE self = GetCurrentProcess();  	PROCESS_MEMORY_COUNTERS counters; @@ -333,7 +135,7 @@ U64 getCurrentRSS()  // 	}  // } -U64 getCurrentRSS() +U64 LLMemory::getCurrentRSS()  {  	U64 residentSize = 0;  	task_basic_info_data_t basicInfo; @@ -357,7 +159,7 @@ U64 getCurrentRSS()  #elif defined(LL_LINUX) -U64 getCurrentRSS() +U64 LLMemory::getCurrentRSS()  {  	static const char statPath[] = "/proc/self/stat";  	LLFILE *fp = LLFile::fopen(statPath, "r"); @@ -396,7 +198,7 @@ bail:  #define _STRUCTURED_PROC 1  #include <sys/procfs.h> -U64 getCurrentRSS() +U64 LLMemory::getCurrentRSS()  {  	char path [LL_MAX_PATH];	/* Flawfinder: ignore */  @@ -419,7 +221,7 @@ U64 getCurrentRSS()  }  #else -U64 getCurrentRSS() +U64 LLMemory::getCurrentRSS()  {  	return 0;  } diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index b5c0711484..f41da37ba6 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -29,21 +29,17 @@   * COMPLETENESS OR PERFORMANCE.   * $/LicenseInfo$   */ -#ifndef LL_MEMORY_H -#define LL_MEMORY_H +#ifndef LLMEMORY_H +#define LLMEMORY_H -#include <new> -#include <cstdlib> -#include "llerror.h"  extern S32 gTotalDAlloc;  extern S32 gTotalDAUse;  extern S32 gDACount; -const U32 LLREFCOUNT_SENTINEL_VALUE = 0xAAAAAAAA; - -//---------------------------------------------------------------------------- +extern void* ll_allocate (size_t size); +extern void ll_release (void *p);  class LLMemory  { @@ -51,422 +47,19 @@ public:  	static void initClass();  	static void cleanupClass();  	static void freeReserve(); +	// Return the resident set size of the current process, in bytes. +	// Return value is zero if not known. +	static U64 getCurrentRSS();  private:  	static char* reserveMem;  }; -//---------------------------------------------------------------------------- -// RefCount objects should generally only be accessed by way of LLPointer<>'s -// NOTE: LLPointer<LLFoo> x = new LLFoo(); MAY NOT BE THREAD SAFE -//   if LLFoo::LLFoo() does anything like put itself in an update queue. -//   The queue may get accessed before it gets assigned to x. -// The correct implementation is: -//   LLPointer<LLFoo> x = new LLFoo; // constructor does not do anything interesting -//   x->instantiate(); // does stuff like place x into an update queue - -// see llthread.h for LLThreadSafeRefCount - -//---------------------------------------------------------------------------- - -class LLRefCount -{ -protected: -	LLRefCount(const LLRefCount&); // not implemented -private: -	LLRefCount&operator=(const LLRefCount&); // not implemented - -protected: -	virtual ~LLRefCount(); // use unref() -	 -public: -	LLRefCount(); - -	void ref() -	{  -		mRef++;  -	}  - -	S32 unref() -	{ -		llassert(mRef >= 1); -		if (0 == --mRef)  -		{ -			delete this;  -			return 0; -		} -		return mRef; -	}	 - -	S32 getNumRefs() const -	{ -		return mRef; -	} - -private:  -	S32	mRef;  -}; - -//---------------------------------------------------------------------------- - -// Note: relies on Type having ref() and unref() methods -template <class Type> class LLPointer -{ -public: - -	LLPointer() :  -		mPointer(NULL) -	{ -	} - -	LLPointer(Type* ptr) :  -		mPointer(ptr) -	{ -		ref(); -	} - -	LLPointer(const LLPointer<Type>& ptr) :  -		mPointer(ptr.mPointer) -	{ -		ref(); -	} - -	// support conversion up the type hierarchy.  See Item 45 in Effective C++, 3rd Ed. -	template<typename Subclass> -	LLPointer(const LLPointer<Subclass>& ptr) :  -		mPointer(ptr.get()) -	{ -		ref(); -	} - -	~LLPointer()								 -	{ -		unref(); -	} - -	Type*	get() const							{ return mPointer; } -	const Type*	operator->() const				{ return mPointer; } -	Type*	operator->()						{ return mPointer; } -	const Type&	operator*() const				{ return *mPointer; } -	Type&	operator*()							{ return *mPointer; } - -	operator BOOL()  const						{ return (mPointer != NULL); } -	operator bool()  const						{ return (mPointer != NULL); } -	bool operator!() const						{ return (mPointer == NULL); } -	bool isNull() const							{ return (mPointer == NULL); } -	bool notNull() const						{ return (mPointer != NULL); } - -	operator Type*()       const				{ return mPointer; } -	operator const Type*() const				{ return mPointer; } -	bool operator !=(Type* ptr) const           { return (mPointer != ptr); 	} -	bool operator ==(Type* ptr) const           { return (mPointer == ptr); 	} -	bool operator ==(const LLPointer<Type>& ptr) const           { return (mPointer == ptr.mPointer); 	} -	bool operator < (const LLPointer<Type>& ptr) const           { return (mPointer < ptr.mPointer); 	} -	bool operator > (const LLPointer<Type>& ptr) const           { return (mPointer > ptr.mPointer); 	} - -	LLPointer<Type>& operator =(Type* ptr)                    -	{  -		if( mPointer != ptr ) -		{ -			unref();  -			mPointer = ptr;  -			ref(); -		} - -		return *this;  -	} - -	LLPointer<Type>& operator =(const LLPointer<Type>& ptr)   -	{  -		if( mPointer != ptr.mPointer ) -		{ -			unref();  -			mPointer = ptr.mPointer; -			ref(); -		} -		return *this;  -	} - -	// support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. -	template<typename Subclass> -	LLPointer<Type>& operator =(const LLPointer<Subclass>& ptr)   -	{  -		if( mPointer != ptr.get() ) -		{ -			unref();  -			mPointer = ptr.get(); -			ref(); -		} -		return *this;  -	} -	 -	// Just exchange the pointers, which will not change the reference counts. -	static void swap(LLPointer<Type>& a, LLPointer<Type>& b) -	{ -		Type* temp = a.mPointer; -		a.mPointer = b.mPointer; -		b.mPointer = temp; -	} - -protected: -	void ref()                              -	{  -		if (mPointer) -		{ -			mPointer->ref(); -		} -	} - -	void unref() -	{ -		if (mPointer) -		{ -			Type *tempp = mPointer; -			mPointer = NULL; -			tempp->unref(); -			if (mPointer != NULL) -			{ -				llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl; -				unref(); -			} -		} -	} - -protected: -	Type*	mPointer; -}; - -//template <class Type>  -//class LLPointerTraits -//{ -//	static Type* null(); -//}; -// -// Expands LLPointer to return a pointer to a special instance of class Type instead of NULL. -// This is useful in instances where operations on NULL pointers are semantically safe and/or -// when error checking occurs at a different granularity or in a different part of the code -// than when referencing an object via a LLSafeHandle. -//  - -template <class Type>  -class LLSafeHandle -{ -public: -	LLSafeHandle() : -		mPointer(NULL) -	{ -	} - -	LLSafeHandle(Type* ptr) :  -		mPointer(NULL) -	{ -		assign(ptr); -	} - -	LLSafeHandle(const LLSafeHandle<Type>& ptr) :  -		mPointer(NULL) -	{ -		assign(ptr.mPointer); -	} - -	// support conversion up the type hierarchy.  See Item 45 in Effective C++, 3rd Ed. -	template<typename Subclass> -	LLSafeHandle(const LLSafeHandle<Subclass>& ptr) :  -		mPointer(NULL) -	{ -		assign(ptr.get()); -	} - -	~LLSafeHandle()								 -	{ -		unref(); -	} - -	const Type*	operator->() const				{ return nonNull(mPointer); } -	Type*	operator->()						{ return nonNull(mPointer); } - -	Type*	get() const							{ return mPointer; } -	// we disallow these operations as they expose our null objects to direct manipulation -	// and bypass the reference counting semantics -	//const Type&	operator*() const			{ return *nonNull(mPointer); } -	//Type&	operator*()							{ return *nonNull(mPointer); } - -	operator BOOL()  const						{ return mPointer != NULL; } -	operator bool()  const						{ return mPointer != NULL; } -	bool operator!() const						{ return mPointer == NULL; } -	bool isNull() const							{ return mPointer == NULL; } -	bool notNull() const						{ return mPointer != NULL; } - - -	operator Type*()       const				{ return mPointer; } -	operator const Type*() const				{ return mPointer; } -	bool operator !=(Type* ptr) const           { return (mPointer != ptr); 	} -	bool operator ==(Type* ptr) const           { return (mPointer == ptr); 	} -	bool operator ==(const LLSafeHandle<Type>& ptr) const           { return (mPointer == ptr.mPointer); 	} -	bool operator < (const LLSafeHandle<Type>& ptr) const           { return (mPointer < ptr.mPointer); 	} -	bool operator > (const LLSafeHandle<Type>& ptr) const           { return (mPointer > ptr.mPointer); 	} - -	LLSafeHandle<Type>& operator =(Type* ptr)                    -	{  -		assign(ptr); -		return *this;  -	} - -	LLSafeHandle<Type>& operator =(const LLSafeHandle<Type>& ptr)   -	{  -		assign(ptr.mPointer); -		return *this;  -	} - -	// support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. -	template<typename Subclass> -	LLSafeHandle<Type>& operator =(const LLSafeHandle<Subclass>& ptr)   -	{  -		assign(ptr.get()); -		return *this;  -	} - -public: -	typedef Type* (*NullFunc)(); -	static const NullFunc sNullFunc; - -protected: -	void ref()                              -	{  -		if (mPointer) -		{ -			mPointer->ref(); -		} -	} - -	void unref() -	{ -		if (mPointer) -		{ -			Type *tempp = mPointer; -			mPointer = NULL; -			tempp->unref(); -			if (mPointer != NULL) -			{ -				llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl; -				unref(); -			} -		} -	} - -	void assign(Type* ptr) -	{ -		if( mPointer != ptr ) -		{ -			unref();  -			mPointer = ptr;  -			ref(); -		} -	} - -	static Type* nonNull(Type* ptr) -	{ -		return ptr == NULL ? sNullFunc() : ptr; -	} - -protected: -	Type*	mPointer; -}; - -// LLInitializedPointer is just a pointer with a default constructor that initializes it to NULL -// NOT a smart pointer like LLPointer<> -// Useful for example in std::map<int,LLInitializedPointer<LLFoo> > -//  (std::map uses the default constructor for creating new entries) -template <typename T> class LLInitializedPointer -{ -public: -	LLInitializedPointer() : mPointer(NULL) {} -	~LLInitializedPointer() { delete mPointer; } -	 -	const T* operator->() const { return mPointer; } -	T* operator->() 			{ return mPointer; } -	const T& operator*() const 	{ return *mPointer; } -	T& operator*() 				{ return *mPointer; } -	operator const T*() const	{ return mPointer; } -	operator T*()				{ return mPointer; } -	T* operator=(T* x)				{ return (mPointer = x); } -	operator bool() const		{ return mPointer != NULL; } -	bool operator!() const		{ return mPointer == NULL; } -	bool operator==(T* rhs)		{ return mPointer == rhs; } -	bool operator==(const LLInitializedPointer<T>* rhs) { return mPointer == rhs.mPointer; } - -protected: -	T* mPointer; -};	 - -//---------------------------------------------------------------------------- +// LLRefCount moved to llrefcount.h -// LLSingleton implements the getInstance() method part of the Singleton -// pattern. It can't make the derived class constructors protected, though, so -// you have to do that yourself. -// -// There are two ways to use LLSingleton. The first way is to inherit from it -// while using the typename that you'd like to be static as the template -// parameter, like so: -// -//   class Foo: public LLSingleton<Foo>{}; -// -//   Foo& instance = Foo::instance(); -// -// The second way is to use the singleton class directly, without inheritance: -// -//   typedef LLSingleton<Foo> FooSingleton; -// -//   Foo& instance = FooSingleton::instance(); -// -// In this case, the class being managed as a singleton needs to provide an -// initSingleton() method since the LLSingleton virtual method won't be -// available -// -// As currently written, it is not thread-safe. -template <typename T> -class LLSingleton -{ -public: -	virtual ~LLSingleton() {} -#ifdef  LL_MSVC7 -// workaround for VC7 compiler bug -// adapted from http://www.codeproject.com/KB/tips/VC2003MeyersSingletonBug.aspx -// our version doesn't introduce a nested struct so that you can still declare LLSingleton<MyClass> -// a friend and hide your constructor -	static T* getInstance() -    { -        LLSingleton<T> singleton; -        return singleton.vsHack(); -    } - -	T* vsHack() -#else -	static T* getInstance() -#endif -	{ -		static T instance; -		static bool needs_init = true; -		if (needs_init) -		{ -			needs_init = false; -			instance.initSingleton(); -		} -		return &instance; -	} - -	static T& instance() -	{ -		return *getInstance(); -	} - -private: -	virtual void initSingleton() {} -}; +// LLPointer moved to llpointer.h -//---------------------------------------------------------------------------- +// LLSafeHandle moved to llsafehandle.h -// Return the resident set size of the current process, in bytes. -// Return value is zero if not known. -U64 getCurrentRSS(); +// LLSingleton moved to llsingleton.h  #endif diff --git a/indra/llcommon/llmemtype.cpp b/indra/llcommon/llmemtype.cpp new file mode 100644 index 0000000000..4e33439711 --- /dev/null +++ b/indra/llcommon/llmemtype.cpp @@ -0,0 +1,237 @@ +/**  + * @file llmemtype.cpp + * @brief Simple memory allocation/deallocation tracking stuff here + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + *  + * Copyright (c) 2002-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llmemtype.h" +#include "llallocator.h" + +std::vector<char const *> LLMemType::DeclareMemType::mNameList; + +LLMemType::DeclareMemType LLMemType::MTYPE_INIT("Init"); +LLMemType::DeclareMemType LLMemType::MTYPE_STARTUP("Startup"); +LLMemType::DeclareMemType LLMemType::MTYPE_MAIN("Main"); +LLMemType::DeclareMemType LLMemType::MTYPE_FRAME("Frame"); + +LLMemType::DeclareMemType LLMemType::MTYPE_GATHER_INPUT("GatherInput"); +LLMemType::DeclareMemType LLMemType::MTYPE_JOY_KEY("JoyKey"); + +LLMemType::DeclareMemType LLMemType::MTYPE_IDLE("Idle"); +LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_PUMP("IdlePump"); +LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_NETWORK("IdleNetwork"); +LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_UPDATE_REGIONS("IdleUpdateRegions"); +LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_UPDATE_VIEWER_REGION("IdleUpdateViewerRegion"); +LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_UPDATE_SURFACE("IdleUpdateSurface"); +LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_UPDATE_PARCEL_OVERLAY("IdleUpdateParcelOverlay"); +LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_AUDIO("IdleAudio"); + +LLMemType::DeclareMemType LLMemType::MTYPE_CACHE_PROCESS_PENDING("CacheProcessPending"); +LLMemType::DeclareMemType LLMemType::MTYPE_CACHE_PROCESS_PENDING_ASKS("CacheProcessPendingAsks"); +LLMemType::DeclareMemType LLMemType::MTYPE_CACHE_PROCESS_PENDING_REPLIES("CacheProcessPendingReplies"); + +LLMemType::DeclareMemType LLMemType::MTYPE_MESSAGE_CHECK_ALL("MessageCheckAll"); +LLMemType::DeclareMemType LLMemType::MTYPE_MESSAGE_PROCESS_ACKS("MessageProcessAcks"); + +LLMemType::DeclareMemType LLMemType::MTYPE_RENDER("Render"); +LLMemType::DeclareMemType LLMemType::MTYPE_SLEEP("Sleep"); + +LLMemType::DeclareMemType LLMemType::MTYPE_NETWORK("Network"); +LLMemType::DeclareMemType LLMemType::MTYPE_PHYSICS("Physics"); +LLMemType::DeclareMemType LLMemType::MTYPE_INTERESTLIST("InterestList"); + +LLMemType::DeclareMemType LLMemType::MTYPE_IMAGEBASE("ImageBase"); +LLMemType::DeclareMemType LLMemType::MTYPE_IMAGERAW("ImageRaw"); +LLMemType::DeclareMemType LLMemType::MTYPE_IMAGEFORMATTED("ImageFormatted"); +		 +LLMemType::DeclareMemType LLMemType::MTYPE_APPFMTIMAGE("AppFmtImage"); +LLMemType::DeclareMemType LLMemType::MTYPE_APPRAWIMAGE("AppRawImage"); +LLMemType::DeclareMemType LLMemType::MTYPE_APPAUXRAWIMAGE("AppAuxRawImage"); +		 +LLMemType::DeclareMemType LLMemType::MTYPE_DRAWABLE("Drawable"); + +LLMemType::DeclareMemType LLMemType::MTYPE_OBJECT("Object"); +LLMemType::DeclareMemType LLMemType::MTYPE_OBJECT_PROCESS_UPDATE("ObjectProcessUpdate"); +LLMemType::DeclareMemType LLMemType::MTYPE_OBJECT_PROCESS_UPDATE_CORE("ObjectProcessUpdateCore"); + +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY("Display"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_UPDATE("DisplayUpdate"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_UPDATE_CAMERA("DisplayUpdateCam"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_UPDATE_GEOM("DisplayUpdateGeom"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_SWAP("DisplaySwap"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_UPDATE_HUD("DisplayUpdateHud"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_GEN_REFLECTION("DisplayGenRefl"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_IMAGE_UPDATE("DisplayImageUpdate"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_STATE_SORT("DisplayStateSort"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_SKY("DisplaySky"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_RENDER_GEOM("DisplayRenderGeom"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_RENDER_FLUSH("DisplayRenderFlush"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_RENDER_UI("DisplayRenderUI"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_RENDER_ATTACHMENTS("DisplayRenderAttach"); + +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_DATA("VertexData"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_CONSTRUCTOR("VertexConstr"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_DESTRUCTOR("VertexDestr"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_CREATE_VERTICES("VertexCreateVerts"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_CREATE_INDICES("VertexCreateIndices"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_DESTROY_BUFFER("VertexDestroyBuff");	 +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_DESTROY_INDICES("VertexDestroyIndices"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_UPDATE_VERTS("VertexUpdateVerts"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_UPDATE_INDICES("VertexUpdateIndices"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_ALLOCATE_BUFFER("VertexAllocateBuffer"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_RESIZE_BUFFER("VertexResizeBuffer"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_MAP_BUFFER("VertexMapBuffer"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_MAP_BUFFER_VERTICES("VertexMapBufferVerts"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_MAP_BUFFER_INDICES("VertexMapBufferIndices"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_UNMAP_BUFFER("VertexUnmapBuffer"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_SET_STRIDE("VertexSetStride"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_SET_BUFFER("VertexSetBuffer"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_SETUP_VERTEX_BUFFER("VertexSetupVertBuff"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_CLEANUP_CLASS("VertexCleanupClass"); + +LLMemType::DeclareMemType LLMemType::MTYPE_SPACE_PARTITION("SpacePartition"); + +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE("Pipeline"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_INIT("PipelineInit"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_CREATE_BUFFERS("PipelineCreateBuffs"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RESTORE_GL("PipelineRestroGL"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_UNLOAD_SHADERS("PipelineUnloadShaders"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_LIGHTING_DETAIL("PipelineLightingDetail"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_GET_POOL_TYPE("PipelineGetPoolType"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_ADD_POOL("PipelineAddPool"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_ALLOCATE_DRAWABLE("PipelineAllocDrawable"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_ADD_OBJECT("PipelineAddObj"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_CREATE_OBJECTS("PipelineCreateObjs"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_UPDATE_MOVE("PipelineUpdateMove"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_UPDATE_GEOM("PipelineUpdateGeom"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_MARK_VISIBLE("PipelineMarkVisible"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_MARK_MOVED("PipelineMarkMoved"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_MARK_SHIFT("PipelineMarkShift"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_SHIFT_OBJECTS("PipelineShiftObjs"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_MARK_TEXTURED("PipelineMarkTextured"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_MARK_REBUILD("PipelineMarkRebuild"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_UPDATE_CULL("PipelineUpdateCull"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_STATE_SORT("PipelineStateSort"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_POST_SORT("PipelinePostSort"); +		 +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_HUD_ELS("PipelineHudEls"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_HL("PipelineRenderHL"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_GEOM("PipelineRenderGeom"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED("PipelineRenderGeomDef"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_GEOM_POST_DEF("PipelineRenderGeomPostDef"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_GEOM_SHADOW("PipelineRenderGeomShadow"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_SELECT("PipelineRenderSelect"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_REBUILD_POOLS("PipelineRebuildPools"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_QUICK_LOOKUP("PipelineQuickLookup"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_OBJECTS("PipelineRenderObjs"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_GENERATE_IMPOSTOR("PipelineGenImpostors"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_BLOOM("PipelineRenderBloom"); + +LLMemType::DeclareMemType LLMemType::MTYPE_UPKEEP_POOLS("UpkeepPools"); + +LLMemType::DeclareMemType LLMemType::MTYPE_AVATAR("Avatar"); +LLMemType::DeclareMemType LLMemType::MTYPE_AVATAR_MESH("AvatarMesh"); +LLMemType::DeclareMemType LLMemType::MTYPE_PARTICLES("Particles"); +LLMemType::DeclareMemType LLMemType::MTYPE_REGIONS("Regions"); + +LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY("Inventory"); +LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_DRAW("InventoryDraw"); +LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_BUILD_NEW_VIEWS("InventoryBuildNewViews"); +LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_DO_FOLDER("InventoryDoFolder"); +LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_POST_BUILD("InventoryPostBuild"); +LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_FROM_XML("InventoryFromXML"); +LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_CREATE_NEW_ITEM("InventoryCreateNewItem"); +LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_VIEW_INIT("InventoryViewInit"); +LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_VIEW_SHOW("InventoryViewShow"); +LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_VIEW_TOGGLE("InventoryViewToggle"); + +LLMemType::DeclareMemType LLMemType::MTYPE_ANIMATION("Animation"); +LLMemType::DeclareMemType LLMemType::MTYPE_VOLUME("Volume"); +LLMemType::DeclareMemType LLMemType::MTYPE_PRIMITIVE("Primitive"); +		 +LLMemType::DeclareMemType LLMemType::MTYPE_SCRIPT("Script"); +LLMemType::DeclareMemType LLMemType::MTYPE_SCRIPT_RUN("ScriptRun"); +LLMemType::DeclareMemType LLMemType::MTYPE_SCRIPT_BYTECODE("ScriptByteCode"); +		 +LLMemType::DeclareMemType LLMemType::MTYPE_IO_PUMP("IoPump"); +LLMemType::DeclareMemType LLMemType::MTYPE_IO_TCP("IoTCP"); +LLMemType::DeclareMemType LLMemType::MTYPE_IO_BUFFER("IoBuffer"); +LLMemType::DeclareMemType LLMemType::MTYPE_IO_HTTP_SERVER("IoHttpServer"); +LLMemType::DeclareMemType LLMemType::MTYPE_IO_SD_SERVER("IoSDServer"); +LLMemType::DeclareMemType LLMemType::MTYPE_IO_SD_CLIENT("IoSDClient"); +LLMemType::DeclareMemType LLMemType::MTYPE_IO_URL_REQUEST("IOUrlRequest"); + +LLMemType::DeclareMemType LLMemType::MTYPE_DIRECTX_INIT("DirectXInit"); + +LLMemType::DeclareMemType LLMemType::MTYPE_TEMP1("Temp1"); +LLMemType::DeclareMemType LLMemType::MTYPE_TEMP2("Temp2"); +LLMemType::DeclareMemType LLMemType::MTYPE_TEMP3("Temp3"); +LLMemType::DeclareMemType LLMemType::MTYPE_TEMP4("Temp4"); +LLMemType::DeclareMemType LLMemType::MTYPE_TEMP5("Temp5"); +LLMemType::DeclareMemType LLMemType::MTYPE_TEMP6("Temp6"); +LLMemType::DeclareMemType LLMemType::MTYPE_TEMP7("Temp7"); +LLMemType::DeclareMemType LLMemType::MTYPE_TEMP8("Temp8"); +LLMemType::DeclareMemType LLMemType::MTYPE_TEMP9("Temp9"); + +LLMemType::DeclareMemType LLMemType::MTYPE_OTHER("Other"); + + +LLMemType::DeclareMemType::DeclareMemType(char const * st) +{ +	mID = (S32)mNameList.size(); +	mName = st; + +	mNameList.push_back(mName); +} + +LLMemType::DeclareMemType::~DeclareMemType() +{ +} + +LLMemType::LLMemType(LLMemType::DeclareMemType& dt) +{ +	mTypeIndex = dt.mID; +	LLAllocator::pushMemType(dt.mID); +} + +LLMemType::~LLMemType() +{ +	LLAllocator::popMemType(); +} + +char const * LLMemType::getNameFromID(S32 id) +{ +	if (id < 0 || id >= (S32)DeclareMemType::mNameList.size()) +	{ +		return "INVALID"; +	} + +	return DeclareMemType::mNameList[id]; +} + diff --git a/indra/llcommon/llmemtype.h b/indra/llcommon/llmemtype.h index a9ebc2062f..12310fcdb4 100644 --- a/indra/llcommon/llmemtype.h +++ b/indra/llcommon/llmemtype.h @@ -36,128 +36,210 @@  //----------------------------------------------------------------------------  //---------------------------------------------------------------------------- -class LLMemType; - -extern void* ll_allocate (size_t size); -extern void ll_release (void *p); +//---------------------------------------------------------------------------- -#define MEM_TRACK_MEM 0 -#define MEM_TRACK_TYPE (1 && MEM_TRACK_MEM) +#include "linden_common.h" +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// WARNING: Never commit with MEM_TRACK_MEM == 1 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +#define MEM_TRACK_MEM (0 && LL_WINDOWS) -#if MEM_TRACK_TYPE -#define MEM_DUMP_DATA 1 -#define MEM_TYPE_NEW(T) \ -static void* operator new(size_t s) { LLMemType mt(T); return ll_allocate(s); } \ -static void  operator delete(void* p) { ll_release(p); } +#include <vector> -#else  #define MEM_TYPE_NEW(T) -#endif // MEM_TRACK_TYPE - - -//----------------------------------------------------------------------------  class LLMemType  {  public: -	// Also update sTypeDesc in llmemory.cpp -	enum EMemType -	{ -		MTYPE_INIT, -		MTYPE_STARTUP, -		MTYPE_MAIN, -		MTYPE_IMAGEBASE, -		MTYPE_IMAGERAW, -		MTYPE_IMAGEFORMATTED, -		 -		MTYPE_APPFMTIMAGE, -		MTYPE_APPRAWIMAGE, -		MTYPE_APPAUXRAWIMAGE, -		 -		MTYPE_DRAWABLE, -		MTYPE_OBJECT, -		MTYPE_VERTEX_DATA, -		MTYPE_SPACE_PARTITION, -		MTYPE_PIPELINE, -		MTYPE_AVATAR, -		MTYPE_AVATAR_MESH, -		MTYPE_PARTICLES, -		MTYPE_REGIONS, -		MTYPE_INVENTORY, -		MTYPE_ANIMATION, -		MTYPE_VOLUME, -		MTYPE_PRIMITIVE, - -		MTYPE_NETWORK, -		MTYPE_PHYSICS, -		MTYPE_INTERESTLIST, -		 -		MTYPE_SCRIPT, -		MTYPE_SCRIPT_RUN, -		MTYPE_SCRIPT_BYTECODE, -		 -		MTYPE_IO_PUMP, -		MTYPE_IO_TCP, -		MTYPE_IO_BUFFER, -		MTYPE_IO_HTTP_SERVER, -		MTYPE_IO_SD_SERVER, -		MTYPE_IO_SD_CLIENT, -		MTYPE_IO_URL_REQUEST, - -		MTYPE_TEMP1, -		MTYPE_TEMP2, -		MTYPE_TEMP3, -		MTYPE_TEMP4, -		MTYPE_TEMP5, -		MTYPE_TEMP6, -		MTYPE_TEMP7, -		MTYPE_TEMP8, -		MTYPE_TEMP9, - -		MTYPE_OTHER, // Special, used by display code +	// class we'll initialize all instances of as +	// static members of MemType.  Then use +	// to construct any new mem type. +	class DeclareMemType +	{ +	public: +		DeclareMemType(char const * st); +		~DeclareMemType(); +	 +		S32 mID; +		char const * mName; -		MTYPE_NUM_TYPES +		// array so we can map an index ID to Name +		static std::vector<char const *> mNameList;  	}; -	enum { MTYPE_MAX_DEPTH = 64 }; -	 -public: -	LLMemType(EMemType type) -	{ -#if MEM_TRACK_TYPE -		if (type < 0 || type >= MTYPE_NUM_TYPES) -			llerrs << "LLMemType error" << llendl; -		if (sCurDepth < 0 || sCurDepth >= MTYPE_MAX_DEPTH) -			llerrs << "LLMemType error" << llendl; -		sType[sCurDepth] = sCurType; -		sCurDepth++; -		sCurType = type; -#endif -	} -	~LLMemType() -	{ -#if MEM_TRACK_TYPE -		sCurDepth--; -		sCurType = sType[sCurDepth]; -#endif -	} -	static void reset(); -	static void printMem(); +	LLMemType(DeclareMemType& dt); +	~LLMemType(); + +	static char const * getNameFromID(S32 id); + +	static DeclareMemType MTYPE_INIT; +	static DeclareMemType MTYPE_STARTUP; +	static DeclareMemType MTYPE_MAIN; +	static DeclareMemType MTYPE_FRAME; + +	static DeclareMemType MTYPE_GATHER_INPUT; +	static DeclareMemType MTYPE_JOY_KEY; + +	static DeclareMemType MTYPE_IDLE; +	static DeclareMemType MTYPE_IDLE_PUMP; +	static DeclareMemType MTYPE_IDLE_NETWORK; +	static DeclareMemType MTYPE_IDLE_UPDATE_REGIONS; +	static DeclareMemType MTYPE_IDLE_UPDATE_VIEWER_REGION; +	static DeclareMemType MTYPE_IDLE_UPDATE_SURFACE; +	static DeclareMemType MTYPE_IDLE_UPDATE_PARCEL_OVERLAY; +	static DeclareMemType MTYPE_IDLE_AUDIO; + +	static DeclareMemType MTYPE_CACHE_PROCESS_PENDING; +	static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_ASKS; +	static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_REPLIES; + +	static DeclareMemType MTYPE_MESSAGE_CHECK_ALL; +	static DeclareMemType MTYPE_MESSAGE_PROCESS_ACKS; + +	static DeclareMemType MTYPE_RENDER; +	static DeclareMemType MTYPE_SLEEP; + +	static DeclareMemType MTYPE_NETWORK; +	static DeclareMemType MTYPE_PHYSICS; +	static DeclareMemType MTYPE_INTERESTLIST; + +	static DeclareMemType MTYPE_IMAGEBASE; +	static DeclareMemType MTYPE_IMAGERAW; +	static DeclareMemType MTYPE_IMAGEFORMATTED; -public: -#if MEM_TRACK_TYPE -	static S32 sCurDepth; -	static S32 sCurType; -	static S32 sType[MTYPE_MAX_DEPTH]; -	static S32 sMemCount[MTYPE_NUM_TYPES]; -	static S32 sMaxMemCount[MTYPE_NUM_TYPES]; -	static S32 sNewCount[MTYPE_NUM_TYPES]; -	static S32 sOverheadMem; -	static const char* sTypeDesc[MTYPE_NUM_TYPES]; -#endif -	static S32 sTotalMem; -	static S32 sMaxTotalMem; +	static DeclareMemType MTYPE_APPFMTIMAGE; +	static DeclareMemType MTYPE_APPRAWIMAGE; +	static DeclareMemType MTYPE_APPAUXRAWIMAGE; +	 +	static DeclareMemType MTYPE_DRAWABLE; +	 +	static DeclareMemType MTYPE_OBJECT; +	static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE; +	static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE_CORE; + +	static DeclareMemType MTYPE_DISPLAY; +	static DeclareMemType MTYPE_DISPLAY_UPDATE; +	static DeclareMemType MTYPE_DISPLAY_UPDATE_CAMERA; +	static DeclareMemType MTYPE_DISPLAY_UPDATE_GEOM; +	static DeclareMemType MTYPE_DISPLAY_SWAP; +	static DeclareMemType MTYPE_DISPLAY_UPDATE_HUD; +	static DeclareMemType MTYPE_DISPLAY_GEN_REFLECTION; +	static DeclareMemType MTYPE_DISPLAY_IMAGE_UPDATE; +	static DeclareMemType MTYPE_DISPLAY_STATE_SORT; +	static DeclareMemType MTYPE_DISPLAY_SKY; +	static DeclareMemType MTYPE_DISPLAY_RENDER_GEOM; +	static DeclareMemType MTYPE_DISPLAY_RENDER_FLUSH; +	static DeclareMemType MTYPE_DISPLAY_RENDER_UI; +	static DeclareMemType MTYPE_DISPLAY_RENDER_ATTACHMENTS; + +	static DeclareMemType MTYPE_VERTEX_DATA; +	static DeclareMemType MTYPE_VERTEX_CONSTRUCTOR; +	static DeclareMemType MTYPE_VERTEX_DESTRUCTOR; +	static DeclareMemType MTYPE_VERTEX_CREATE_VERTICES; +	static DeclareMemType MTYPE_VERTEX_CREATE_INDICES; +	static DeclareMemType MTYPE_VERTEX_DESTROY_BUFFER;	 +	static DeclareMemType MTYPE_VERTEX_DESTROY_INDICES; +	static DeclareMemType MTYPE_VERTEX_UPDATE_VERTS; +	static DeclareMemType MTYPE_VERTEX_UPDATE_INDICES; +	static DeclareMemType MTYPE_VERTEX_ALLOCATE_BUFFER; +	static DeclareMemType MTYPE_VERTEX_RESIZE_BUFFER; +	static DeclareMemType MTYPE_VERTEX_MAP_BUFFER; +	static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_VERTICES; +	static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_INDICES; +	static DeclareMemType MTYPE_VERTEX_UNMAP_BUFFER; +	static DeclareMemType MTYPE_VERTEX_SET_STRIDE; +	static DeclareMemType MTYPE_VERTEX_SET_BUFFER; +	static DeclareMemType MTYPE_VERTEX_SETUP_VERTEX_BUFFER; +	static DeclareMemType MTYPE_VERTEX_CLEANUP_CLASS; + +	static DeclareMemType MTYPE_SPACE_PARTITION; + +	static DeclareMemType MTYPE_PIPELINE; +	static DeclareMemType MTYPE_PIPELINE_INIT; +	static DeclareMemType MTYPE_PIPELINE_CREATE_BUFFERS; +	static DeclareMemType MTYPE_PIPELINE_RESTORE_GL; +	static DeclareMemType MTYPE_PIPELINE_UNLOAD_SHADERS; +	static DeclareMemType MTYPE_PIPELINE_LIGHTING_DETAIL; +	static DeclareMemType MTYPE_PIPELINE_GET_POOL_TYPE; +	static DeclareMemType MTYPE_PIPELINE_ADD_POOL; +	static DeclareMemType MTYPE_PIPELINE_ALLOCATE_DRAWABLE; +	static DeclareMemType MTYPE_PIPELINE_ADD_OBJECT; +	static DeclareMemType MTYPE_PIPELINE_CREATE_OBJECTS; +	static DeclareMemType MTYPE_PIPELINE_UPDATE_MOVE; +	static DeclareMemType MTYPE_PIPELINE_UPDATE_GEOM; +	static DeclareMemType MTYPE_PIPELINE_MARK_VISIBLE; +	static DeclareMemType MTYPE_PIPELINE_MARK_MOVED; +	static DeclareMemType MTYPE_PIPELINE_MARK_SHIFT; +	static DeclareMemType MTYPE_PIPELINE_SHIFT_OBJECTS; +	static DeclareMemType MTYPE_PIPELINE_MARK_TEXTURED; +	static DeclareMemType MTYPE_PIPELINE_MARK_REBUILD; +	static DeclareMemType MTYPE_PIPELINE_UPDATE_CULL; +	static DeclareMemType MTYPE_PIPELINE_STATE_SORT; +	static DeclareMemType MTYPE_PIPELINE_POST_SORT; +	 +	static DeclareMemType MTYPE_PIPELINE_RENDER_HUD_ELS; +	static DeclareMemType MTYPE_PIPELINE_RENDER_HL; +	static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM; +	static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED; +	static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_POST_DEF; +	static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_SHADOW; +	static DeclareMemType MTYPE_PIPELINE_RENDER_SELECT; +	static DeclareMemType MTYPE_PIPELINE_REBUILD_POOLS; +	static DeclareMemType MTYPE_PIPELINE_QUICK_LOOKUP; +	static DeclareMemType MTYPE_PIPELINE_RENDER_OBJECTS; +	static DeclareMemType MTYPE_PIPELINE_GENERATE_IMPOSTOR; +	static DeclareMemType MTYPE_PIPELINE_RENDER_BLOOM; + +	static DeclareMemType MTYPE_UPKEEP_POOLS; + +	static DeclareMemType MTYPE_AVATAR; +	static DeclareMemType MTYPE_AVATAR_MESH; +	static DeclareMemType MTYPE_PARTICLES; +	static DeclareMemType MTYPE_REGIONS; + +	static DeclareMemType MTYPE_INVENTORY; +	static DeclareMemType MTYPE_INVENTORY_DRAW; +	static DeclareMemType MTYPE_INVENTORY_BUILD_NEW_VIEWS; +	static DeclareMemType MTYPE_INVENTORY_DO_FOLDER; +	static DeclareMemType MTYPE_INVENTORY_POST_BUILD; +	static DeclareMemType MTYPE_INVENTORY_FROM_XML; +	static DeclareMemType MTYPE_INVENTORY_CREATE_NEW_ITEM; +	static DeclareMemType MTYPE_INVENTORY_VIEW_INIT; +	static DeclareMemType MTYPE_INVENTORY_VIEW_SHOW; +	static DeclareMemType MTYPE_INVENTORY_VIEW_TOGGLE; + +	static DeclareMemType MTYPE_ANIMATION; +	static DeclareMemType MTYPE_VOLUME; +	static DeclareMemType MTYPE_PRIMITIVE; +	 +	static DeclareMemType MTYPE_SCRIPT; +	static DeclareMemType MTYPE_SCRIPT_RUN; +	static DeclareMemType MTYPE_SCRIPT_BYTECODE; +	 +	static DeclareMemType MTYPE_IO_PUMP; +	static DeclareMemType MTYPE_IO_TCP; +	static DeclareMemType MTYPE_IO_BUFFER; +	static DeclareMemType MTYPE_IO_HTTP_SERVER; +	static DeclareMemType MTYPE_IO_SD_SERVER; +	static DeclareMemType MTYPE_IO_SD_CLIENT; +	static DeclareMemType MTYPE_IO_URL_REQUEST; + +	static DeclareMemType MTYPE_DIRECTX_INIT; + +	static DeclareMemType MTYPE_TEMP1; +	static DeclareMemType MTYPE_TEMP2; +	static DeclareMemType MTYPE_TEMP3; +	static DeclareMemType MTYPE_TEMP4; +	static DeclareMemType MTYPE_TEMP5; +	static DeclareMemType MTYPE_TEMP6; +	static DeclareMemType MTYPE_TEMP7; +	static DeclareMemType MTYPE_TEMP8; +	static DeclareMemType MTYPE_TEMP9; + +	static DeclareMemType MTYPE_OTHER; // Special; used by display code + +	S32 mTypeIndex;  };  //---------------------------------------------------------------------------- diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h new file mode 100644 index 0000000000..2c37eadcc6 --- /dev/null +++ b/indra/llcommon/llpointer.h @@ -0,0 +1,177 @@ +/**  + * @file llpointer.h + * @brief A reference-counted pointer for objects derived from LLRefCount + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + *  + * Copyright (c) 2002-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#ifndef LLPOINTER_H +#define LLPOINTER_H + +#include "llerror.h"	// *TODO: consider eliminating this + +//---------------------------------------------------------------------------- +// RefCount objects should generally only be accessed by way of LLPointer<>'s +// NOTE: LLPointer<LLFoo> x = new LLFoo(); MAY NOT BE THREAD SAFE +//   if LLFoo::LLFoo() does anything like put itself in an update queue. +//   The queue may get accessed before it gets assigned to x. +// The correct implementation is: +//   LLPointer<LLFoo> x = new LLFoo; // constructor does not do anything interesting +//   x->instantiate(); // does stuff like place x into an update queue + +// see llthread.h for LLThreadSafeRefCount + +//---------------------------------------------------------------------------- + +// Note: relies on Type having ref() and unref() methods +template <class Type> class LLPointer +{ +public: + +	LLPointer() :  +		mPointer(NULL) +	{ +	} + +	LLPointer(Type* ptr) :  +		mPointer(ptr) +	{ +		ref(); +	} + +	LLPointer(const LLPointer<Type>& ptr) :  +		mPointer(ptr.mPointer) +	{ +		ref(); +	} + +	// support conversion up the type hierarchy.  See Item 45 in Effective C++, 3rd Ed. +	template<typename Subclass> +	LLPointer(const LLPointer<Subclass>& ptr) :  +		mPointer(ptr.get()) +	{ +		ref(); +	} + +	~LLPointer()								 +	{ +		unref(); +	} + +	Type*	get() const							{ return mPointer; } +	const Type*	operator->() const				{ return mPointer; } +	Type*	operator->()						{ return mPointer; } +	const Type&	operator*() const				{ return *mPointer; } +	Type&	operator*()							{ return *mPointer; } + +	operator BOOL()  const						{ return (mPointer != NULL); } +	operator bool()  const						{ return (mPointer != NULL); } +	bool operator!() const						{ return (mPointer == NULL); } +	bool isNull() const							{ return (mPointer == NULL); } +	bool notNull() const						{ return (mPointer != NULL); } + +	operator Type*()       const				{ return mPointer; } +	operator const Type*() const				{ return mPointer; } +	bool operator !=(Type* ptr) const           { return (mPointer != ptr); 	} +	bool operator ==(Type* ptr) const           { return (mPointer == ptr); 	} +	bool operator ==(const LLPointer<Type>& ptr) const           { return (mPointer == ptr.mPointer); 	} +	bool operator < (const LLPointer<Type>& ptr) const           { return (mPointer < ptr.mPointer); 	} +	bool operator > (const LLPointer<Type>& ptr) const           { return (mPointer > ptr.mPointer); 	} + +	LLPointer<Type>& operator =(Type* ptr)                    +	{  +		if( mPointer != ptr ) +		{ +			unref();  +			mPointer = ptr;  +			ref(); +		} + +		return *this;  +	} + +	LLPointer<Type>& operator =(const LLPointer<Type>& ptr)   +	{  +		if( mPointer != ptr.mPointer ) +		{ +			unref();  +			mPointer = ptr.mPointer; +			ref(); +		} +		return *this;  +	} + +	// support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. +	template<typename Subclass> +	LLPointer<Type>& operator =(const LLPointer<Subclass>& ptr)   +	{  +		if( mPointer != ptr.get() ) +		{ +			unref();  +			mPointer = ptr.get(); +			ref(); +		} +		return *this;  +	} +	 +	// Just exchange the pointers, which will not change the reference counts. +	static void swap(LLPointer<Type>& a, LLPointer<Type>& b) +	{ +		Type* temp = a.mPointer; +		a.mPointer = b.mPointer; +		b.mPointer = temp; +	} + +protected: +	void ref()                              +	{  +		if (mPointer) +		{ +			mPointer->ref(); +		} +	} + +	void unref() +	{ +		if (mPointer) +		{ +			Type *tempp = mPointer; +			mPointer = NULL; +			tempp->unref(); +			if (mPointer != NULL) +			{ +				llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl; +				unref(); +			} +		} +	} + +protected: +	Type*	mPointer; +}; + +#endif diff --git a/indra/llcommon/llptrto.cpp b/indra/llcommon/llptrto.cpp new file mode 100644 index 0000000000..ce93f09489 --- /dev/null +++ b/indra/llcommon/llptrto.cpp @@ -0,0 +1,108 @@ +/** + * @file   llptrto.cpp + * @author Nat Goodspeed + * @date   2008-08-20 + * @brief  Test for llptrto.h + *  + * $LicenseInfo:firstyear=2008&license=viewergpl$ + *  + * Copyright (c) 2008-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "llptrto.h" +// STL headers +// std headers +// external library headers +#include <boost/type_traits/is_same.hpp> +#include <boost/static_assert.hpp> +// other Linden headers +#include "llmemory.h" + +// a refcounted class +class RCFoo: public LLRefCount +{ +public: +    RCFoo() {} +}; + +// a refcounted subclass +class RCSubFoo: public RCFoo +{ +public: +    RCSubFoo() {} +}; + +// a refcounted class using the other refcount base class +class TSRCFoo: public LLThreadSafeRefCount +{ +public: +    TSRCFoo() {} +}; + +// a non-refcounted class +class Bar +{ +public: +    Bar() {} +}; + +// a non-refcounted subclass +class SubBar: public Bar +{ +public: +    SubBar() {} +}; + +int main(int argc, char *argv[]) +{ +    // test LLPtrTo<> +    BOOST_STATIC_ASSERT((boost::is_same<LLPtrTo<RCFoo>::type, LLPointer<RCFoo> >::value)); +    BOOST_STATIC_ASSERT((boost::is_same<LLPtrTo<RCSubFoo>::type, LLPointer<RCSubFoo> >::value)); +    BOOST_STATIC_ASSERT((boost::is_same<LLPtrTo<TSRCFoo>::type, LLPointer<TSRCFoo> >::value)); +    BOOST_STATIC_ASSERT((boost::is_same<LLPtrTo<Bar>::type, Bar*>::value)); +    BOOST_STATIC_ASSERT((boost::is_same<LLPtrTo<SubBar>::type, SubBar*>::value)); +    BOOST_STATIC_ASSERT((boost::is_same<LLPtrTo<int>::type, int*>::value)); + +    // Test LLRemovePointer<>. Note that we remove both pointer variants from +    // each kind of type, regardless of whether the variant makes sense. +    BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer<RCFoo*>::type, RCFoo>::value)); +    BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer< LLPointer<RCFoo> >::type, RCFoo>::value)); +    BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer<RCSubFoo*>::type, RCSubFoo>::value)); +    BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer< LLPointer<RCSubFoo> >::type, RCSubFoo>::value)); +    BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer<TSRCFoo*>::type, TSRCFoo>::value)); +    BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer< LLPointer<TSRCFoo> >::type, TSRCFoo>::value)); +    BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer<Bar*>::type, Bar>::value)); +    BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer< LLPointer<Bar> >::type, Bar>::value)); +    BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer<SubBar*>::type, SubBar>::value)); +    BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer< LLPointer<SubBar> >::type, SubBar>::value)); +    BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer<int*>::type, int>::value)); +    BOOST_STATIC_ASSERT((boost::is_same<LLRemovePointer< LLPointer<int> >::type, int>::value)); + +    return 0; +} diff --git a/indra/llcommon/llptrto.h b/indra/llcommon/llptrto.h new file mode 100644 index 0000000000..74c117a7f6 --- /dev/null +++ b/indra/llcommon/llptrto.h @@ -0,0 +1,93 @@ +/** + * @file   llptrto.h + * @author Nat Goodspeed + * @date   2008-08-19 + * @brief  LLPtrTo<TARGET> is a template helper to pick either TARGET* or -- when + *         TARGET is a subclass of LLRefCount or LLThreadSafeRefCount -- + *         LLPointer<TARGET>. LLPtrTo<> chooses whichever pointer type is best. + *  + * $LicenseInfo:firstyear=2008&license=viewergpl$ + *  + * Copyright (c) 2008-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLPTRTO_H) +#define LL_LLPTRTO_H + +#include "llpointer.h" +#include "llrefcount.h"             // LLRefCount +#include "llthread.h"               // LLThreadSafeRefCount +#include <boost/type_traits/is_base_of.hpp> +#include <boost/type_traits/remove_pointer.hpp> +#include <boost/utility/enable_if.hpp> + +/** + * LLPtrTo<TARGET>::type is either of two things: + * + * * When TARGET is a subclass of either LLRefCount or LLThreadSafeRefCount, + *   LLPtrTo<TARGET>::type is LLPointer<TARGET>. + * * Otherwise, LLPtrTo<TARGET>::type is TARGET*. + * + * This way, a class template can use LLPtrTo<TARGET>::type to select an + * appropriate pointer type to store. + */ +template <class T, class ENABLE=void> +struct LLPtrTo +{ +    typedef T* type; +}; + +/// specialize for subclasses of LLRefCount +template <class T> +struct LLPtrTo<T, typename boost::enable_if< boost::is_base_of<LLRefCount, T> >::type> +{ +    typedef LLPointer<T> type; +}; + +/// specialize for subclasses of LLThreadSafeRefCount +template <class T> +struct LLPtrTo<T, typename boost::enable_if< boost::is_base_of<LLThreadSafeRefCount, T> >::type> +{ +    typedef LLPointer<T> type; +}; + +/** + * LLRemovePointer<PTRTYPE>::type gets you the underlying (pointee) type. + */ +template <typename PTRTYPE> +struct LLRemovePointer +{ +    typedef typename boost::remove_pointer<PTRTYPE>::type type; +}; + +/// specialize for LLPointer<SOMECLASS> +template <typename SOMECLASS> +struct LLRemovePointer< LLPointer<SOMECLASS> > +{ +    typedef SOMECLASS type; +}; + +#endif /* ! defined(LL_LLPTRTO_H) */ diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp index cd53e701d2..3db5c36545 100644 --- a/indra/llcommon/llqueuedthread.cpp +++ b/indra/llcommon/llqueuedthread.cpp @@ -31,7 +31,9 @@  #include "linden_common.h"  #include "llqueuedthread.h" +  #include "llstl.h" +#include "lltimer.h"	// ms_sleep()  //============================================================================ diff --git a/indra/llcommon/llrefcount.cpp b/indra/llcommon/llrefcount.cpp new file mode 100644 index 0000000000..33b6875fb0 --- /dev/null +++ b/indra/llcommon/llrefcount.cpp @@ -0,0 +1,49 @@ +/**  + * @file llrefcount.cpp + * @brief Base class for reference counted objects for use with LLPointer + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + *  + * Copyright (c) 2002-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#include "linden_common.h" + +#include "llrefcount.h" + +#include "llerror.h" + +LLRefCount::LLRefCount() : +	mRef(0) +{ +} + +LLRefCount::~LLRefCount() +{  +	if (mRef != 0) +	{ +		llerrs << "deleting non-zero reference" << llendl; +	} +} diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h new file mode 100644 index 0000000000..540a18b8a0 --- /dev/null +++ b/indra/llcommon/llrefcount.h @@ -0,0 +1,78 @@ +/**  + * @file llrefcount.h + * @brief Base class for reference counted objects for use with LLPointer + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + *  + * Copyright (c) 2002-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#ifndef LLREFCOUNT_H +#define LLREFCOUNT_H + +//---------------------------------------------------------------------------- +// RefCount objects should generally only be accessed by way of LLPointer<>'s +// see llthread.h for LLThreadSafeRefCount +//---------------------------------------------------------------------------- + +class LLRefCount +{ +protected: +	LLRefCount(const LLRefCount&); // not implemented +private: +	LLRefCount&operator=(const LLRefCount&); // not implemented + +protected: +	virtual ~LLRefCount(); // use unref() +	 +public: +	LLRefCount(); + +	void ref() +	{  +		mRef++;  +	}  + +	S32 unref() +	{ +		llassert(mRef >= 1); +		if (0 == --mRef)  +		{ +			delete this;  +			return 0; +		} +		return mRef; +	}	 + +	S32 getNumRefs() const +	{ +		return mRef; +	} + +private:  +	S32	mRef;  +}; + +#endif diff --git a/indra/llcommon/llsafehandle.h b/indra/llcommon/llsafehandle.h new file mode 100644 index 0000000000..1f7c682fd1 --- /dev/null +++ b/indra/llcommon/llsafehandle.h @@ -0,0 +1,167 @@ +/**  + * @file llsafehandle.h + * @brief Reference-counted object where Object() is valid, not NULL. + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + *  + * Copyright (c) 2002-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#ifndef LLSAFEHANDLE_H +#define LLSAFEHANDLE_H + +#include "llerror.h"	// *TODO: consider eliminating this + +// Expands LLPointer to return a pointer to a special instance of class Type instead of NULL. +// This is useful in instances where operations on NULL pointers are semantically safe and/or +// when error checking occurs at a different granularity or in a different part of the code +// than when referencing an object via a LLSafeHandle. + +template <class Type>  +class LLSafeHandle +{ +public: +	LLSafeHandle() : +		mPointer(NULL) +	{ +	} + +	LLSafeHandle(Type* ptr) :  +		mPointer(NULL) +	{ +		assign(ptr); +	} + +	LLSafeHandle(const LLSafeHandle<Type>& ptr) :  +		mPointer(NULL) +	{ +		assign(ptr.mPointer); +	} + +	// support conversion up the type hierarchy.  See Item 45 in Effective C++, 3rd Ed. +	template<typename Subclass> +	LLSafeHandle(const LLSafeHandle<Subclass>& ptr) :  +		mPointer(NULL) +	{ +		assign(ptr.get()); +	} + +	~LLSafeHandle()								 +	{ +		unref(); +	} + +	const Type*	operator->() const				{ return nonNull(mPointer); } +	Type*	operator->()						{ return nonNull(mPointer); } + +	Type*	get() const							{ return mPointer; } +	// we disallow these operations as they expose our null objects to direct manipulation +	// and bypass the reference counting semantics +	//const Type&	operator*() const			{ return *nonNull(mPointer); } +	//Type&	operator*()							{ return *nonNull(mPointer); } + +	operator BOOL()  const						{ return mPointer != NULL; } +	operator bool()  const						{ return mPointer != NULL; } +	bool operator!() const						{ return mPointer == NULL; } +	bool isNull() const							{ return mPointer == NULL; } +	bool notNull() const						{ return mPointer != NULL; } + + +	operator Type*()       const				{ return mPointer; } +	operator const Type*() const				{ return mPointer; } +	bool operator !=(Type* ptr) const           { return (mPointer != ptr); 	} +	bool operator ==(Type* ptr) const           { return (mPointer == ptr); 	} +	bool operator ==(const LLSafeHandle<Type>& ptr) const           { return (mPointer == ptr.mPointer); 	} +	bool operator < (const LLSafeHandle<Type>& ptr) const           { return (mPointer < ptr.mPointer); 	} +	bool operator > (const LLSafeHandle<Type>& ptr) const           { return (mPointer > ptr.mPointer); 	} + +	LLSafeHandle<Type>& operator =(Type* ptr)                    +	{  +		assign(ptr); +		return *this;  +	} + +	LLSafeHandle<Type>& operator =(const LLSafeHandle<Type>& ptr)   +	{  +		assign(ptr.mPointer); +		return *this;  +	} + +	// support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. +	template<typename Subclass> +	LLSafeHandle<Type>& operator =(const LLSafeHandle<Subclass>& ptr)   +	{  +		assign(ptr.get()); +		return *this;  +	} + +public: +	typedef Type* (*NullFunc)(); +	static const NullFunc sNullFunc; + +protected: +	void ref()                              +	{  +		if (mPointer) +		{ +			mPointer->ref(); +		} +	} + +	void unref() +	{ +		if (mPointer) +		{ +			Type *tempp = mPointer; +			mPointer = NULL; +			tempp->unref(); +			if (mPointer != NULL) +			{ +				llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl; +				unref(); +			} +		} +	} + +	void assign(Type* ptr) +	{ +		if( mPointer != ptr ) +		{ +			unref();  +			mPointer = ptr;  +			ref(); +		} +	} + +	static Type* nonNull(Type* ptr) +	{ +		return ptr == NULL ? sNullFunc() : ptr; +	} + +protected: +	Type*	mPointer; +}; + +#endif diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index 7a66d70d3f..cf337be161 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -34,7 +34,7 @@  #include "linden_common.h"  #include "llsdserialize.h" -#include "llmemory.h" +#include "llpointer.h"  #include "llstreamtools.h" // for fullread  #include <iostream> diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h index bb38b75d8f..7463d1e5dd 100644 --- a/indra/llcommon/llsdserialize.h +++ b/indra/llcommon/llsdserialize.h @@ -36,8 +36,9 @@  #define LL_LLSDSERIALIZE_H  #include <iosfwd> +#include "llpointer.h" +#include "llrefcount.h"  #include "llsd.h" -#include "llmemory.h"  /**    * @class LLSDParser diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp index aa0e0f3696..0202a033c3 100644 --- a/indra/llcommon/llsdutil.cpp +++ b/indra/llcommon/llsdutil.cpp @@ -171,6 +171,15 @@ char* ll_print_sd(const LLSD& sd)  	return buffer;  } +char* ll_pretty_print_sd_ptr(const LLSD* sd) +{ +	if (sd) +	{ +		return ll_pretty_print_sd(*sd); +	} +	return NULL; +} +  char* ll_pretty_print_sd(const LLSD& sd)  {  	const U32 bufferSize = 10 * 1024; diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h index b67ad521ea..501600f1d9 100644 --- a/indra/llcommon/llsdutil.h +++ b/indra/llcommon/llsdutil.h @@ -89,6 +89,7 @@ LLSD ll_binary_from_string(const LLSD& sd);  char* ll_print_sd(const LLSD& sd);  // Serializes sd to static buffer and returns pointer, using "pretty printing" mode. +char* ll_pretty_print_sd_ptr(const LLSD* sd);  char* ll_pretty_print_sd(const LLSD& sd);  //compares the structure of an LLSD to a template LLSD and stores the diff --git a/indra/llcommon/llsecondlifeurls.cpp b/indra/llcommon/llsecondlifeurls.cpp index 36d8e8870f..6323d9d36b 100644 --- a/indra/llcommon/llsecondlifeurls.cpp +++ b/indra/llcommon/llsecondlifeurls.cpp @@ -32,57 +32,59 @@  #include "linden_common.h"  #include "llsecondlifeurls.h" - +/*  const std::string CREATE_ACCOUNT_URL (   	"http://secondlife.com/registration/");  const std::string MANAGE_ACCOUNT (  -	"http://secondlife.com/account/"); +	"http://secondlife.com/account/");  // *TODO: NOT USED  const std::string AUCTION_URL (   	"http://secondlife.com/auctions/auction-detail.php?id=");  const std::string EVENTS_URL (   	"http://secondlife.com/events/"); - +*/  const std::string TIER_UP_URL (  -	"http://secondlife.com/app/landtier"); +	"http://secondlife.com/app/landtier"); // *TODO: Translate (simulator) +const std::string DIRECTX_9_URL (  +								 "http://secondlife.com/support/"); // *TODO: NOT USED +/*  const std::string LAND_URL (  -	"http://secondlife.com/app/landtier"); +	"http://secondlife.com/app/landtier"); // *TODO: NOT USED  const std::string UPGRADE_TO_PREMIUM_URL ( -	"http://secondlife.com/app/upgrade/"); - -const std::string DIRECTX_9_URL (  -	"http://secondlife.com/support/"); +	"http://secondlife.com/app/upgrade/"); // *TODO: NOT USED  const std::string AMD_AGP_URL (  -	"http://secondlife.com/support/"); +	"http://secondlife.com/support/"); // *TODO: NOT USED  const std::string VIA_URL (  -	"http://secondlife.com/support/"); +	"http://secondlife.com/support/"); // *TODO: NOT USED  const std::string SUPPORT_URL (       "http://secondlife.com/support/");  const std::string INTEL_CHIPSET_URL (  -	"http://secondlife.com/support/"); +	"http://secondlife.com/support/"); // *TODO: NOT USED  const std::string SIS_CHIPSET_URL (  -	"http://secondlife.com/support/"); +	"http://secondlife.com/support/"); // *TODO: NOT USED  const std::string BLOGS_URL (  -	"http://blog.secondlife.com/"); +	"http://blog.secondlife.com/"); // *TODO: NOT USED  const std::string BUY_CURRENCY_URL (  	"http://secondlife.com/app/currency/");  const std::string LSL_DOC_URL ( -	"http://secondlife.com/app/lsldoc/"); +	"http://secondlife.com/app/lsldoc/");  // *TODO: NOT USED  const std::string SL_KB_URL ( -	"http://secondlife.com/knowledgebase/"); +	"http://secondlife.com/knowledgebase/"); // *TODO: NOT USED  const std::string RELEASE_NOTES_BASE_URL (  	"http://secondlife.com/app/releasenotes/"); +*/ + diff --git a/indra/llcommon/llsecondlifeurls.h b/indra/llcommon/llsecondlifeurls.h index 9fd75c363b..a2e5f0b9c6 100644 --- a/indra/llcommon/llsecondlifeurls.h +++ b/indra/llcommon/llsecondlifeurls.h @@ -32,7 +32,7 @@  #ifndef LL_LLSECONDLIFEURLS_H  #define LL_LLSECONDLIFEURLS_H - +/*  // Account registration web page  extern const std::string CREATE_ACCOUNT_URL; @@ -42,18 +42,21 @@ extern const std::string MANAGE_ACCOUNT;  extern const std::string AUCTION_URL;   extern const std::string EVENTS_URL; - +*/  // Tier up to a new land level.  extern const std::string TIER_UP_URL; +  // Tier up to a new land level.  extern const std::string LAND_URL; +// How to get DirectX 9 +extern const std::string DIRECTX_9_URL; + +/*  // Upgrade from basic membership to premium membership  extern const std::string UPGRADE_TO_PREMIUM_URL; -// How to get DirectX 9 -extern const std::string DIRECTX_9_URL;  // Out of date VIA chipset  extern const std::string VIA_URL; @@ -75,5 +78,5 @@ extern const std::string SL_KB_URL;  // Release Notes Redirect URL for Server and Viewer  extern const std::string RELEASE_NOTES_BASE_URL; - +*/  #endif diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h new file mode 100644 index 0000000000..dc1457e4f7 --- /dev/null +++ b/indra/llcommon/llsingleton.h @@ -0,0 +1,158 @@ +/**  + * @file llsingleton.h + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + *  + * Copyright (c) 2002-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#ifndef LLSINGLETON_H +#define LLSINGLETON_H + +#include "llerror.h"	// *TODO: eliminate this + +#include <boost/noncopyable.hpp> + +// LLSingleton implements the getInstance() method part of the Singleton +// pattern. It can't make the derived class constructors protected, though, so +// you have to do that yourself. +// +// There are two ways to use LLSingleton. The first way is to inherit from it +// while using the typename that you'd like to be static as the template +// parameter, like so: +// +//   class Foo: public LLSingleton<Foo>{}; +// +//   Foo& instance = Foo::instance(); +// +// The second way is to use the singleton class directly, without inheritance: +// +//   typedef LLSingleton<Foo> FooSingleton; +// +//   Foo& instance = FooSingleton::instance(); +// +// In this case, the class being managed as a singleton needs to provide an +// initSingleton() method since the LLSingleton virtual method won't be +// available +// +// As currently written, it is not thread-safe. + +template <typename DERIVED_TYPE> +class LLSingleton : private boost::noncopyable +{ +	 +private: +	typedef enum e_init_state +	{ +		UNINITIALIZED, +		CONSTRUCTING, +		INITIALIZING, +		INITIALIZED, +		DELETED +	} EInitState; +	 +	static void deleteSingleton() +	{ +		delete getData().mSingletonInstance; +		getData().mSingletonInstance = NULL; +	} +	 +	// stores pointer to singleton instance +	// and tracks initialization state of singleton +	struct SingletonInstanceData +	{ +		EInitState		mInitState; +		DERIVED_TYPE*	mSingletonInstance; +		 +		SingletonInstanceData() +		:	mSingletonInstance(NULL), +			mInitState(UNINITIALIZED) +		{} + +		~SingletonInstanceData() +		{ +			deleteSingleton(); +		} +	}; +	 +public: +	virtual ~LLSingleton() +	{ +		SingletonInstanceData& data = getData(); +		data.mSingletonInstance = NULL; +		data.mInitState = DELETED; +	} + +	static SingletonInstanceData& getData() +	{ +		static SingletonInstanceData data; +		return data; +	} + +	static DERIVED_TYPE* getInstance() +	{ +		SingletonInstanceData& data = getData(); + +		if (data.mInitState == CONSTRUCTING) +		{ +			llerrs << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from singleton constructor!" << llendl; +		} + +		if (data.mInitState == DELETED) +		{ +			llwarns << "Trying to access deleted singleton " << typeid(DERIVED_TYPE).name() << " creating new instance" << llendl; +		} +		 +		if (!data.mSingletonInstance)  +		{ +			data.mInitState = CONSTRUCTING; +			data.mSingletonInstance = new DERIVED_TYPE();  +			data.mInitState = INITIALIZING; +			data.mSingletonInstance->initSingleton();  +			data.mInitState = INITIALIZED;	 +		} +		 +		return data.mSingletonInstance; +	} + +	// Reference version of getInstance() +	// Preferred over getInstance() as it disallows checking for NULL +	static DERIVED_TYPE& instance() +	{ +		return *getInstance(); +	} + +	// Has this singleton already been deleted? +	// Use this to avoid accessing singletons from a static object's destructor +	static bool destroyed() +	{ +		return getData().mInitState == DELETED; +	} + +private: +	virtual void initSingleton() {} +}; + +#endif diff --git a/indra/llcommon/llstacktrace.cpp b/indra/llcommon/llstacktrace.cpp new file mode 100644 index 0000000000..4be91b5b11 --- /dev/null +++ b/indra/llcommon/llstacktrace.cpp @@ -0,0 +1,141 @@ +/**  + * @file llstacktrace.cpp + * @brief stack tracing functionality + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + *  + * Copyright (c) 2001-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llstacktrace.h" + +#ifdef LL_WINDOWS + +#include <iostream> +#include <sstream> + +#include "windows.h" +#include "Dbghelp.h" + +typedef USHORT NTAPI RtlCaptureStackBackTrace_Function( +    IN ULONG frames_to_skip, +    IN ULONG frames_to_capture, +    OUT PVOID *backtrace, +    OUT PULONG backtrace_hash); + +static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn = +   (RtlCaptureStackBackTrace_Function*) +   GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace"); + +bool ll_get_stack_trace(std::vector<std::string>& lines) +{ +	const S32 MAX_STACK_DEPTH = 32; +	const S32 STRING_NAME_LENGTH = 200; +	const S32 FRAME_SKIP = 2; +	static BOOL symbolsLoaded = false; +	static BOOL firstCall = true; + +	HANDLE hProc = GetCurrentProcess(); + +	// load the symbols if they're not loaded +	if(!symbolsLoaded && firstCall) +	{ +		symbolsLoaded = SymInitialize(hProc, NULL, true); +		firstCall = false; +	} + +	// if loaded, get the call stack +	if(symbolsLoaded) +	{ +		// create the frames to hold the addresses +		void* frames[MAX_STACK_DEPTH]; +		memset(frames, 0, sizeof(void*)*MAX_STACK_DEPTH); +		S32 depth = 0; + +		// get the addresses +		depth = RtlCaptureStackBackTrace_fn(FRAME_SKIP, MAX_STACK_DEPTH, frames, NULL); + +		IMAGEHLP_LINE64 line; +		memset(&line, 0, sizeof(IMAGEHLP_LINE64)); +		line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + +		// create something to hold address info +		PIMAGEHLP_SYMBOL64 pSym; +		pSym = (PIMAGEHLP_SYMBOL64)malloc(sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH); +		memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH); +		pSym->MaxNameLength = STRING_NAME_LENGTH; +		pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); + +		// get address info for each address frame +		// and store +		for(S32 i=0; i < depth; i++) +		{ +			std::stringstream stack_line; +			BOOL ret; + +			DWORD64 addr = (DWORD64)frames[i]; +			ret = SymGetSymFromAddr64(hProc, addr, 0, pSym); +			if(ret) +			{ +				stack_line << pSym->Name << " "; +			} + +			DWORD dummy; +			ret = SymGetLineFromAddr64(hProc, addr, &dummy, &line); +			if(ret) +			{ +				std::string file_name = line.FileName; +				std::string::size_type index = file_name.rfind("\\"); +				stack_line << file_name.substr(index + 1, file_name.size()) << ":" << line.LineNumber;  +			} + +			lines.push_back(stack_line.str()); +		} +		 +		free(pSym); + +		// TODO: figure out a way to cleanup symbol loading +		// Not hugely necessary, however. +		//SymCleanup(hProc); +		return true; +	} +	else +	{ +		lines.push_back("Stack Trace Failed.  PDB symbol info not loaded"); +	} + +	return false; +} + +#else + +bool ll_get_stack_trace(std::vector<std::string>& lines) +{ +	return false; +} + +#endif + diff --git a/indra/llcommon/llstacktrace.h b/indra/llcommon/llstacktrace.h new file mode 100644 index 0000000000..609b934a97 --- /dev/null +++ b/indra/llcommon/llstacktrace.h @@ -0,0 +1,44 @@ +/**  + * @file llstacktrace.h + * @brief stack trace functions + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + *  + * Copyright (c) 2001-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + +#ifndef LL_LLSTACKTRACE_H +#define LL_LLSTACKTRACE_H + +#include "stdtypes.h" +#include <vector> +#include <string> + +bool ll_get_stack_trace(std::vector<std::string>& lines); + +#endif + diff --git a/indra/llcommon/llstat.cpp b/indra/llcommon/llstat.cpp index 291b019616..90dae11793 100644 --- a/indra/llcommon/llstat.cpp +++ b/indra/llcommon/llstat.cpp @@ -46,6 +46,7 @@  BOOL            LLPerfBlock::sStatsEnabled = FALSE;    // Flag for detailed information  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 @@ -725,28 +726,48 @@ void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,  LLTimer LLStat::sTimer;  LLFrameTimer LLStat::sFrameTimer; -LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer) +void LLStat::init()  { -	llassert(num_bins > 0); -	U32 i; -	mUseFrameTimer = use_frame_timer; +	llassert(mNumBins > 0);  	mNumValues = 0;  	mLastValue = 0.f;  	mLastTime = 0.f; -	mNumBins = num_bins;  	mCurBin = (mNumBins-1);  	mNextBin = 0;  	mBins      = new F32[mNumBins];  	mBeginTime = new F64[mNumBins];  	mTime      = new F64[mNumBins];  	mDT        = new F32[mNumBins]; -	for (i = 0; i < mNumBins; i++) +	for (U32 i = 0; i < mNumBins; i++)  	{  		mBins[i]      = 0.f;  		mBeginTime[i] = 0.0;  		mTime[i]      = 0.0;  		mDT[i]        = 0.f;  	} + +	if (!mName.empty()) +	{ +		stat_map_t::iterator iter = sStatList.find(mName); +		if (iter != sStatList.end()) +			llwarns << "LLStat with duplicate name: " << mName << llendl; +		sStatList.insert(std::make_pair(mName, this)); +	} +} + +LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer) +	: mUseFrameTimer(use_frame_timer), +	  mNumBins(num_bins) +{ +	init(); +} + +LLStat::LLStat(std::string name, U32 num_bins, BOOL use_frame_timer) +	: mUseFrameTimer(use_frame_timer), +	  mNumBins(num_bins), +	  mName(name) +{ +	init();  }  LLStat::~LLStat() @@ -755,6 +776,15 @@ LLStat::~LLStat()  	delete[] mBeginTime;  	delete[] mTime;  	delete[] mDT; + +	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) +			++iter; +		sStatList.erase(iter); +	}  }  void LLStat::reset() diff --git a/indra/llcommon/llstat.h b/indra/llcommon/llstat.h index 61aaac45bf..bad18f46a0 100644 --- a/indra/llcommon/llstat.h +++ b/indra/llcommon/llstat.h @@ -258,8 +258,15 @@ private:  // ----------------------------------------------------------------------------  class LLStat  { +private: +	typedef std::multimap<std::string, LLStat*> stat_map_t; +	static stat_map_t sStatList; + +	void init(); +  public: -	LLStat(const U32 num_bins = 32, BOOL use_frame_timer = FALSE); +	LLStat(U32 num_bins = 32, BOOL use_frame_timer = FALSE); +	LLStat(std::string name, U32 num_bins = 32, BOOL use_frame_timer = FALSE);  	~LLStat();  	void reset(); @@ -322,8 +329,22 @@ private:  	F32 *mDT;  	S32 mCurBin;  	S32 mNextBin; +	 +	std::string mName; +  	static LLTimer sTimer;  	static LLFrameTimer sFrameTimer; +	 +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()) +			return iter->second; +		else +			return NULL; +	}  }; - +	  #endif // LL_STAT_ diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index 1f653c159c..ec1718a8cb 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -71,6 +71,24 @@ U8 hex_as_nybble(char hex)  	return 0; // uh - oh, not hex any more...  } +bool iswindividual(llwchar elem) +{    +	U32 cur_char = (U32)elem; +	bool result = false; +	if (0x2E80<= cur_char && cur_char <= 0x9FFF) +	{ +		result = true; +	} +	else if (0xAC00<= cur_char && cur_char <= 0xD7A0 ) +	{ +		result = true; +	} +	else if (0xF900<= cur_char && cur_char <= 0xFA60 ) +	{ +		result = true; +	} +	return result; +}  bool _read_file_into_string(std::string& str, const std::string& filename)  { @@ -650,6 +668,11 @@ std::string ll_convert_wide_to_string(const wchar_t* in)  }  #endif // LL_WINDOWS +long LLStringOps::sltOffset; +long LLStringOps::localTimeOffset; +bool LLStringOps::daylightSavings; +std::map<std::string, std::string> LLStringOps::datetimeToCodes; +  S32	LLStringOps::collate(const llwchar* a, const llwchar* b)  {   	#if LL_WINDOWS @@ -661,6 +684,59 @@ S32	LLStringOps::collate(const llwchar* a, const llwchar* b)  	#endif  } +void LLStringOps::setupDatetimeInfo (bool daylight) +{ +	time_t nowT, localT, gmtT; +	struct tm * tmpT; + +	nowT = time (NULL); + +	tmpT = localtime (&nowT); +	localT = mktime (tmpT); + +	tmpT = gmtime (&nowT); +	gmtT = mktime (tmpT); + +	localTimeOffset = (long) (gmtT - localT); + + +	daylightSavings = daylight; +	sltOffset = (daylightSavings? 7 : 8 ) * 60 * 60; + +	datetimeToCodes["wkday"]	= "%a";		// Thu +	datetimeToCodes["weekday"]	= "%A";		// Thursday +	datetimeToCodes["year4"]	= "%Y";		// 2009 +	datetimeToCodes["year"]		= "%Y";		// 2009 +	datetimeToCodes["year2"]	= "%y";		// 09 +	datetimeToCodes["mth"]		= "%b";		// Aug +	datetimeToCodes["month"]	= "%B";		// August +	datetimeToCodes["mthnum"]	= "%m";		// 08 +	datetimeToCodes["day"]		= "%d";		// 31 +	datetimeToCodes["hour24"]	= "%H";		// 14 +	datetimeToCodes["hour"]		= "%H";		// 14 +	datetimeToCodes["hour12"]	= "%I";		// 02 +	datetimeToCodes["min"]		= "%M";		// 59 +	datetimeToCodes["ampm"]		= "%p";		// AM +	datetimeToCodes["second"]	= "%S";		// 59 +	datetimeToCodes["timezone"]	= "%Z";		// PST +} + +std::string LLStringOps::getDatetimeCode (std::string key) +{ +	std::map<std::string, std::string>::iterator iter; + +	iter = datetimeToCodes.find (key); +	if (iter != datetimeToCodes.end()) +	{ +		return iter->second; +	} +	else +	{ +		return std::string(""); +	} +} + +  namespace LLStringFn  {  	// NOTE - this restricts output to ascii diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 6ba665b8d2..91b706a5be 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -34,6 +34,10 @@  #define LL_LLSTRING_H  #include <string> +#include <locale> +#include <iomanip> +#include <boost/regex.hpp> +#include "llsd.h"  #if LL_LINUX || LL_SOLARIS  #include <wctype.h> @@ -145,6 +149,12 @@ struct char_traits<U16>  class LLStringOps  { +private: +	static long sltOffset; +	static long localTimeOffset; +	static bool daylightSavings; +	static std::map<std::string, std::string> datetimeToCodes; +  public:  	static char toUpper(char elem) { return toupper((unsigned char)elem); }  	static llwchar toUpper(llwchar elem) { return towupper(elem); } @@ -172,6 +182,12 @@ public:  	static S32	collate(const char* a, const char* b) { return strcoll(a, b); }  	static S32	collate(const llwchar* a, const llwchar* b); + +	static void setupDatetimeInfo (bool daylight); +	static long getSltOffset (void) {return sltOffset;} +	static long getLocalTimeOffset (void) {return localTimeOffset;} +	static bool getDaylightSavings (void) {return daylightSavings;} +	static std::string getDatetimeCode (std::string key);  };  /** @@ -201,6 +217,9 @@ private:  template <class T>  class LLStringUtilBase  { +private: +	static std::string sLocale; +  public:  	typedef typename std::basic_string<T>::size_type size_type; @@ -211,7 +230,14 @@ public:  	static std::basic_string<T> null;  	typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t; +	static void getTokens (std::basic_string<T> input, std::vector<std::basic_string<T> >& tokens); +	static void formatNumber(std::basic_string<T>& numStr, std::basic_string<T> decimals); +	static bool formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token, std::basic_string<T> param, const LLSD& substitutions); +	static S32 format(std::basic_string<T>& s, const LLSD& substitutions);  	static S32 format(std::basic_string<T>& s, const format_map_t& fmt_map); +	static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const LLSD& substitutions); +	static void setLocale (std::string inLocale) {sLocale = inLocale;}; +	static std::string getLocale (void) {return sLocale;};  	static bool isValidIndex(const std::basic_string<T>& string, size_type i)  	{ @@ -317,6 +343,7 @@ public:  };  template<class T> std::basic_string<T> LLStringUtilBase<T>::null; +template<class T> std::string LLStringUtilBase<T>::sLocale;  typedef LLStringUtilBase<char> LLStringUtil;  typedef LLStringUtilBase<llwchar> LLWStringUtil; @@ -378,6 +405,7 @@ U8 hex_as_nybble(char hex);   * @return Returns true on success. If false, str is unmodified.   */  bool _read_file_into_string(std::string& str, const std::string& filename); +bool iswindividual(llwchar elem);  /**   * Unicode support @@ -564,64 +592,216 @@ namespace LLStringFn  //////////////////////////////////////////////////////////// -// LLStringBase::format() -// -// This function takes a string 's' and a map 'fmt_map' of strings-to-strings. -// All occurances of strings in 's' from the left-hand side of 'fmt_map' are -// then replaced with the corresponding right-hand side of 'fmt_map', non- -// recursively.  The function returns the number of substitutions made. +//static +template<class T> +void LLStringUtilBase<T>::getTokens (std::basic_string<T> input, std::vector<std::basic_string<T> >& tokens) +{ +	const std::basic_string<T> delims (","); +	std::basic_string<T> currToken; +	size_type begIdx, endIdx; + +	begIdx = input.find_first_not_of (delims); +	while (begIdx != std::basic_string<T>::npos) +	{ +		endIdx = input.find_first_of (delims, begIdx); +		if (endIdx == std::basic_string<T>::npos) +		{ +			endIdx = input.length(); +		} + +		currToken = input.substr(begIdx, endIdx - begIdx); +		trim (currToken); +		tokens.push_back(currToken); +		begIdx = input.find_first_not_of (delims, endIdx); +	} +}  // static  template<class T>   S32 LLStringUtilBase<T>::format(std::basic_string<T>& s, const format_map_t& fmt_map)  { -	typedef typename std::basic_string<T>::size_type string_size_type_t; -	string_size_type_t scanstart = 0; +	LLSD llsdMap; + +	for (format_map_t::const_iterator iter = fmt_map.begin(); +		 iter != fmt_map.end(); +		 ++iter) +	{ +		llsdMap[iter->first] = iter->second; +	} + +	return format (s, llsdMap); +} + +//static +template<class T> +S32 LLStringUtilBase<T>::format(std::basic_string<T>& s, const LLSD& substitutions) +{  	S32 res = 0; -	// Look for the first match of any keyword, replace that keyword, -	// repeat from the end of the replacement string.  This avoids -	// accidentally performing substitution on a substituted string. -	while (1) +	if (!substitutions.isMap())  +	{ +		return res; +	} + +	std::basic_ostringstream<T> output; +	// match strings like [NAME,number,3] +	const boost::regex key("\\[((\\s)*([0-9_A-Za-z]+)((\\s)*,(\\s)*[0-9_A-Za-z\\s]*){0,2}(\\s)*)]"); + + +	typename std::basic_string<T>::const_iterator start = s.begin(); +	typename std::basic_string<T>::const_iterator end = s.end(); +	boost::smatch match; +	 + +	while (boost::regex_search(start, end, match, key, boost::match_default))  	{ -		string_size_type_t first_match_pos = scanstart; -		string_size_type_t first_match_str_length = 0; -		std::basic_string<T> first_match_str_replacement; +		bool found_replacement = false; +		std::vector<std::basic_string<T> > tokens; +		std::basic_string<T> replacement; -		for (format_map_t::const_iterator iter = fmt_map.begin(); -		     iter != fmt_map.end(); -		     ++iter) +		getTokens (std::basic_string<T>(match[1].first, match[1].second), tokens); + +		if (tokens.size() == 1)  		{ -			string_size_type_t n = s.find(iter->first, scanstart); -			if (n != std::basic_string<T>::npos && -			    (n < first_match_pos || -			     0 == first_match_str_length)) -			{ -				first_match_pos = n; -				first_match_str_length = iter->first.length(); -				first_match_str_replacement = iter->second; -			} +			found_replacement = simpleReplacement (replacement, tokens[0], substitutions);  		} +		else if (tokens[1] == "number") +		{ +			std::basic_string<T> param = "0"; -		if (0 == first_match_str_length) +			if (tokens.size() > 2) param = tokens[2]; +			found_replacement = simpleReplacement (replacement, tokens[0], substitutions); +			if (found_replacement) formatNumber (replacement, param); +		} +		else if (tokens[1] == "datetime")  		{ -			// no more keys found to substitute from this point -			// in the string forward. -			break; +			std::basic_string<T> param; +			if (tokens.size() > 2) param = tokens[2]; + +			found_replacement = formatDatetime (replacement, tokens[0], param, substitutions); +		} + +		if (found_replacement) +		{ +			output << std::basic_string<T>(start, match[0].first) << replacement; +			res++;  		}  		else  		{ -			s.erase(first_match_pos, first_match_str_length); -			s.insert(first_match_pos, first_match_str_replacement); -			scanstart = first_match_pos + -				first_match_str_replacement.length(); -			++res; +			// we had no replacement, so leave the string we searched for so that it gets noticed by QA +			// "hello [NAME_NOT_FOUND]" is output +			output << std::basic_string<T>(start, match[0].second);  		} +		 +		// update search position  +		start = match[0].second;   	} +	// send the remainder of the string (with no further matches for bracketed names) +	output << std::basic_string<T>(start, end); +	s = output.str();  	return res;  }  // static +template<class T> +bool LLStringUtilBase<T>::simpleReplacement(std::basic_string<T> &replacement, std::basic_string<T> token, const LLSD &substitutions) +{ +	// see if we have a replacement for the bracketed string (without the brackets) +	// test first using has() because if we just look up with operator[] we get back an +	// empty string even if the value is missing. We want to distinguish between  +	// missing replacements and deliberately empty replacement strings. +	if (substitutions.has(token)) +	{ +		replacement = substitutions[token].asString(); +		return true; +	} +	// if not, see if there's one WITH brackets +	else if (substitutions.has(std::basic_string<T>("[" + token + "]"))) +	{ +		replacement = substitutions[std::basic_string<T>("[" + token + "]")].asString(); +		return true; +	} + +	return false; +} + +// static +template<class T> +void LLStringUtilBase<T>::formatNumber(std::basic_string<T>& numStr, std::basic_string<T> decimals) +{ +	typedef typename std::basic_string<T>::size_type string_size_type_t; +	std::basic_stringstream<T> strStream; +	S32 intDecimals = 0; + +	convertToS32 (decimals, intDecimals); +	if (!sLocale.empty()) +	{ +		strStream.imbue (std::locale(sLocale.c_str())); +	} + +	if (!intDecimals) +	{ +		S32 intStr; + +		if (convertToS32(numStr, intStr)) +		{ +			strStream << intStr; +			numStr = strStream.str(); +		} +	} +	else +	{ +		F32 floatStr; + +		if (convertToF32(numStr, floatStr)) +		{ +			strStream << std::fixed << std::showpoint << std::setprecision(intDecimals) << floatStr; +			numStr = strStream.str(); +		} +	} +} + +// static +template<class T> +bool LLStringUtilBase<T>::formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token, +										 std::basic_string<T> param, const LLSD& substitutions) +{ +	S32 secFromEpoch = (long) substitutions["datetime"].asInteger(); + +	if (param == "local")   // local +	{ +		secFromEpoch -= LLStringOps::getLocalTimeOffset(); +	} +	else if (param != "utc") // slt +	{ +		secFromEpoch -= LLStringOps::getSltOffset(); +	} +		 +	// if never fell into those two ifs above, param must be utc +	if (secFromEpoch < 0) secFromEpoch = 0; + +	LLDate * datetime = new LLDate((F64)secFromEpoch); +	std::string code = LLStringOps::getDatetimeCode (token); + +	// special case to handle timezone +	if (code == "%Z") { +		if (param == "utc") replacement = "GMT"; +		else if (param != "local") replacement = LLStringOps::getDaylightSavings()? "PDT" : "PST"; +		return true; +	} + +	replacement = datetime->toHTTPDateString(code); +	if (code.empty()) +	{ +		return false; +	} +	else +	{ +		return true; +	} +} + +// static  template<class T>   S32 LLStringUtilBase<T>::compareStrings(const T* lhs, const T* rhs)  {	 diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index c8c9fd4eec..f25339f48d 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -35,7 +35,6 @@  #include "llapr.h"  #include "llapp.h" -#include "llmemory.h"  #include "apr_thread_cond.h" diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp index fa6efaf38e..ea5b0c03ef 100644 --- a/indra/llcommon/lltimer.cpp +++ b/indra/llcommon/lltimer.cpp @@ -561,32 +561,27 @@ void secondsToTimecodeString(F32 current_time, std::string& tcstring)  //  ////////////////////////////////////////////////////////////////////////////// -std::list<LLEventTimer*> LLEventTimer::sActiveList; -  LLEventTimer::LLEventTimer(F32 period)  : mEventTimer()  {  	mPeriod = period; -	sActiveList.push_back(this);  }  LLEventTimer::LLEventTimer(const LLDate& time)  : mEventTimer()  {  	mPeriod = (F32)(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch()); -	sActiveList.push_back(this);  } -LLEventTimer::~LLEventTimer()  +LLEventTimer::~LLEventTimer()  { -	sActiveList.remove(this);  }  void LLEventTimer::updateClass()   {  	std::list<LLEventTimer*> completed_timers; -	for (std::list<LLEventTimer*>::iterator iter = sActiveList.begin(); iter != sActiveList.end(); )  +	for (instance_iter iter = beginInstances(); iter != endInstances(); )   	{  		LLEventTimer* timer = *iter++;  		F32 et = timer->mEventTimer.getElapsedTimeF32(); diff --git a/indra/llcommon/lltimer.h b/indra/llcommon/lltimer.h index e2cf1c7689..0319bec45b 100644 --- a/indra/llcommon/lltimer.h +++ b/indra/llcommon/lltimer.h @@ -40,6 +40,7 @@  #include "stdtypes.h"  #include "lldate.h" +#include "llinstancetracker.h"  #include <string>  #include <list> @@ -171,13 +172,13 @@ void microsecondsToTimecodeString(U64 current_time, std::string& tcstring);  void secondsToTimecodeString(F32 current_time, std::string& tcstring);  // class for scheduling a function to be called at a given frequency (approximate, inprecise) -class LLEventTimer  +class LLEventTimer : protected LLInstanceTracker<LLEventTimer>  {  public:  	LLEventTimer(F32 period);	// period is the amount of time between each call to tick() in seconds  	LLEventTimer(const LLDate& time);  	virtual ~LLEventTimer(); - +	  	//function to be called at the supplied frequency  	// Normally return FALSE; TRUE will delete the timer after the function returns.  	virtual BOOL tick() = 0; @@ -187,10 +188,6 @@ public:  protected:  	LLTimer mEventTimer;  	F32 mPeriod; - -private: -	//list of active timers -	static std::list<LLEventTimer*> sActiveList; // TODO should this be a vector  };  #endif diff --git a/indra/llcommon/lltreeiterators.h b/indra/llcommon/lltreeiterators.h new file mode 100644 index 0000000000..c946566e84 --- /dev/null +++ b/indra/llcommon/lltreeiterators.h @@ -0,0 +1,711 @@ +/** + * @file   lltreeiterators.h + * @author Nat Goodspeed + * @date   2008-08-19 + * @brief  This file defines iterators useful for traversing arbitrary node + *         classes, potentially polymorphic, linked into strict tree + *         structures. + * + *         Dereferencing any one of these iterators actually yields a @em + *         pointer to the node in question. For example, given an + *         LLLinkedIter<MyNode> <tt>li</tt>, <tt>*li</tt> gets you a pointer + *         to MyNode, and <tt>**li</tt> gets you the MyNode instance itself. + *         More commonly, instead of writing <tt>li->member</tt>, you write + *         <tt>(*li)->member</tt> -- as you would if you were traversing an + *         STL container of MyNode pointers. + * + *         It would certainly be possible to build these iterators so that + *         <tt>*iterator</tt> would return a reference to the node itself + *         rather than a pointer to the node, and for many purposes it would + *         even be more convenient. However, that would be insufficiently + *         flexible. If you want to use an iterator range to (e.g.) initialize + *         a std::vector collecting results -- you rarely want to actually @em + *         copy the nodes in question. You're much more likely to want to copy + *         <i>pointers to</i> the traversed nodes. Hence these iterators + *         produce pointers. + * + *         Though you specify the actual NODE class as the template parameter, + *         these iterators internally use LLPtrTo<> to discover whether to + *         store and return an LLPointer<NODE> or a simple NODE*. + * + *         By strict tree structures, we mean that each child must have + *         exactly one parent. This forbids a child claiming any ancestor as a + *         child of its own. Child nodes with multiple parents will be visited + *         once for each parent. Cycles in the graph will result in either an + *         infinite loop or an out-of-memory crash. You Have Been Warned. + *  + * $LicenseInfo:firstyear=2008&license=viewergpl$ + *  + * Copyright (c) 2008-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLTREEITERATORS_H) +#define LL_LLTREEITERATORS_H + +#include "llptrto.h" +#include <vector> +#include <deque> +#include <boost/iterator/iterator_facade.hpp> +#include <boost/function.hpp> +#include <boost/static_assert.hpp> + +namespace LLTreeIter +{ +    /// Discriminator between LLTreeUpIter and LLTreeDownIter +    enum RootIter { UP, DOWN }; +    /// Discriminator between LLTreeDFSIter, LLTreeDFSPostIter and LLTreeBFSIter +    enum WalkIter { DFS_PRE, DFS_POST, BFS }; +} + +/** + * LLBaseIter defines some machinery common to all these iterators. We use + * boost::iterator_facade to define the iterator boilerplate: the conventional + * operators and methods necessary to implement a standards-conforming + * iterator. That allows us to specify the actual iterator semantics in terms + * of equal(), dereference() and increment() methods. + */ +template <class SELFTYPE, class NODE> +class LLBaseIter: public boost::iterator_facade<SELFTYPE, +                                                // use pointer type as the +                                                // reference type +                                                typename LLPtrTo<NODE>::type, +                                                boost::forward_traversal_tag> +{ +protected: +    /// LLPtrTo<NODE>::type is either NODE* or LLPointer<NODE>, as appropriate +    typedef typename LLPtrTo<NODE>::type ptr_type; +    /// function that advances from this node to next accepts a node pointer +    /// and returns another +    typedef boost::function<ptr_type(const ptr_type&)> func_type; +    typedef SELFTYPE self_type; +}; + +/// Functor returning NULL, suitable for an end-iterator's 'next' functor +template <class NODE> +typename LLPtrTo<NODE>::type LLNullNextFunctor(const typename LLPtrTo<NODE>::type&) +{ +    return typename LLPtrTo<NODE>::type(); +} + +/** + * LLLinkedIter is an iterator over an intrusive singly-linked list. The + * beginning of the list is represented by LLLinkedIter(list head); the end is + * represented by LLLinkedIter(). + * + * The begin LLLinkedIter must be instantiated with a functor to extract the + * 'next' pointer from the current node. Supposing that the link pointer is @c + * public, something like: + * + * @code + * NODE* mNext; + * @endcode + * + * you can use (e.g.) <tt>boost::bind(&NODE::mNext, _1)</tt> for the purpose. + * Alternatively, you can bind whatever accessor method is normally used to + * advance to the next node, e.g. for: + * + * @code + * NODE* next() const; + * @endcode + * + * you can use <tt>boost::bind(&NODE::next, _1)</tt>. + */ +template <class NODE> +class LLLinkedIter: public LLBaseIter<LLLinkedIter<NODE>, NODE> +{ +    typedef LLBaseIter<LLLinkedIter<NODE>, NODE> super; +protected: +    /// some methods need to return a reference to self +    typedef typename super::self_type self_type; +    typedef typename super::ptr_type ptr_type; +    typedef typename super::func_type func_type; +public: +    /// Instantiate an LLLinkedIter to start a range, or to end a range before +    /// a particular list entry. Pass a functor to extract the 'next' pointer +    /// from the current node. +    LLLinkedIter(const ptr_type& entry, const func_type& nextfunc): +        mCurrent(entry), +        mNextFunc(nextfunc) +    {} +    /// Instantiate an LLLinkedIter to end a range at the end of the list +    LLLinkedIter(): +        mCurrent(), +        mNextFunc(LLNullNextFunctor<NODE>) +    {} + +private: +    /// leverage boost::iterator_facade +    friend class boost::iterator_core_access; + +    /// advance +    void increment() +    { +        mCurrent = mNextFunc(mCurrent); +    } +    /// equality +    bool equal(const self_type& that) const { return this->mCurrent == that.mCurrent; } +    /// dereference +    ptr_type& dereference() const { return const_cast<ptr_type&>(mCurrent); } + +    ptr_type mCurrent; +    func_type mNextFunc; +}; + +/** + * LLTreeUpIter walks from the node in hand to the root of the tree. The term + * "up" is applied to a tree visualized with the root at the top. + * + * LLTreeUpIter is an alias for LLLinkedIter, since any linked tree that you + * can navigate that way at all contains parent pointers. + */ +template <class NODE> +class LLTreeUpIter: public LLLinkedIter<NODE> +{ +    typedef LLLinkedIter<NODE> super; +public: +    /// Instantiate an LLTreeUpIter to start from a particular tree node, or +    /// to end a parent traversal before reaching a particular ancestor. Pass +    /// a functor to extract the 'parent' pointer from the current node. +    LLTreeUpIter(const typename super::ptr_type& node, +                 const typename super::func_type& parentfunc): +        super(node, parentfunc) +    {} +    /// Instantiate an LLTreeUpIter to end a range at the root of the tree +    LLTreeUpIter(): +        super() +    {} +}; + +/** + * LLTreeDownIter walks from the root of the tree to the node in hand. The + * term "down" is applied to a tree visualized with the root at the top. + * + * Though you instantiate the begin() LLTreeDownIter with a pointer to some + * node at an arbitrary location in the tree, the root will be the first node + * you dereference and the passed node will be the last node you dereference. + * + * On construction, LLTreeDownIter walks from the current node to the root, + * capturing the path. Then in use, it replays that walk in reverse. As with + * all traversals of interesting data structures, it is actively dangerous to + * modify the tree during an LLTreeDownIter walk. + */ +template <class NODE> +class LLTreeDownIter: public LLBaseIter<LLTreeDownIter<NODE>, NODE> +{ +    typedef LLBaseIter<LLTreeDownIter<NODE>, NODE> super; +    typedef typename super::self_type self_type; +protected: +    typedef typename super::ptr_type ptr_type; +    typedef typename super::func_type func_type; +private: +    typedef std::vector<ptr_type> list_type; +public: +    /// Instantiate an LLTreeDownIter to end at a particular tree node. Pass a +    /// functor to extract the 'parent' pointer from the current node. +    LLTreeDownIter(const ptr_type& node, +                   const func_type& parentfunc) +    { +        for (ptr_type n = node; n; n = parentfunc(n)) +            mParents.push_back(n); +    } +    /// Instantiate an LLTreeDownIter representing "here", the end of the loop +    LLTreeDownIter() {} + +private: +    /// leverage boost::iterator_facade +    friend class boost::iterator_core_access; + +    /// advance +    void increment() +    { +        mParents.pop_back(); +    } +    /// equality +    bool equal(const self_type& that) const { return this->mParents == that.mParents; } +    /// implement dereference/indirection operators +    ptr_type& dereference() const { return const_cast<ptr_type&>(mParents.back()); } + +    list_type mParents; +}; + +/** + * When you want to select between LLTreeUpIter and LLTreeDownIter with a + * compile-time discriminator, use LLTreeRootIter with an LLTreeIter::RootIter + * template arg. + */ +template <LLTreeIter::RootIter DISCRIM, class NODE> +class LLTreeRootIter +{ +    enum { use_a_valid_LLTreeIter_RootIter_value = false }; +public: +    /// Bogus constructors for default (unrecognized discriminator) case +    template <typename TYPE1, typename TYPE2> +    LLTreeRootIter(TYPE1, TYPE2) +    { +        BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_RootIter_value); +    } +    LLTreeRootIter() +    { +        BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_RootIter_value); +    } +}; + +/// Specialize for LLTreeIter::UP +template <class NODE> +class LLTreeRootIter<LLTreeIter::UP, NODE>: public LLTreeUpIter<NODE> +{ +    typedef LLTreeUpIter<NODE> super; +public: +    /// forward begin ctor +    LLTreeRootIter(const typename super::ptr_type& node, +                   const typename super::func_type& parentfunc): +        super(node, parentfunc) +    {} +    /// forward end ctor +    LLTreeRootIter(): +        super() +    {} +}; + +/// Specialize for LLTreeIter::DOWN +template <class NODE> +class LLTreeRootIter<LLTreeIter::DOWN, NODE>: public LLTreeDownIter<NODE> +{ +    typedef LLTreeDownIter<NODE> super; +public: +    /// forward begin ctor +    LLTreeRootIter(const typename super::ptr_type& node, +                   const typename super::func_type& parentfunc): +        super(node, parentfunc) +    {} +    /// forward end ctor +    LLTreeRootIter(): +        super() +    {} +}; + +/** + * Instantiated with a tree node, typically the root, LLTreeDFSIter "flattens" + * a depth-first tree walk through that node and all its descendants. + * + * The begin() LLTreeDFSIter must be instantiated with functors to obtain from + * a given node begin() and end() iterators for that node's children. For this + * reason, you must specify the type of the node's child iterator as an + * additional template parameter. + * + * Specifically, the begin functor must return an iterator whose dereferenced + * value is a @em pointer to a child tree node. For instance, if each node + * tracks its children in an STL container of node* pointers, you can simply + * return that container's begin() iterator. + * + * Alternatively, if a node tracks its children with a classic linked list, + * write a functor returning LLLinkedIter<NODE>. + * + * The end() LLTreeDFSIter must, of course, match the begin() iterator's + * template parameters, but is constructed without runtime parameters. + */ +template <class NODE, typename CHILDITER> +class LLTreeDFSIter: public LLBaseIter<LLTreeDFSIter<NODE, CHILDITER>, NODE> +{ +    typedef LLBaseIter<LLTreeDFSIter<NODE, CHILDITER>, NODE> super; +    typedef typename super::self_type self_type; +protected: +    typedef typename super::ptr_type ptr_type; +    // The func_type is different for this: from a NODE pointer, we must +    // obtain a CHILDITER. +    typedef boost::function<CHILDITER(const ptr_type&)> func_type; +private: +    typedef std::vector<ptr_type> list_type; +public: +    /// Instantiate an LLTreeDFSIter to start a depth-first walk. Pass +    /// functors to extract the 'child begin' and 'child end' iterators from +    /// each node. +    LLTreeDFSIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc): +        mBeginFunc(beginfunc), +        mEndFunc(endfunc), +		mSkipChildren(false) +    { +        // Only push back this node if it's non-NULL! +        if (node) +            mPending.push_back(node); +    } +    /// Instantiate an LLTreeDFSIter to mark the end of the walk +    LLTreeDFSIter() {} + +	/// flags iterator logic to skip traversing children of current node on next increment +	void skipDescendants(bool skip = true) { mSkipChildren = skip; } + +private: +    /// leverage boost::iterator_facade +    friend class boost::iterator_core_access; + +    /// advance +    /// This implementation is due to http://en.wikipedia.org/wiki/Depth-first_search +    void increment() +    { +        // Capture the node we were just looking at +        ptr_type current = mPending.back(); +        // Remove it from mPending so we don't process it again later +        mPending.pop_back(); +		if (!mSkipChildren) +		{ +			// Add all its children to mPending +			addChildren(current); +		} +		// reset flag after each step +		mSkipChildren = false; +    } +    /// equality +    bool equal(const self_type& that) const { return this->mPending == that.mPending; } +    /// implement dereference/indirection operators +    ptr_type& dereference() const { return const_cast<ptr_type&>(mPending.back()); } + +    /// Add the direct children of the specified node to mPending +    void addChildren(const ptr_type& node) +    { +        // If we just use push_back() for each child in turn, we'll end up +        // processing children in reverse order. We don't want to assume +        // CHILDITER is reversible: some of the linked trees we'll be +        // processing manage their children using singly-linked lists. So +        // figure out how many children there are, grow mPending by that size +        // and reverse-copy the children into the new space. +        CHILDITER chi = mBeginFunc(node), chend = mEndFunc(node); +        // grow mPending by the number of children +        mPending.resize(mPending.size() + std::distance(chi, chend)); +        // reverse-copy the children into the newly-expanded space +        std::copy(chi, chend, mPending.rbegin()); +    } + +    /// list of the nodes yet to be processed +    list_type mPending; +    /// functor to extract begin() child iterator +    func_type mBeginFunc; +    /// functor to extract end() child iterator +    func_type mEndFunc; +	/// flag which controls traversal of children (skip children of current node if true) +	bool	mSkipChildren; +}; + +/** + * Instantiated with a tree node, typically the root, LLTreeDFSPostIter + * "flattens" a depth-first tree walk through that node and all its + * descendants. Whereas LLTreeDFSIter visits each node before visiting any of + * its children, LLTreeDFSPostIter visits all of a node's children before + * visiting the node itself. + * + * The begin() LLTreeDFSPostIter must be instantiated with functors to obtain + * from a given node begin() and end() iterators for that node's children. For + * this reason, you must specify the type of the node's child iterator as an + * additional template parameter. + * + * Specifically, the begin functor must return an iterator whose dereferenced + * value is a @em pointer to a child tree node. For instance, if each node + * tracks its children in an STL container of node* pointers, you can simply + * return that container's begin() iterator. + * + * Alternatively, if a node tracks its children with a classic linked list, + * write a functor returning LLLinkedIter<NODE>. + * + * The end() LLTreeDFSPostIter must, of course, match the begin() iterator's + * template parameters, but is constructed without runtime parameters. + */ +template <class NODE, typename CHILDITER> +class LLTreeDFSPostIter: public LLBaseIter<LLTreeDFSPostIter<NODE, CHILDITER>, NODE> +{ +    typedef LLBaseIter<LLTreeDFSPostIter<NODE, CHILDITER>, NODE> super; +    typedef typename super::self_type self_type; +protected: +    typedef typename super::ptr_type ptr_type; +    // The func_type is different for this: from a NODE pointer, we must +    // obtain a CHILDITER. +    typedef boost::function<CHILDITER(const ptr_type&)> func_type; +private: +    // Upon reaching a given node in our pending list, we need to know whether +    // we've already pushed that node's children, so we must associate a bool +    // with each node pointer. +    typedef std::vector< std::pair<ptr_type, bool> > list_type; +public: +    /// Instantiate an LLTreeDFSPostIter to start a depth-first walk. Pass +    /// functors to extract the 'child begin' and 'child end' iterators from +    /// each node. +    LLTreeDFSPostIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc): +        mBeginFunc(beginfunc), +        mEndFunc(endfunc), +		mSkipAncestors(false) +    { +        if (! node) +            return; +        mPending.push_back(typename list_type::value_type(node, false)); +        makeCurrent(); +    } +    /// Instantiate an LLTreeDFSPostIter to mark the end of the walk +    LLTreeDFSPostIter() {} + +	/// flags iterator logic to skip traversing ancestors of current node on next increment +	void skipAncestors(bool skip = true) { mSkipAncestors = skip; } + +private: +    /// leverage boost::iterator_facade +    friend class boost::iterator_core_access; + +    /// advance +    /// This implementation is due to http://en.wikipedia.org/wiki/Depth-first_search +    void increment() +    { +        // Pop the previous current node +        mPending.pop_back(); +        makeCurrent(); +    } +    /// equality +    bool equal(const self_type& that) const { return this->mPending == that.mPending; } +    /// implement dereference/indirection operators +    ptr_type& dereference() const { return const_cast<ptr_type&>(mPending.back().first); } + +	struct isOpen +	{ +		bool operator()(const typename list_type::value_type& item) +		{ +			return item.second; +		} +	}; + +    /// Call this each time we change mPending.back() -- that is, every time +    /// we're about to change the value returned by dereference(). If we +    /// haven't yet pushed the new node's children, do so now. +    void makeCurrent() +    { +		if (mSkipAncestors) +		{ +			mPending.erase(std::remove_if(mPending.begin(), mPending.end(), isOpen()), mPending.end()); +			mSkipAncestors = false; +		} + +        // Once we've popped the last node, this becomes a no-op. +        if (mPending.empty()) +            return; +        // Here mPending.back() holds the node pointer we're proposing to +        // dereference next. Have we pushed that node's children yet? +        if (mPending.back().second) +            return;                 // if so, it's okay to visit this node now +        // We haven't yet pushed this node's children. Do so now. Remember +        // that we did -- while the node in question is still back(). +        mPending.back().second = true; +        addChildren(mPending.back().first); +        // Now, because we've just changed mPending.back(), make that new node +        // current. +        makeCurrent(); +    } + +    /// Add the direct children of the specified node to mPending +    void addChildren(const ptr_type& node) +    { +        // If we just use push_back() for each child in turn, we'll end up +        // processing children in reverse order. We don't want to assume +        // CHILDITER is reversible: some of the linked trees we'll be +        // processing manage their children using singly-linked lists. So +        // figure out how many children there are, grow mPending by that size +        // and reverse-copy the children into the new space. +        CHILDITER chi = mBeginFunc(node), chend = mEndFunc(node); +        // grow mPending by the number of children +        mPending.resize(mPending.size() + std::distance(chi, chend)); +        // Reverse-copy the children into the newly-expanded space. We can't +        // just use std::copy() because the source is a ptr_type, whereas the +        // dest is a pair of (ptr_type, bool). +        for (typename list_type::reverse_iterator pi = mPending.rbegin(); chi != chend; ++chi, ++pi) +        { +            pi->first = *chi;       // copy the child pointer +            pi->second = false;     // we haven't yet pushed this child's chldren +        } +    } + +    /// list of the nodes yet to be processed +    list_type	mPending; +    /// functor to extract begin() child iterator +    func_type	mBeginFunc; +    /// functor to extract end() child iterator +    func_type	mEndFunc; +	/// flags logic to skip traversal of ancestors of current node +	bool		mSkipAncestors; +}; + +/** + * Instantiated with a tree node, typically the root, LLTreeBFSIter "flattens" + * a breadth-first tree walk through that node and all its descendants. + * + * The begin() LLTreeBFSIter must be instantiated with functors to obtain from + * a given node the begin() and end() iterators of that node's children. For + * this reason, you must specify the type of the node's child iterator as an + * additional template parameter. + * + * Specifically, the begin functor must return an iterator whose dereferenced + * value is a @em pointer to a child tree node. For instance, if each node + * tracks its children in an STL container of node* pointers, you can simply + * return that container's begin() iterator. + * + * Alternatively, if a node tracks its children with a classic linked list, + * write a functor returning LLLinkedIter<NODE>. + * + * The end() LLTreeBFSIter must, of course, match the begin() iterator's + * template parameters, but is constructed without runtime parameters. + */ +template <class NODE, typename CHILDITER> +class LLTreeBFSIter: public LLBaseIter<LLTreeBFSIter<NODE, CHILDITER>, NODE> +{ +    typedef LLBaseIter<LLTreeBFSIter<NODE, CHILDITER>, NODE> super; +    typedef typename super::self_type self_type; +protected: +    typedef typename super::ptr_type ptr_type; +    // The func_type is different for this: from a NODE pointer, we must +    // obtain a CHILDITER. +    typedef boost::function<CHILDITER(const ptr_type&)> func_type; +private: +    // We need a FIFO queue rather than a LIFO stack. Use a deque rather than +    // a vector, since vector can't implement pop_front() efficiently. +    typedef std::deque<ptr_type> list_type; +public: +    /// Instantiate an LLTreeBFSIter to start a depth-first walk. Pass +    /// functors to extract the 'child begin' and 'child end' iterators from +    /// each node. +    LLTreeBFSIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc): +        mBeginFunc(beginfunc), +        mEndFunc(endfunc) +    { +        if (node) +            mPending.push_back(node); +    } +    /// Instantiate an LLTreeBFSIter to mark the end of the walk +    LLTreeBFSIter() {} + +private: +    /// leverage boost::iterator_facade +    friend class boost::iterator_core_access; + +    /// advance +    /// This implementation is due to http://en.wikipedia.org/wiki/Breadth-first_search +    void increment() +    { +        // Capture the node we were just looking at +        ptr_type current = mPending.front(); +        // Remove it from mPending so we don't process it again later +        mPending.pop_front(); +        // Add all its children to mPending +        CHILDITER chend = mEndFunc(current); +        for (CHILDITER chi = mBeginFunc(current); chi != chend; ++chi) +            mPending.push_back(*chi); +    } +    /// equality +    bool equal(const self_type& that) const { return this->mPending == that.mPending; } +    /// implement dereference/indirection operators +    ptr_type& dereference() const { return const_cast<ptr_type&>(mPending.front()); } + +    /// list of the nodes yet to be processed +    list_type mPending; +    /// functor to extract begin() child iterator +    func_type mBeginFunc; +    /// functor to extract end() child iterator +    func_type mEndFunc; +}; + +/** + * When you want to select between LLTreeDFSIter, LLTreeDFSPostIter and + * LLTreeBFSIter with a compile-time discriminator, use LLTreeWalkIter with an + * LLTreeIter::WalkIter template arg. + */ +template <LLTreeIter::WalkIter DISCRIM, class NODE, typename CHILDITER> +class LLTreeWalkIter +{ +    enum { use_a_valid_LLTreeIter_WalkIter_value = false }; +public: +    /// Bogus constructors for default (unrecognized discriminator) case +    template <typename TYPE1, typename TYPE2> +    LLTreeWalkIter(TYPE1, TYPE2) +    { +        BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_WalkIter_value); +    } +    LLTreeWalkIter() +    { +        BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_WalkIter_value); +    } +}; + +/// Specialize for LLTreeIter::DFS_PRE +template <class NODE, typename CHILDITER> +class LLTreeWalkIter<LLTreeIter::DFS_PRE, NODE, CHILDITER>: +    public LLTreeDFSIter<NODE, CHILDITER> +{ +    typedef LLTreeDFSIter<NODE, CHILDITER> super; +public: +    /// forward begin ctor +    LLTreeWalkIter(const typename super::ptr_type& node, +                   const typename super::func_type& beginfunc, +                   const typename super::func_type& endfunc): +        super(node, beginfunc, endfunc) +    {} +    /// forward end ctor +    LLTreeWalkIter(): +        super() +    {} +}; + +/// Specialize for LLTreeIter::DFS_POST +template <class NODE, typename CHILDITER> +class LLTreeWalkIter<LLTreeIter::DFS_POST, NODE, CHILDITER>: +    public LLTreeDFSPostIter<NODE, CHILDITER> +{ +    typedef LLTreeDFSPostIter<NODE, CHILDITER> super; +public: +    /// forward begin ctor +    LLTreeWalkIter(const typename super::ptr_type& node, +                   const typename super::func_type& beginfunc, +                   const typename super::func_type& endfunc): +        super(node, beginfunc, endfunc) +    {} +    /// forward end ctor +    LLTreeWalkIter(): +        super() +    {} +}; + +/// Specialize for LLTreeIter::BFS +template <class NODE, typename CHILDITER> +class LLTreeWalkIter<LLTreeIter::BFS, NODE, CHILDITER>: +    public LLTreeBFSIter<NODE, CHILDITER> +{ +    typedef LLTreeBFSIter<NODE, CHILDITER> super; +public: +    /// forward begin ctor +    LLTreeWalkIter(const typename super::ptr_type& node, +                   const typename super::func_type& beginfunc, +                   const typename super::func_type& endfunc): +        super(node, beginfunc, endfunc) +    {} +    /// forward end ctor +    LLTreeWalkIter(): +        super() +    {} +}; + +#endif /* ! defined(LL_LLTREEITERATORS_H) */ diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h index a28d0f7268..45810a101d 100644 --- a/indra/llcommon/llversionviewer.h +++ b/indra/llcommon/llversionviewer.h @@ -33,11 +33,11 @@  #ifndef LL_LLVERSIONVIEWER_H  #define LL_LLVERSIONVIEWER_H -const S32 LL_VERSION_MAJOR = 1; -const S32 LL_VERSION_MINOR = 24; -const S32 LL_VERSION_PATCH = 2; +const S32 LL_VERSION_MAJOR = 2; +const S32 LL_VERSION_MINOR = 0; +const S32 LL_VERSION_PATCH = 0;  const S32 LL_VERSION_BUILD = 0; -const char * const LL_CHANNEL = "Second Life Release"; +const char * const LL_CHANNEL = "Second Life 2009";  #endif diff --git a/indra/llcommon/tests/llallocator_heap_profile_test.cpp b/indra/llcommon/tests/llallocator_heap_profile_test.cpp new file mode 100644 index 0000000000..7369fdc8bc --- /dev/null +++ b/indra/llcommon/tests/llallocator_heap_profile_test.cpp @@ -0,0 +1,150 @@ +/** + * @file   llallocator_heap_profile_test.cpp + * @author Brad Kittenbrink + * @date   2008-02- + * @brief  Test for llallocator_heap_profile.cpp. + *  + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "../llallocator_heap_profile.h" +#include "../test/lltut.h" + +namespace tut +{ +    struct llallocator_heap_profile_data +    { +        LLAllocatorHeapProfile prof; + +        static char const * const sample_win_profile; +        // *TODO - get test output from mac/linux tcmalloc +        static char const * const sample_mac_profile; +        static char const * const sample_lin_profile; + +        static char const * const crash_testcase; +    }; +    typedef test_group<llallocator_heap_profile_data> factory; +    typedef factory::object object; +} +namespace +{ +        tut::factory llallocator_heap_profile_test_factory("LLAllocatorHeapProfile"); +} + +namespace tut +{ +    template<> template<> +    void object::test<1>() +    { +        prof.parse(sample_win_profile); + +        ensure_equals("count lines", prof.mLines.size() , 5); +        ensure_equals("alloc counts", prof.mLines[0].mLiveCount, 2131854U); +        ensure_equals("alloc counts", prof.mLines[0].mLiveSize, 2245710106ULL); +        ensure_equals("alloc counts", prof.mLines[0].mTotalCount, 14069198U); +        ensure_equals("alloc counts", prof.mLines[0].mTotalSize, 4295177308ULL); +        ensure_equals("count markers", prof.mLines[0].mTrace.size(), 0); +        ensure_equals("count markers", prof.mLines[1].mTrace.size(), 0); +        ensure_equals("count markers", prof.mLines[2].mTrace.size(), 4); +        ensure_equals("count markers", prof.mLines[3].mTrace.size(), 6); +        ensure_equals("count markers", prof.mLines[4].mTrace.size(), 7); + +        //prof.dump(std::cout); +    } + +    template<> template<> +    void object::test<2>() +    { +        prof.parse(crash_testcase); + +        ensure_equals("count lines", prof.mLines.size(), 2); +        ensure_equals("alloc counts", prof.mLines[0].mLiveCount, 3U); +        ensure_equals("alloc counts", prof.mLines[0].mLiveSize, 1049652ULL); +        ensure_equals("alloc counts", prof.mLines[0].mTotalCount, 8U); +        ensure_equals("alloc counts", prof.mLines[0].mTotalSize, 1049748ULL); +        ensure_equals("count markers", prof.mLines[0].mTrace.size(), 0); +        ensure_equals("count markers", prof.mLines[1].mTrace.size(), 0); + +        //prof.dump(std::cout); +    } + +    template<> template<> +    void object::test<3>() +    { +        // test that we don't crash on edge case data +        prof.parse(""); +        ensure("emtpy on error", prof.mLines.empty()); + +        prof.parse("heap profile:"); +        ensure("emtpy on error", prof.mLines.empty()); +    } + +char const * const llallocator_heap_profile_data::sample_win_profile = +"heap profile: 2131854: 2245710106 [14069198: 4295177308] @\n" +"308592: 1073398388 [966564: 1280998739] @\n" +"462651: 375969538 [1177377: 753561247] @        2        3        6        1\n" +"314744: 206611283 [2008722: 570934755] @        2        3        3        7       21       32\n" +"277152: 82862770 [621961: 168503640] @        2        3        3        7       21       32       87\n" +"\n" +"MAPPED_LIBRARIES:\n" +"00400000-02681000 r-xp 00000000 00:00 0           c:\\proj\\tcmalloc-eval-9\\indra\\build-vc80\\newview\\RelWithDebInfo\\secondlife-bin.exe\n" +"77280000-773a7000 r-xp 00000000 00:00 0           C:\\Windows\\system32\\ntdll.dll\n" +"76df0000-76ecb000 r-xp 00000000 00:00 0           C:\\Windows\\system32\\kernel32.dll\n" +"76000000-76073000 r-xp 00000000 00:00 0           C:\\Windows\\system32\\comdlg32.dll\n" +"75ee0000-75f8a000 r-xp 00000000 00:00 0           C:\\Windows\\system32\\msvcrt.dll\n" +"76c30000-76c88000 r-xp 00000000 00:00 0           C:\\Windows\\system32\\SHLWAPI.dll\n" +"75f90000-75fdb000 r-xp 00000000 00:00 0           C:\\Windows\\system32\\GDI32.dll\n" +"77420000-774bd000 r-xp 00000000 00:00 0           C:\\Windows\\system32\\USER32.dll\n" +"75e10000-75ed6000 r-xp 00000000 00:00 0           C:\\Windows\\system32\\ADVAPI32.dll\n" +"75b00000-75bc2000 r-xp 00000000 00:00 0           C:\\Windows\\system32\\RPCRT4.dll\n" +"72ca0000-72d25000 r-xp 00000000 00:00 0           C:\\Windows\\WinSxS\\x86_microsoft.windows.common-controls_6595b64144ccf1df_5.82.6001.18000_none_886786f450a74a05\\COMCTL32.dll\n" +"76120000-76c30000 r-xp 00000000 00:00 0           C:\\Windows\\system32\\SHELL32.dll\n" +"71ce0000-71d13000 r-xp 00000000 00:00 0           C:\\Windows\\system32\\DINPUT8.dll\n"; + + +char const * const llallocator_heap_profile_data::crash_testcase = +"heap profile:      3:  1049652 [     8:  1049748] @\n" +"     3:  1049652 [     8:  1049748] @\n" +"\n" +"MAPPED_LIBRARIES:\n" +"00400000-004d5000 r-xp 00000000 00:00 0           c:\\code\\linden\\tcmalloc\\indra\\build-vc80\\llcommon\\RelWithDebInfo\\llallocator_test.exe\n" +"7c900000-7c9af000 r-xp 00000000 00:00 0           C:\\WINDOWS\\system32\\ntdll.dll\n" +"7c800000-7c8f6000 r-xp 00000000 00:00 0           C:\\WINDOWS\\system32\\kernel32.dll\n" +"77dd0000-77e6b000 r-xp 00000000 00:00 0           C:\\WINDOWS\\system32\\ADVAPI32.dll\n" +"77e70000-77f02000 r-xp 00000000 00:00 0           C:\\WINDOWS\\system32\\RPCRT4.dll\n" +"77fe0000-77ff1000 r-xp 00000000 00:00 0           C:\\WINDOWS\\system32\\Secur32.dll\n" +"71ab0000-71ac7000 r-xp 00000000 00:00 0           C:\\WINDOWS\\system32\\WS2_32.dll\n" +"77c10000-77c68000 r-xp 00000000 00:00 0           C:\\WINDOWS\\system32\\msvcrt.dll\n" +"71aa0000-71aa8000 r-xp 00000000 00:00 0           C:\\WINDOWS\\system32\\WS2HELP.dll\n" +"76bf0000-76bfb000 r-xp 00000000 00:00 0           C:\\WINDOWS\\system32\\PSAPI.DLL\n" +"5b860000-5b8b5000 r-xp 00000000 00:00 0           C:\\WINDOWS\\system32\\NETAPI32.dll\n" +"10000000-10041000 r-xp 00000000 00:00 0           c:\\code\\linden\\tcmalloc\\indra\\build-vc80\\llcommon\\RelWithDebInfo\\libtcmalloc_minimal.dll\n" +"7c420000-7c4a7000 r-xp 00000000 00:00 0           C:\\WINDOWS\\WinSxS\\x86_Microsoft.VC80.CRT_1fc8b3b9a1e18e3b_8.0.50727.1433_x-ww_5cf844d2\\MSVCP80.dll\n" +"78130000-781cb000 r-xp 00000000 00:00 0           C:\\WINDOWS\\WinSxS\\x86_Microsoft.VC80.CRT_1fc8b3b9a1e18e3b_8.0.50727.1433_x-ww_5cf844d2\\MSVCR80.dll\n"; + +} diff --git a/indra/llcommon/tests/llallocator_test.cpp b/indra/llcommon/tests/llallocator_test.cpp new file mode 100644 index 0000000000..9db95f4273 --- /dev/null +++ b/indra/llcommon/tests/llallocator_test.cpp @@ -0,0 +1,86 @@ +/** + * @file   llallocator_test.cpp + * @author Brad Kittenbrink + * @date   2008-02- + * @brief  Test for llallocator.cpp. + *  + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "../llallocator.h" +#include "../test/lltut.h" + +namespace tut +{ +    struct llallocator_data +    { +        LLAllocator llallocator; +    }; +    typedef test_group<llallocator_data> factory; +    typedef factory::object object; +} +namespace +{ +        tut::factory llallocator_test_factory("LLAllocator"); +} + +namespace tut +{ +    template<> template<> +    void object::test<1>() +    { +        llallocator.setProfilingEnabled(false); +        ensure("Profiler disable", !llallocator.isProfiling()); +    } + +#if LL_USE_TCMALLOC +    template<> template<> +    void object::test<2>() +    { +        llallocator.setProfilingEnabled(true); +        ensure("Profiler enable", llallocator.isProfiling()); +    } + +    template <> template <> +    void object::test<3>() +    { +        llallocator.setProfilingEnabled(true); + +        char * test_alloc = new char[1024]; + +        llallocator.getProfile(); + +        delete [] test_alloc; + +        llallocator.getProfile();         + +        // *NOTE - this test isn't ensuring anything right now other than no +        // exceptions are thrown. +    } +#endif // LL_USE_TCMALLOC +}; diff --git a/indra/llcommon/tests/llmemtype_test.cpp b/indra/llcommon/tests/llmemtype_test.cpp new file mode 100644 index 0000000000..6cc5ce01ce --- /dev/null +++ b/indra/llcommon/tests/llmemtype_test.cpp @@ -0,0 +1,123 @@ +/** + * @file   llmemtype_test.cpp + * @author Palmer Truelson + * @date   2008-03- + * @brief  Test for llmemtype.cpp. + *  + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "../llmemtype.h" +#include "../test/lltut.h" +#include "../llallocator.h" + + +#include <stack> + +std::stack<S32> memTypeStack; + +void LLAllocator::pushMemType(S32 i) +{ +	memTypeStack.push(i); +} + +S32 LLAllocator::popMemType(void) +{ +	S32 ret = memTypeStack.top(); +	memTypeStack.pop(); +	return ret; +} + +namespace tut +{ +    struct llmemtype_data +    { +    }; + +    typedef test_group<llmemtype_data> factory; +    typedef factory::object object; +} +namespace +{ +        tut::factory llmemtype_test_factory("LLMemType"); +} + +namespace tut +{ +    template<> template<> +    void object::test<1>() +    { +        ensure("Simplest test ever", true); +    } + +	// test with no scripts +	template<> template<> +	void object::test<2>() +	{ +		{ +			LLMemType m1(LLMemType::MTYPE_INIT); +		} +		ensure("Test that you can construct and destruct the mem type"); +	} + +	// test creation and stack testing +	template<> template<> +	void object::test<3>() +	{ +		{ +			ensure("Test that creation and destruction properly inc/dec the stack");			 +			ensure_equals(memTypeStack.size(), 0); +			{ +				LLMemType m1(LLMemType::MTYPE_INIT); +				ensure_equals(memTypeStack.size(), 1); +				LLMemType m2(LLMemType::MTYPE_STARTUP); +				ensure_equals(memTypeStack.size(), 2); +			} +			ensure_equals(memTypeStack.size(), 0); +		} +	} + +	// test with no scripts +	template<> template<> +	void object::test<4>() +	{ +		// catch the begining and end +		std::string test_name = LLMemType::getNameFromID(LLMemType::MTYPE_INIT.mID); +		ensure_equals("Init name", test_name, "Init"); + +		std::string test_name2 = LLMemType::getNameFromID(LLMemType::MTYPE_VOLUME.mID); +		ensure_equals("Volume name", test_name2, "Volume"); + +		std::string test_name3 = LLMemType::getNameFromID(LLMemType::MTYPE_OTHER.mID); +		ensure_equals("Other name", test_name3, "Other"); + +        std::string test_name4 = LLMemType::getNameFromID(-1); +        ensure_equals("Invalid name", test_name4, "INVALID"); +	} + +}; | 
