summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/CMakeLists.txt44
-rw-r--r--indra/llcommon/is_approx_equal_fraction.h23
-rw-r--r--indra/llcommon/linden_common.h18
-rw-r--r--indra/llcommon/llallocator.cpp140
-rw-r--r--indra/llcommon/llallocator.h63
-rw-r--r--indra/llcommon/llallocator_heap_profile.cpp149
-rw-r--r--indra/llcommon/llallocator_heap_profile.h77
-rw-r--r--indra/llcommon/llapp.h5
-rw-r--r--indra/llcommon/llassettype.cpp12
-rw-r--r--indra/llcommon/llassettype.h1
-rw-r--r--indra/llcommon/llboost.h15
-rw-r--r--indra/llcommon/llchat.h10
-rw-r--r--indra/llcommon/llcommon.cpp2
-rw-r--r--indra/llcommon/llcommon.h3
-rw-r--r--indra/llcommon/lldate.cpp64
-rw-r--r--indra/llcommon/lldate.h4
-rw-r--r--indra/llcommon/lldeleteutils.h53
-rw-r--r--indra/llcommon/lldependencies.h3
-rwxr-xr-xindra/llcommon/lldoubledispatch.h332
-rw-r--r--indra/llcommon/llerror.cpp17
-rw-r--r--indra/llcommon/llerrorcontrol.h16
-rw-r--r--indra/llcommon/llerrorthread.cpp2
-rw-r--r--indra/llcommon/llevent.h2
-rw-r--r--indra/llcommon/llevents.h11
-rw-r--r--indra/llcommon/llfasttimer.h374
-rw-r--r--indra/llcommon/llfixedbuffer.cpp13
-rw-r--r--indra/llcommon/llfixedbuffer.h22
-rw-r--r--indra/llcommon/llinstancetracker.h121
-rw-r--r--indra/llcommon/llmd5.cpp1
-rw-r--r--indra/llcommon/llmemory.cpp208
-rw-r--r--indra/llcommon/llmemory.h429
-rw-r--r--indra/llcommon/llmemtype.cpp237
-rw-r--r--indra/llcommon/llmemtype.h300
-rw-r--r--indra/llcommon/llmetrics.cpp2
-rw-r--r--indra/llcommon/lloptioninterface.cpp39
-rw-r--r--indra/llcommon/lloptioninterface.h46
-rw-r--r--indra/llcommon/llpointer.h177
-rw-r--r--indra/llcommon/llpreprocessor.h4
-rw-r--r--indra/llcommon/llprocesslauncher.cpp344
-rw-r--r--indra/llcommon/llprocesslauncher.h85
-rw-r--r--indra/llcommon/llptrto.cpp108
-rw-r--r--indra/llcommon/llptrto.h93
-rw-r--r--indra/llcommon/llqueuedthread.cpp2
-rw-r--r--indra/llcommon/llrefcount.cpp49
-rw-r--r--indra/llcommon/llrefcount.h79
-rw-r--r--indra/llcommon/llsafehandle.h167
-rw-r--r--indra/llcommon/llsd.cpp18
-rw-r--r--indra/llcommon/llsdserialize.cpp2
-rw-r--r--indra/llcommon/llsdserialize.h3
-rw-r--r--indra/llcommon/llsdutil.cpp9
-rw-r--r--indra/llcommon/llsdutil.h1
-rw-r--r--indra/llcommon/llsecondlifeurls.cpp34
-rw-r--r--indra/llcommon/llsecondlifeurls.h13
-rw-r--r--indra/llcommon/llsingleton.h165
-rw-r--r--indra/llcommon/llstacktrace.cpp141
-rw-r--r--indra/llcommon/llstacktrace.h44
-rw-r--r--indra/llcommon/llstat.cpp42
-rw-r--r--indra/llcommon/llstat.h25
-rw-r--r--indra/llcommon/llstring.cpp396
-rw-r--r--indra/llcommon/llstring.h115
-rw-r--r--indra/llcommon/llthread.h1
-rw-r--r--indra/llcommon/lltimer.cpp9
-rw-r--r--indra/llcommon/lltimer.h9
-rw-r--r--indra/llcommon/lltreeiterators.h711
-rw-r--r--indra/llcommon/llversionserver.h2
-rw-r--r--indra/llcommon/llversionviewer.h10
-rw-r--r--indra/llcommon/tests/llallocator_heap_profile_test.cpp150
-rw-r--r--indra/llcommon/tests/llallocator_test.cpp86
-rw-r--r--indra/llcommon/tests/llmemtype_test.cpp123
69 files changed, 4950 insertions, 1125 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 7bfcd43684..138dc85459 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,16 @@ set(llcommon_SOURCE_FILES
llmd5.cpp
llmemory.cpp
llmemorystream.cpp
+ llmemtype.cpp
llmetrics.cpp
llmortician.cpp
+ lloptioninterface.cpp
+ llptrto.cpp
+ llprocesslauncher.cpp
llprocessor.cpp
llqueuedthread.cpp
llrand.cpp
+ llrefcount.cpp
llrun.cpp
llsd.cpp
llsdserialize.cpp
@@ -52,6 +66,7 @@ set(llcommon_SOURCE_FILES
llsdutil.cpp
llsecondlifeurls.cpp
llstat.cpp
+ llstacktrace.cpp
llstreamtools.cpp
llstring.cpp
llstringtable.cpp
@@ -78,6 +93,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,9 +115,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
@@ -122,6 +141,7 @@ set(llcommon_HEADER_FILES
llheartbeat.h
llhttpstatuscodes.h
llindexedqueue.h
+ llinstancetracker.h
llkeythrottle.h
lllazy.h
lllinkedqueue.h
@@ -138,23 +158,32 @@ set(llcommon_HEADER_FILES
llmetrics.h
llmortician.h
llnametable.h
+ lloptioninterface.h
+ llpointer.h
llpreprocessor.h
llpriqueuemap.h
+ llprocesslauncher.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
@@ -165,6 +194,7 @@ set(llcommon_HEADER_FILES
llsys.h
llthread.h
lltimer.h
+ lltreeiterators.h
lluri.h
lluuid.h
lluuidhashmap.h
@@ -200,12 +230,22 @@ target_link_libraries(
${APR_LIBRARIES}
${EXPAT_LIBRARIES}
${ZLIB_LIBRARIES}
+ ${BOOST_PROGRAM_OPTIONS_LIBRARY}
+ ${BOOST_REGEX_LIBRARY}
)
include(LLAddBuildTest)
SET(llcommon_TEST_SOURCE_FILES
- # WARNING: Please don't write tests against LLCommon or LLMath until this issue is resolved: https://jira.lindenlab.com/jira/browse/DEV-29456
- # lllazy.cpp
)
LL_ADD_PROJECT_UNIT_TESTS(llcommon "${llcommon_TEST_SOURCE_FILES}")
+#set(TEST_DEBUG on)
+set(test_libs llcommon ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES} ${GOOGLEMOCK_LIBRARIES})
+# Have to treat lllazy test as an integration test until this issue is resolved:
+# https://jira.lindenlab.com/jira/browse/DEV-29456
+LL_ADD_INTEGRATION_TEST(lllazy lllazy.cpp "${test_libs}")
+
+# *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/llapp.h b/indra/llcommon/llapp.h
index cc60ba0b80..e32a293f1c 100644
--- a/indra/llcommon/llapp.h
+++ b/indra/llcommon/llapp.h
@@ -37,6 +37,7 @@
#include "llapr.h"
#include "llrun.h"
#include "llsd.h"
+#include "lloptioninterface.h"
// Forward declarations
class LLErrorThread;
@@ -61,7 +62,7 @@ public:
};
#endif
-class LLApp
+class LLApp : public LLOptionInterface
{
friend class LLErrorThread;
public:
@@ -110,7 +111,7 @@ public:
* @param name The name of the option.
* @return Returns the option data.
*/
- LLSD getOption(const std::string& name) const;
+ virtual LLSD getOption(const std::string& name) const;
/**
* @brief Parse command line options and insert them into
diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp
index b852e4c00f..66c8bcac6a 100644
--- a/indra/llcommon/llassettype.cpp
+++ b/indra/llcommon/llassettype.cpp
@@ -35,6 +35,7 @@
#include "llassettype.h"
#include "lldictionary.h"
#include "llmemory.h"
+#include "llsingleton.h"
///----------------------------------------------------------------------------
/// Class LLAssetType
@@ -100,7 +101,7 @@ LLAssetDictionary::LLAssetDictionary()
addEntry(LLAssetType::AT_IMAGE_TGA, new AssetEntry("IMAGE_TGA", "img_tga", "targa image", "Uncompressed Images", DAD_NONE, FALSE, TRUE));
addEntry(LLAssetType::AT_IMAGE_JPEG, new AssetEntry("IMAGE_JPEG", "jpeg", "jpeg image", "Uncompressed Images", DAD_NONE, FALSE, TRUE));
addEntry(LLAssetType::AT_ANIMATION, new AssetEntry("ANIMATION", "animatn", "animation", "Animations", DAD_ANIMATION, FALSE, TRUE));
- addEntry(LLAssetType::AT_GESTURE, new AssetEntry("GESTURE", "gesture", "gesture", "Gestures", DAD_GESTURE, FALSE, TRUE));
+ addEntry(LLAssetType::AT_GESTURE, new AssetEntry("GESTURE", "gesture", "gesture", "Gestures", DAD_GESTURE, TRUE, TRUE));
addEntry(LLAssetType::AT_SIMSTATE, new AssetEntry("SIMSTATE", "simstate", "simstate", "New Folder", DAD_NONE, FALSE, TRUE));
addEntry(LLAssetType::AT_FAVORITE, new AssetEntry("FAVORITE", "favorite", "favorite", "favorite", DAD_NONE, FALSE, TRUE));
@@ -115,7 +116,7 @@ LLAssetDictionary::LLAssetDictionary()
}
addEntry(LLAssetType::AT_CURRENT_OUTFIT, new AssetEntry("CURRENT", "current", "current outfit", "Current Outfit", DAD_CATEGORY, FALSE, TRUE));
- addEntry(LLAssetType::AT_OUTFIT, new AssetEntry("OUTFIT", "outfit", "outfit", "Outfit", DAD_CATEGORY, TRUE, FALSE));
+ addEntry(LLAssetType::AT_OUTFIT, new AssetEntry("OUTFIT", "outfit", "outfit", "New Outfit", DAD_CATEGORY, TRUE, FALSE));
addEntry(LLAssetType::AT_MY_OUTFITS, new AssetEntry("MY_OUTFITS", "my_otfts", "my outfits", "My Outfits", DAD_CATEGORY, FALSE, TRUE));
addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, "New Folder", DAD_NONE, FALSE, FALSE));
@@ -281,6 +282,13 @@ bool LLAssetType::lookupIsProtectedCategoryType(EType asset_type)
return true;
}
+// static
+bool LLAssetType::lookupIsEnsembleCategoryType(EType asset_type)
+{
+ return (asset_type >= AT_FOLDER_ENSEMBLE_START &&
+ asset_type <= AT_FOLDER_ENSEMBLE_END);
+}
+
// static. Generate a good default description
void LLAssetType::generateDescriptionFor(LLAssetType::EType asset_type,
diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h
index 5c30c8354f..880b7a19b5 100644
--- a/indra/llcommon/llassettype.h
+++ b/indra/llcommon/llassettype.h
@@ -187,6 +187,7 @@ public:
static const char* lookupCategoryName(EType asset_type);
static bool lookupIsProtectedCategoryType(EType asset_type);
+ static bool lookupIsEnsembleCategoryType(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().
diff --git a/indra/llcommon/llboost.h b/indra/llcommon/llboost.h
index 4df9dbf3bd..c2bde3a097 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 return a bool (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/llchat.h b/indra/llcommon/llchat.h
index 7b010d6739..acd0da61a4 100644
--- a/indra/llcommon/llchat.h
+++ b/indra/llcommon/llchat.h
@@ -65,6 +65,12 @@ typedef enum e_chat_audible_level
CHAT_AUDIBLE_FULLY = 1
} EChatAudible;
+typedef enum e_chat_style
+{
+ CHAT_STYLE_NORMAL,
+ CHAT_STYLE_IRC
+}EChatStyle;
+
// A piece of chat
class LLChat
{
@@ -79,7 +85,8 @@ public:
mMuted(FALSE),
mTime(0.0),
mPosAgent(),
- mURL()
+ mURL(),
+ mChatStyle(CHAT_STYLE_NORMAL)
{ }
std::string mText; // UTF-8 line of text
@@ -92,6 +99,7 @@ public:
F64 mTime; // viewer only, seconds from viewer start
LLVector3 mPosAgent;
std::string mURL;
+ EChatStyle mChatStyle;
};
#endif
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..6a82a848be 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,42 @@ 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
+LLFastTimer::DeclareTimer FT_DATE_FORMAT("Date Format");
+
+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);
+ LLFastTimer ft1(FT_DATE_FORMAT);
+
+ 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)
+{
+ LLFastTimer ft1(FT_DATE_FORMAT);
+
+ 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)
+{
+ LLFastTimer ft1(FT_DATE_FORMAT);
- // 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 std::time_put<char>& tp = std::use_facet<std::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/lldependencies.h b/indra/llcommon/lldependencies.h
index bd4bd7c96a..82f53c6e17 100644
--- a/indra/llcommon/lldependencies.h
+++ b/indra/llcommon/lldependencies.h
@@ -581,6 +581,8 @@ public:
return sorted_range(begin, end);
}
+ using LLDependenciesBase::describe; // unhide virtual std::string describe(bool full=true) const;
+
/// Override base-class describe() with actual implementation
virtual std::ostream& describe(std::ostream& out, bool full=true) const
{
@@ -597,6 +599,7 @@ public:
return out;
}
+
/// describe() helper: report a DepNodeEntry
static std::ostream& describe(std::ostream& out, std::string& sep,
const DepNodeMapEntry& entry, bool full)
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*>(&param1) &&
+ dynamic_cast<const Type2*>(&param2));
+ }
+ /// 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/llerror.cpp b/indra/llcommon/llerror.cpp
index 8102eddb18..77c0c2294a 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -53,12 +53,11 @@
#include "llapp.h"
#include "llapr.h"
#include "llfile.h"
-#include "llfixedbuffer.h"
#include "lllivefile.h"
#include "llsd.h"
#include "llsdserialize.h"
#include "llstl.h"
-
+#include "lltimer.h"
namespace {
#if !LL_WINDOWS
@@ -192,16 +191,16 @@ namespace {
class RecordToFixedBuffer : public LLError::Recorder
{
public:
- RecordToFixedBuffer(LLFixedBuffer& buffer) : mBuffer(buffer) { }
+ RecordToFixedBuffer(LLLineBuffer* buffer) : mBuffer(buffer) { }
virtual void recordMessage(LLError::ELevel level,
- const std::string& message)
+ const std::string& message)
{
- mBuffer.addLine(message);
+ mBuffer->addLine(message);
}
private:
- LLFixedBuffer& mBuffer;
+ LLLineBuffer* mBuffer;
};
#if LL_WINDOWS
@@ -209,7 +208,7 @@ namespace {
{
public:
virtual void recordMessage(LLError::ELevel level,
- const std::string& message)
+ const std::string& message)
{
llutf16string utf16str =
wstring_to_utf16str(utf8str_to_wstring(message));
@@ -792,7 +791,7 @@ namespace LLError
addRecorder(f);
}
- void logToFixedBuffer(LLFixedBuffer* fixedBuffer)
+ void logToFixedBuffer(LLLineBuffer* fixedBuffer)
{
LLError::Settings& s = LLError::Settings::get();
@@ -805,7 +804,7 @@ namespace LLError
return;
}
- s.fixedBufferRecorder = new RecordToFixedBuffer(*fixedBuffer);
+ s.fixedBufferRecorder = new RecordToFixedBuffer(fixedBuffer);
addRecorder(s.fixedBufferRecorder);
}
diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h
index c9424f8a5e..fab0a1ef9f 100644
--- a/indra/llcommon/llerrorcontrol.h
+++ b/indra/llcommon/llerrorcontrol.h
@@ -38,7 +38,6 @@
#include "boost/function.hpp"
#include <string>
-class LLFixedBuffer;
class LLSD;
/*
@@ -49,6 +48,18 @@ class LLSD;
These implementations are in llerror.cpp.
*/
+// Line buffer interface
+class LLLineBuffer
+{
+public:
+ LLLineBuffer() {};
+ virtual ~LLLineBuffer() {};
+
+ virtual void clear() = 0; // Clear the buffer, and reset it.
+
+ virtual void addLine(const std::string& utf8line) = 0;
+};
+
namespace LLError
{
@@ -73,6 +84,7 @@ namespace LLError
void setFunctionLevel(const std::string& function_name, LLError::ELevel);
void setClassLevel(const std::string& class_name, LLError::ELevel);
void setFileLevel(const std::string& file_name, LLError::ELevel);
+ void setTagLevel(const std::string& file_name, LLError::ELevel);
void configure(const LLSD&);
// the LLSD can configure all of the settings
@@ -143,7 +155,7 @@ namespace LLError
// each error message is passed to each recorder via recordMessage()
void logToFile(const std::string& filename);
- void logToFixedBuffer(LLFixedBuffer*);
+ void logToFixedBuffer(LLLineBuffer*);
// Utilities to add recorders for logging to a file or a fixed buffer
// A second call to the same function will remove the logger added
// with the first.
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..240adcdd41 100644
--- a/indra/llcommon/llevents.h
+++ b/indra/llcommon/llevents.h
@@ -22,7 +22,16 @@
#include <list>
#include <deque>
#include <stdexcept>
+#if LL_WINDOWS
+ #pragma warning (push)
+ #pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch
+ #pragma warning (disable : 4264)
+#endif
#include <boost/signals2.hpp>
+#if LL_WINDOWS
+ #pragma warning (pop)
+#endif
+
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
@@ -38,7 +47,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..0d89353dee 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -30,229 +30,215 @@
* $/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() const { return mCollapsed; }
+
+ U64 getCountAverage() const { return mCountAverage; }
+ U64 getCallAverage() const { return mCallAverage; }
+
+ U64 getHistoricalCount(S32 history_index = 0) const;
+ U64 getHistoricalCalls(S32 history_index = 0) const;
+
+ 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;
+ };
+
+
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();
-
- sStart[sCurDepth] = cpu_clocks;
- sCurDepth++;
+ 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;
#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);
+ static const NamedTimer* getTimerByName(const std::string& name);
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/llfixedbuffer.cpp b/indra/llcommon/llfixedbuffer.cpp
index e9d6029378..1f6a06c247 100644
--- a/indra/llcommon/llfixedbuffer.cpp
+++ b/indra/llcommon/llfixedbuffer.cpp
@@ -32,20 +32,21 @@
#include "llfixedbuffer.h"
+////////////////////////////////////////////////////////////////////////////
+
LLFixedBuffer::LLFixedBuffer(const U32 max_lines)
- : mMutex(NULL)
+ : LLLineBuffer(),
+ mMaxLines(max_lines),
+ mMutex(NULL)
{
- mMaxLines = max_lines;
mTimer.reset();
}
-
LLFixedBuffer::~LLFixedBuffer()
{
clear();
}
-
void LLFixedBuffer::clear()
{
mMutex.lock() ;
@@ -61,10 +62,10 @@ void LLFixedBuffer::clear()
void LLFixedBuffer::addLine(const std::string& utf8line)
{
LLWString wstring = utf8str_to_wstring(utf8line);
- LLFixedBuffer::addLine(wstring);
+ addWLine(wstring);
}
-void LLFixedBuffer::addLine(const LLWString& line)
+void LLFixedBuffer::addWLine(const LLWString& line)
{
if (line.empty())
{
diff --git a/indra/llcommon/llfixedbuffer.h b/indra/llcommon/llfixedbuffer.h
index 992a024df1..01b46d327a 100644
--- a/indra/llcommon/llfixedbuffer.h
+++ b/indra/llcommon/llfixedbuffer.h
@@ -38,14 +38,14 @@
#include <string>
#include "llstring.h"
#include "llthread.h"
+#include "llerrorcontrol.h"
-// Fixed size buffer for console output and other things.
-
-class LLFixedBuffer
+// fixed buffer implementation
+class LLFixedBuffer : public LLLineBuffer
{
public:
LLFixedBuffer(const U32 max_lines = 20);
- virtual ~LLFixedBuffer();
+ ~LLFixedBuffer();
LLTimer mTimer;
U32 mMaxLines;
@@ -53,22 +53,18 @@ public:
std::deque<F32> mAddTimes;
std::deque<S32> mLineLengths;
- void clear(); // Clear the buffer, and reset it.
+ /*virtual*/ void clear(); // Clear the buffer, and reset it.
- //do not make these two "virtual"
- void addLine(const std::string& utf8line);
- void addLine(const LLWString& line);
+ /*virtual*/ void addLine(const std::string& utf8line);
- // Get lines currently in the buffer, up to max_size chars, max_length lines
- char *getLines(U32 max_size = 0, U32 max_length = 0);
void setMaxLines(S32 max_lines);
+
protected:
- virtual void removeExtraLines();
+ void removeExtraLines();
+ void addWLine(const LLWString& line);
protected:
LLMutex mMutex ;
};
-const U32 FIXED_BUF_MAX_LINE_LEN = 255; // Not including termnating 0
-
#endif //LL_FIXED_BUFFER_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/llmetrics.cpp b/indra/llcommon/llmetrics.cpp
index 8db3284c42..30e5d435ae 100644
--- a/indra/llcommon/llmetrics.cpp
+++ b/indra/llcommon/llmetrics.cpp
@@ -71,7 +71,7 @@ void LLMetricsImpl::recordEventDetails(const std::string& location,
metrics["location"] = location;
metrics["stats"] = stats;
- llinfos << "LLMETRICS: " << LLSDNotationStreamer(metrics) << llendl;
+ llinfos << "LLMETRICS: " << (LLSDNotationStreamer(metrics)) << llendl;
}
// Store this:
diff --git a/indra/llcommon/lloptioninterface.cpp b/indra/llcommon/lloptioninterface.cpp
new file mode 100644
index 0000000000..68c1ff1c41
--- /dev/null
+++ b/indra/llcommon/lloptioninterface.cpp
@@ -0,0 +1,39 @@
+/**
+ * @file lloptioninterface.cpp
+ * @brief
+ *
+ * $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$
+ */
+
+#include "lloptioninterface.h"
+
+
+LLOptionInterface::~LLOptionInterface()
+{
+
+}
diff --git a/indra/llcommon/lloptioninterface.h b/indra/llcommon/lloptioninterface.h
new file mode 100644
index 0000000000..4faf95f5e1
--- /dev/null
+++ b/indra/llcommon/lloptioninterface.h
@@ -0,0 +1,46 @@
+/**
+ * @file lloptioninterface.h
+ * @brief
+ *
+ * $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_LLOPTIONINTERFACE_H
+#define LL_LLOPTIONINTERFACE_H
+
+#include "linden_common.h"
+
+class LLSD;
+class LLOptionInterface
+{
+public:
+ virtual ~LLOptionInterface() = 0;
+ virtual LLSD getOption(const std::string& name) const = 0;
+};
+
+#endif
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/llpreprocessor.h b/indra/llcommon/llpreprocessor.h
index 2e4fd4787a..4401be1679 100644
--- a/indra/llcommon/llpreprocessor.h
+++ b/indra/llcommon/llpreprocessor.h
@@ -127,8 +127,10 @@ using snprintf_hack::snprintf;
#pragma warning( 3 : 4702 ) // "unreachable code" Treat this as level 3, not level 4.
#pragma warning( 3 : 4189 ) // "local variable initialized but not referenced" Treat this as level 3, not level 4.
//#pragma warning( 3 : 4018 ) // "signed/unsigned mismatch" Treat this as level 3, not level 4.
+#pragma warning( 3 : 4263 ) // 'function' : member function does not override any base class virtual member function
+#pragma warning( 3 : 4264 ) // "'virtual_function' : no override available for virtual member function from base 'class'; function is hidden"
#pragma warning( 3 : 4265 ) // "class has virtual functions, but destructor is not virtual"
-#pragma warning( disable : 4786 ) // silly MS warning deep inside their <map> include file
+#pragma warning( 3 : 4266 ) // 'function' : no override available for virtual member function from base 'type'; function is hidden
#pragma warning( disable : 4284 ) // silly MS warning deep inside their <map> include file
#pragma warning( disable : 4503 ) // 'decorated name length exceeded, name was truncated'. Does not seem to affect compilation.
#pragma warning( disable : 4800 ) // 'BOOL' : forcing value to bool 'true' or 'false' (performance warning)
diff --git a/indra/llcommon/llprocesslauncher.cpp b/indra/llcommon/llprocesslauncher.cpp
new file mode 100644
index 0000000000..f0315e92eb
--- /dev/null
+++ b/indra/llcommon/llprocesslauncher.cpp
@@ -0,0 +1,344 @@
+/**
+ * @file llprocesslauncher.cpp
+ * @brief Utility class for launching, terminating, and tracking the state of processes.
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ *
+ * Copyright (c) 2008, 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$
+ */
+
+#include "linden_common.h"
+
+#include "llprocesslauncher.h"
+
+#include <iostream>
+#if LL_DARWIN || LL_LINUX
+// not required or present on Win32
+#include <sys/wait.h>
+#endif
+
+LLProcessLauncher::LLProcessLauncher()
+{
+#if LL_WINDOWS
+ mProcessHandle = 0;
+#else
+ mProcessID = 0;
+#endif
+}
+
+LLProcessLauncher::~LLProcessLauncher()
+{
+ kill();
+}
+
+void LLProcessLauncher::setExecutable(const std::string &executable)
+{
+ mExecutable = executable;
+}
+
+void LLProcessLauncher::setWorkingDirectory(const std::string &dir)
+{
+ mWorkingDir = dir;
+}
+
+void LLProcessLauncher::clearArguments()
+{
+ mLaunchArguments.clear();
+}
+
+void LLProcessLauncher::addArgument(const std::string &arg)
+{
+ mLaunchArguments.push_back(arg);
+}
+
+void LLProcessLauncher::addArgument(const char *arg)
+{
+ mLaunchArguments.push_back(std::string(arg));
+}
+
+#if LL_WINDOWS
+
+int LLProcessLauncher::launch(void)
+{
+ // If there was already a process associated with this object, kill it.
+ kill();
+ orphan();
+
+ int result = 0;
+
+ PROCESS_INFORMATION pinfo;
+ STARTUPINFOA sinfo;
+ memset(&sinfo, 0, sizeof(sinfo));
+
+ std::string args = mExecutable;
+ for(int i = 0; i < (int)mLaunchArguments.size(); i++)
+ {
+ args += " ";
+ args += mLaunchArguments[i];
+ }
+
+ // So retarded. Windows requires that the second parameter to CreateProcessA be a writable (non-const) string...
+ char *args2 = new char[args.size() + 1];
+ strcpy(args2, args.c_str());
+
+ if( ! CreateProcessA( NULL, args2, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo ) )
+ {
+ // TODO: do better than returning the OS-specific error code on failure...
+ result = GetLastError();
+ if(result == 0)
+ {
+ // Make absolutely certain we return a non-zero value on failure.
+ result = -1;
+ }
+ }
+ else
+ {
+ // foo = pinfo.dwProcessId; // get your pid here if you want to use it later on
+ // CloseHandle(pinfo.hProcess); // stops leaks - nothing else
+ mProcessHandle = pinfo.hProcess;
+ CloseHandle(pinfo.hThread); // stops leaks - nothing else
+ }
+
+ delete[] args2;
+
+ return result;
+}
+
+bool LLProcessLauncher::isRunning(void)
+{
+ if(mProcessHandle != 0)
+ {
+ DWORD waitresult = WaitForSingleObject(mProcessHandle, 0);
+ if(waitresult == WAIT_OBJECT_0)
+ {
+ // the process has completed.
+ mProcessHandle = 0;
+ }
+ }
+
+ return (mProcessHandle != 0);
+}
+bool LLProcessLauncher::kill(void)
+{
+ bool result = true;
+
+ if(mProcessHandle != 0)
+ {
+ TerminateProcess(mProcessHandle,0);
+
+ if(isRunning())
+ {
+ result = false;
+ }
+ }
+
+ return result;
+}
+
+void LLProcessLauncher::orphan(void)
+{
+ // Forget about the process
+ mProcessHandle = 0;
+}
+
+// static
+void LLProcessLauncher::reap(void)
+{
+ // No actions necessary on Windows.
+}
+
+#else // Mac and linux
+
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+
+static std::list<pid_t> sZombies;
+
+// Attempt to reap a process ID -- returns true if the process has exited and been reaped, false otherwise.
+static bool reap_pid(pid_t pid)
+{
+ bool result = false;
+
+ pid_t wait_result = ::waitpid(pid, NULL, WNOHANG);
+ if(wait_result == pid)
+ {
+ result = true;
+ }
+ else if(wait_result == -1)
+ {
+ if(errno == ECHILD)
+ {
+ // No such process -- this may mean we're ignoring SIGCHILD.
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+int LLProcessLauncher::launch(void)
+{
+ // If there was already a process associated with this object, kill it.
+ kill();
+ orphan();
+
+ int result = 0;
+ int current_wd = -1;
+
+ // create an argv vector for the child process
+ const char ** fake_argv = new const char *[mLaunchArguments.size() + 2]; // 1 for the executable path, 1 for the NULL terminator
+
+ int i = 0;
+
+ // add the executable path
+ fake_argv[i++] = mExecutable.c_str();
+
+ // and any arguments
+ for(int j=0; j < mLaunchArguments.size(); j++)
+ fake_argv[i++] = mLaunchArguments[j].c_str();
+
+ // terminate with a null pointer
+ fake_argv[i] = NULL;
+
+ if(!mWorkingDir.empty())
+ {
+ // save the current working directory
+ current_wd = ::open(".", O_RDONLY);
+
+ // and change to the one the child will be executed in
+ if (::chdir(mWorkingDir.c_str()))
+ {
+ // chdir failed
+ }
+ }
+
+ // flush all buffers before the child inherits them
+ ::fflush(NULL);
+
+ pid_t id = vfork();
+ if(id == 0)
+ {
+ // child process
+
+ ::execv(mExecutable.c_str(), (char * const *)fake_argv);
+
+ // If we reach this point, the exec failed.
+ // Use _exit() instead of exit() per the vfork man page.
+ _exit(0);
+ }
+
+ // parent process
+
+ if(current_wd >= 0)
+ {
+ // restore the previous working directory
+ if (::fchdir(current_wd))
+ {
+ // chdir failed
+ }
+ ::close(current_wd);
+ }
+
+ delete[] fake_argv;
+
+ mProcessID = id;
+
+ // At this point, the child process will have been created (since that's how vfork works -- the child borrowed our execution context until it forked)
+ // If the process doesn't exist at this point, the exec failed.
+ if(!isRunning())
+ {
+ result = -1;
+ }
+
+ return result;
+}
+
+bool LLProcessLauncher::isRunning(void)
+{
+ if(mProcessID != 0)
+ {
+ // Check whether the process has exited, and reap it if it has.
+ if(reap_pid(mProcessID))
+ {
+ // the process has exited.
+ mProcessID = 0;
+ }
+ }
+
+ return (mProcessID != 0);
+}
+
+bool LLProcessLauncher::kill(void)
+{
+ bool result = true;
+
+ if(mProcessID != 0)
+ {
+ // Try to kill the process. We'll do approximately the same thing whether the kill returns an error or not, so we ignore the result.
+ (void)::kill(mProcessID, SIGTERM);
+
+ // This will have the side-effect of reaping the zombie if the process has exited.
+ if(isRunning())
+ {
+ result = false;
+ }
+ }
+
+ return result;
+}
+
+void LLProcessLauncher::orphan(void)
+{
+ // Disassociate the process from this object
+ if(mProcessID != 0)
+ {
+ // We may still need to reap the process's zombie eventually
+ sZombies.push_back(mProcessID);
+
+ mProcessID = 0;
+ }
+}
+
+// static
+void LLProcessLauncher::reap(void)
+{
+ // Attempt to real all saved process ID's.
+
+ std::list<pid_t>::iterator iter = sZombies.begin();
+ while(iter != sZombies.end())
+ {
+ if(reap_pid(*iter))
+ {
+ iter = sZombies.erase(iter);
+ }
+ else
+ {
+ iter++;
+ }
+ }
+}
+
+#endif
diff --git a/indra/llcommon/llprocesslauncher.h b/indra/llcommon/llprocesslauncher.h
new file mode 100644
index 0000000000..a1b8e22691
--- /dev/null
+++ b/indra/llcommon/llprocesslauncher.h
@@ -0,0 +1,85 @@
+/**
+ * @file llprocesslauncher.h
+ * @brief Utility class for launching, terminating, and tracking the state of processes.
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ *
+ * Copyright (c) 2008, 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_LLPROCESSLAUNCHER_H
+#define LL_LLPROCESSLAUNCHER_H
+
+#if LL_WINDOWS
+#include <windows.h>
+#endif
+
+
+/*
+ LLProcessLauncher handles launching external processes with specified command line arguments.
+ It also keeps track of whether the process is still running, and can kill it if required.
+*/
+
+class LLProcessLauncher
+{
+ LOG_CLASS(LLProcessLauncher);
+public:
+ LLProcessLauncher();
+ virtual ~LLProcessLauncher();
+
+ void setExecutable(const std::string &executable);
+ void setWorkingDirectory(const std::string &dir);
+
+ void clearArguments();
+ void addArgument(const std::string &arg);
+ void addArgument(const char *arg);
+
+ int launch(void);
+ bool isRunning(void);
+
+ // Attempt to kill the process -- returns true if the process is no longer running when it returns.
+ // Note that even if this returns false, the process may exit some time after it's called.
+ bool kill(void);
+
+ // Use this if you want the external process to continue execution after the LLProcessLauncher instance controlling it is deleted.
+ // Normally, the destructor will attempt to kill the process and wait for termination.
+ // This should only be used if the viewer is about to exit -- otherwise, the child process will become a zombie after it exits.
+ void orphan(void);
+
+ // This needs to be called periodically on Mac/Linux to clean up zombie processes.
+ static void reap(void);
+private:
+ std::string mExecutable;
+ std::string mWorkingDir;
+ std::vector<std::string> mLaunchArguments;
+
+#if LL_WINDOWS
+ HANDLE mProcessHandle;
+#else
+ pid_t mProcessID;
+#endif
+};
+
+#endif // LL_LLPROCESSLAUNCHER_H
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..d3597b454c
--- /dev/null
+++ b/indra/llcommon/llrefcount.h
@@ -0,0 +1,79 @@
+/**
+ * @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
+
+#include <boost/noncopyable.hpp>
+
+//----------------------------------------------------------------------------
+// RefCount objects should generally only be accessed by way of LLPointer<>'s
+// see llthread.h for LLThreadSafeRefCount
+//----------------------------------------------------------------------------
+
+class LLRefCount
+{
+protected:
+ LLRefCount(const LLRefCount& other); // no implementation
+private:
+ LLRefCount& operator=(const LLRefCount&); // no implementation
+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/llsd.cpp b/indra/llcommon/llsd.cpp
index 2cc94c2914..9140ebb3f3 100644
--- a/indra/llcommon/llsd.cpp
+++ b/indra/llcommon/llsd.cpp
@@ -162,6 +162,7 @@ namespace
virtual LLSD::Type type() const { return T; }
+ using LLSD::Impl::assign; // Unhiding base class virtuals...
virtual void assign(LLSD::Impl*& var, DataRef value) {
if (shared())
{
@@ -349,6 +350,10 @@ namespace
virtual LLSD::Boolean asBoolean() const { return !mData.empty(); }
virtual bool has(const LLSD::String&) const;
+
+ using LLSD::Impl::get; // Unhiding get(LLSD::Integer)
+ using LLSD::Impl::erase; // Unhiding erase(LLSD::Integer)
+ using LLSD::Impl::ref; // Unhiding ref(LLSD::Integer)
virtual LLSD get(const LLSD::String&) const;
LLSD& insert(const LLSD::String& k, const LLSD& v);
virtual void erase(const LLSD::String&);
@@ -439,6 +444,9 @@ namespace
virtual LLSD::Boolean asBoolean() const { return !mData.empty(); }
+ using LLSD::Impl::get; // Unhiding get(LLSD::String)
+ using LLSD::Impl::erase; // Unhiding erase(LLSD::String)
+ using LLSD::Impl::ref; // Unhiding ref(LLSD::String)
virtual int size() const;
virtual LLSD get(LLSD::Integer) const;
void set(LLSD::Integer, const LLSD&);
@@ -811,9 +819,15 @@ static const char *llsd_dump(const LLSD &llsd, bool useXMLFormat)
{
std::ostringstream out;
if (useXMLFormat)
- out << LLSDXMLStreamer(llsd);
+ {
+ LLSDXMLStreamer xml_streamer(llsd);
+ out << xml_streamer;
+ }
else
- out << LLSDNotationStreamer(llsd);
+ {
+ LLSDNotationStreamer notation_streamer(llsd);
+ out << notation_streamer;
+ }
out_string = out.str();
}
int len = out_string.length();
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..2e7d845bf7
--- /dev/null
+++ b/indra/llcommon/llsingleton.h
@@ -0,0 +1,165 @@
+/**
+ * @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 been created uet?
+ // Use this to avoid accessing singletons before the can safely be constructed
+ static bool instanceExists()
+ {
+ return getData().mInitState == INITIALIZED;
+ }
+
+ // 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 e650f911b7..0bd2609f4a 100644
--- a/indra/llcommon/llstat.cpp
+++ b/indra/llcommon/llstat.cpp
@@ -46,6 +46,7 @@
S32 LLPerfBlock::sStatsFlags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS; // Control what is being recorded
LLPerfBlock::stat_map_t LLPerfBlock::sStatMap; // Map full path string to LLStatTime objects, tracks all active objects
std::string LLPerfBlock::sCurrentStatPath = ""; // Something like "/total_time/physics/physics step"
+LLStat::stat_map_t LLStat::sStatList;
//------------------------------------------------------------------------
// Live config file to trigger stats logging
@@ -754,28 +755,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()
@@ -784,6 +805,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 e2e904bb06..76aa3963f4 100644
--- a/indra/llcommon/llstat.h
+++ b/indra/llcommon/llstat.h
@@ -267,8 +267,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();
@@ -331,8 +338,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..78e835dc95 100644
--- a/indra/llcommon/llstring.cpp
+++ b/indra/llcommon/llstring.cpp
@@ -42,6 +42,9 @@
#include <winnls.h> // for WideCharToMultiByte
#endif
+LLFastTimer::DeclareTimer FT_STRING_FORMAT("String Format");
+
+
std::string ll_safe_string(const char* in)
{
if(in) return std::string(in);
@@ -71,6 +74,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 +671,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 +687,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
@@ -697,12 +776,12 @@ namespace LLStringFn
// https://wiki.lindenlab.com/wiki/Unicode_Guidelines has details on
// allowable code points for XML. Specifically, they are:
// 0x09, 0x0a, 0x0d, and 0x20 on up. JC
- std::string strip_invalid_xml(const std::string& input)
+ std::string strip_invalid_xml(const std::string& instr)
{
std::string output;
- output.reserve( input.size() );
- std::string::const_iterator it = input.begin();
- while (it != input.end())
+ output.reserve( instr.size() );
+ std::string::const_iterator it = instr.begin();
+ while (it != instr.end())
{
// Must compare as unsigned for >=
// Test most likely match first
@@ -738,6 +817,315 @@ namespace LLStringFn
}
}
+////////////////////////////////////////////////////////////
+
+//static
+template<>
+void LLStringUtil::getTokens(const std::string& instr, std::vector<std::string >& tokens, const std::string& delims)
+{
+ std::string currToken;
+ std::string::size_type begIdx, endIdx;
+
+ begIdx = instr.find_first_not_of (delims);
+ while (begIdx != std::string::npos)
+ {
+ endIdx = instr.find_first_of (delims, begIdx);
+ if (endIdx == std::string::npos)
+ {
+ endIdx = instr.length();
+ }
+
+ currToken = instr.substr(begIdx, endIdx - begIdx);
+ LLStringUtil::trim (currToken);
+ tokens.push_back(currToken);
+ begIdx = instr.find_first_not_of (delims, endIdx);
+ }
+}
+
+template<>
+LLStringUtil::size_type LLStringUtil::getSubstitution(const std::string& instr, size_type& start, std::vector<std::string>& tokens)
+{
+ const std::string delims (",");
+
+ // Find the first ]
+ size_type pos2 = instr.find(']', start);
+ if (pos2 == std::string::npos)
+ return std::string::npos;
+
+ // Find the last [ before ]
+ size_type pos1 = instr.find_last_of('[', pos2-1);
+ if (pos1 == std::string::npos || pos1 < start)
+ return std::string::npos;
+
+ getTokens(std::string(instr,pos1+1,pos2-pos1-1), tokens, delims);
+ start = pos2+1;
+
+ return pos1;
+}
+
+// static
+template<>
+bool LLStringUtil::simpleReplacement(std::string &replacement, std::string token, const format_map_t& 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.
+ format_map_t::const_iterator iter = substitutions.find(token);
+ if (iter != substitutions.end())
+ {
+ replacement = iter->second;
+ return true;
+ }
+ // if not, see if there's one WITH brackets
+ iter = substitutions.find(std::string("[" + token + "]"));
+ if (iter != substitutions.end())
+ {
+ replacement = iter->second;
+ return true;
+ }
+
+ return false;
+}
+
+// static
+template<>
+bool LLStringUtil::simpleReplacement(std::string &replacement, std::string 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::string("[" + token + "]")))
+ {
+ replacement = substitutions[std::string("[" + token + "]")].asString();
+ return true;
+ }
+
+ return false;
+}
+
+// static
+template<>
+void LLStringUtil::formatNumber(std::string& numStr, std::string decimals)
+{
+ std::stringstream 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<>
+bool LLStringUtil::formatDatetime(std::string& replacement, std::string token,
+ std::string param, S32 secFromEpoch)
+{
+ 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;
+ }
+}
+
+// LLStringUtil::format recogizes the following patterns.
+// All substitutions *must* be encased in []'s in the input string.
+// The []'s are optional in the substitution map.
+// [FOO_123]
+// [FOO,number,precision]
+// [FOO,datetime,format]
+
+
+// static
+template<>
+S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions)
+{
+ LLFastTimer ft(FT_STRING_FORMAT);
+ S32 res = 0;
+
+ std::string output;
+ std::vector<std::string> tokens;
+
+ std::string::size_type start = 0;
+ std::string::size_type prev_start = 0;
+ std::string::size_type key_start = 0;
+ while ((key_start = getSubstitution(s, start, tokens)) != std::string::npos)
+ {
+ output += std::string(s, prev_start, key_start-prev_start);
+ prev_start = start;
+
+ bool found_replacement = false;
+ std::string replacement;
+
+ if (tokens.size() == 1)
+ {
+ found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
+ }
+ else if (tokens[1] == "number")
+ {
+ std::string param = "0";
+
+ 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")
+ {
+ std::string param;
+ if (tokens.size() > 2) param = tokens[2];
+
+ format_map_t::const_iterator iter = substitutions.find("datetime");
+ if (iter != substitutions.end())
+ {
+ S32 secFromEpoch = 0;
+ BOOL r = LLStringUtil::convertToS32(iter->second, secFromEpoch);
+ if (r)
+ {
+ found_replacement = formatDatetime(replacement, tokens[0], param, secFromEpoch);
+ }
+ }
+ }
+
+ if (found_replacement)
+ {
+ output += replacement;
+ res++;
+ }
+ else
+ {
+ // 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::string("[") + tokens[0] + std::string("]");
+ }
+ tokens.clear();
+ }
+ // send the remainder of the string (with no further matches for bracketed names)
+ output += std::string(s, start);
+ s = output;
+ return res;
+}
+
+//static
+template<>
+S32 LLStringUtil::format(std::string& s, const LLSD& substitutions)
+{
+ LLFastTimer ft(FT_STRING_FORMAT);
+ S32 res = 0;
+
+ if (!substitutions.isMap())
+ {
+ return res;
+ }
+
+ std::string output;
+ std::vector<std::string> tokens;
+
+ std::string::size_type start = 0;
+ std::string::size_type prev_start = 0;
+ std::string::size_type key_start = 0;
+ while ((key_start = getSubstitution(s, start, tokens)) != std::string::npos)
+ {
+ output += std::string(s, prev_start, key_start-prev_start);
+ prev_start = start;
+
+ bool found_replacement = false;
+ std::string replacement;
+
+ if (tokens.size() == 1)
+ {
+ found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
+ }
+ else if (tokens[1] == "number")
+ {
+ std::string param = "0";
+
+ 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")
+ {
+ std::string param;
+ if (tokens.size() > 2) param = tokens[2];
+
+ S32 secFromEpoch = (S32) substitutions["datetime"].asInteger();
+ found_replacement = formatDatetime (replacement, tokens[0], param, secFromEpoch);
+ }
+
+ if (found_replacement)
+ {
+ output += replacement;
+ res++;
+ }
+ else
+ {
+ // 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::string("[") + tokens[0] + std::string("]");
+ }
+ tokens.clear();
+ }
+ // send the remainder of the string (with no further matches for bracketed names)
+ output += std::string(s, start);
+ s = output;
+ return res;
+}
////////////////////////////////////////////////////////////
// Testing
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 6ba665b8d2..3b1379c76a 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -34,6 +34,11 @@
#define LL_LLSTRING_H
#include <string>
+#include <locale>
+#include <iomanip>
+#include <boost/regex.hpp>
+#include "llsd.h"
+#include "llfasttimer.h"
#if LL_LINUX || LL_SOLARIS
#include <wctype.h>
@@ -145,6 +150,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 +183,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 +218,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 +231,16 @@ public:
static std::basic_string<T> null;
typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t;
- static S32 format(std::basic_string<T>& s, const format_map_t& fmt_map);
+ static void getTokens(const std::basic_string<T>& instr, std::vector<std::basic_string<T> >& tokens, const std::basic_string<T>& delims);
+ static size_type getSubstitution(const std::basic_string<T>& instr, size_type& start, 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, S32 secFromEpoch);
+ static S32 format(std::basic_string<T>& s, const format_map_t& substitutions);
+ static S32 format(std::basic_string<T>& s, const LLSD& substitutions);
+ static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const format_map_t& substitutions);
+ 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)
{
@@ -253,7 +282,8 @@ public:
static void replaceTabsWithSpaces( std::basic_string<T>& string, size_type spaces_per_tab );
static void replaceNonstandardASCII( std::basic_string<T>& string, T replacement );
static void replaceChar( std::basic_string<T>& string, T target, T replacement );
-
+ static void replaceString( std::basic_string<T>& string, std::basic_string<T> target, std::basic_string<T> replacement );
+
static BOOL containsNonprintable(const std::basic_string<T>& string);
static void stripNonprintable(std::basic_string<T>& string);
@@ -310,6 +340,9 @@ public:
// Copies src into dst at a given offset.
static void copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset);
+ static bool isPartOfWord(T c) { return (c == (T)'_') || LLStringOps::isAlnum(c); }
+
+
#ifdef _DEBUG
static void testHarness();
#endif
@@ -317,6 +350,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 +412,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
@@ -563,63 +598,12 @@ namespace LLStringFn
}
////////////////////////////////////////////////////////////
+// NOTE: LLStringUtil::format, getTokens, and support functions moved to llstring.cpp.
+// There is no LLWStringUtil::format implementation currently.
+// Calling thse for anything other than LLStringUtil will produce link errors.
-// 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>
-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;
- 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)
- {
- 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;
-
- for (format_map_t::const_iterator iter = fmt_map.begin();
- iter != fmt_map.end();
- ++iter)
- {
- 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;
- }
- }
+////////////////////////////////////////////////////////////
- if (0 == first_match_str_length)
- {
- // no more keys found to substitute from this point
- // in the string forward.
- break;
- }
- 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;
- }
- }
- return res;
-}
// static
template<class T>
@@ -917,11 +901,22 @@ template<class T>
void LLStringUtilBase<T>::replaceChar( std::basic_string<T>& string, T target, T replacement )
{
size_type found_pos = 0;
- for (found_pos = string.find(target, found_pos);
- found_pos != std::basic_string<T>::npos;
- found_pos = string.find(target, found_pos))
+ while( (found_pos = string.find(target, found_pos)) != std::basic_string<T>::npos )
{
string[found_pos] = replacement;
+ found_pos++; // avoid infinite defeat if target == replacement
+ }
+}
+
+//static
+template<class T>
+void LLStringUtilBase<T>::replaceString( std::basic_string<T>& string, std::basic_string<T> target, std::basic_string<T> replacement )
+{
+ size_type found_pos = 0;
+ while( (found_pos = string.find(target, found_pos)) != std::basic_string<T>::npos )
+ {
+ string.replace( found_pos, target.length(), replacement );
+ found_pos += replacement.length(); // avoid infinite defeat if replacement contains target
}
}
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/llversionserver.h b/indra/llcommon/llversionserver.h
index a2c1819d8d..f073bd327b 100644
--- a/indra/llcommon/llversionserver.h
+++ b/indra/llcommon/llversionserver.h
@@ -36,7 +36,7 @@
const S32 LL_VERSION_MAJOR = 1;
const S32 LL_VERSION_MINOR = 31;
const S32 LL_VERSION_PATCH = 0;
-const S32 LL_VERSION_BUILD = 0;
+const S32 LL_VERSION_BUILD = 2425;
const char * const LL_CHANNEL = "Second Life Server";
diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h
index 7e623d47d6..04cf98ce19 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 = 4;
-const S32 LL_VERSION_BUILD = 0;
+const S32 LL_VERSION_MAJOR = 2;
+const S32 LL_VERSION_MINOR = 0;
+const S32 LL_VERSION_PATCH = 0;
+const S32 LL_VERSION_BUILD = 2425;
-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");
+ }
+
+};