summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2017-05-22 21:30:26 -0400
committerNat Goodspeed <nat@lindenlab.com>2017-05-22 21:30:26 -0400
commitfe64db61d6f10a9b31191090e2318aebc2d53b29 (patch)
tree635d4a6bee25c1e4ef55421f147e9e06bf5faeb3 /indra/llcommon
parent48af8529a80052e9bc42f81f36896739f8aff861 (diff)
parentb92ab8f7e659de66140cc6f538c74c1fc81e6a73 (diff)
Automated merge with ssh://bitbucket.org/lindenlab/viewer-release
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/CMakeLists.txt11
-rw-r--r--indra/llcommon/llallocator.cpp43
-rw-r--r--indra/llcommon/llcommon.cpp2
-rw-r--r--indra/llcommon/llcoros.cpp4
-rw-r--r--indra/llcommon/lldependencies.h6
-rw-r--r--indra/llcommon/llerror.cpp97
-rw-r--r--indra/llcommon/lleventdispatcher.h4
-rw-r--r--indra/llcommon/llevents.cpp12
-rw-r--r--indra/llcommon/llevents.h18
-rw-r--r--indra/llcommon/llfasttimer.h38
-rw-r--r--indra/llcommon/llfile.h2
-rw-r--r--indra/llcommon/llhandle.h1
-rw-r--r--indra/llcommon/llheteromap.h2
-rw-r--r--indra/llcommon/llinstancetracker.h31
-rw-r--r--indra/llcommon/llmake.h10
-rw-r--r--indra/llcommon/llmemory.cpp143
-rw-r--r--indra/llcommon/llmemory.h17
-rw-r--r--indra/llcommon/llpreprocessor.h16
-rw-r--r--indra/llcommon/llprocess.cpp12
-rw-r--r--indra/llcommon/llprocess.h29
-rw-r--r--indra/llcommon/llprocessor.cpp22
-rw-r--r--indra/llcommon/llsafehandle.h46
-rw-r--r--indra/llcommon/llsingleton.cpp46
-rw-r--r--indra/llcommon/llsingleton.h38
-rw-r--r--indra/llcommon/llstring.h2
-rw-r--r--indra/llcommon/llsys.cpp48
-rw-r--r--indra/llcommon/llsys.h5
-rw-r--r--indra/llcommon/llthread.cpp2
-rw-r--r--indra/llcommon/lltrace.h2
-rw-r--r--indra/llcommon/tests/llprocess_test.cpp89
-rw-r--r--indra/llcommon/tests/llsdserialize_test.cpp2
31 files changed, 390 insertions, 410 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index aa76a57f1d..142e56dfca 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -10,7 +10,6 @@ include(Boost)
include(LLSharedLibs)
include(JsonCpp)
include(GoogleBreakpad)
-include(GooglePerfTools)
include(Copy3rdPartyLibs)
include(ZLIB)
include(URIPARSER)
@@ -259,13 +258,13 @@ list(APPEND llcommon_SOURCE_FILES ${llcommon_HEADER_FILES})
if(LLCOMMON_LINK_SHARED)
add_library (llcommon SHARED ${llcommon_SOURCE_FILES})
- if(NOT WORD_SIZE EQUAL 32)
+ if(NOT ADDRESS_SIZE EQUAL 32)
if(WINDOWS)
- add_definitions(/FIXED:NO)
+ ##add_definitions(/FIXED:NO)
else(WINDOWS) # not windows therefore gcc LINUX and DARWIN
add_definitions(-fPIC)
endif(WINDOWS)
- endif(NOT WORD_SIZE EQUAL 32)
+ endif(NOT ADDRESS_SIZE EQUAL 32)
if(WINDOWS)
# always generate llcommon.pdb, even for "Release" builds
set_target_properties(llcommon PROPERTIES LINK_FLAGS "/DEBUG")
@@ -351,8 +350,4 @@ if (LL_TESTS)
## throwing and catching exceptions.
##LL_ADD_INTEGRATION_TEST(llexception "" "${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)
endif (LL_TESTS)
diff --git a/indra/llcommon/llallocator.cpp b/indra/llcommon/llallocator.cpp
index 34fc28d8cc..ac97fb71dd 100644
--- a/indra/llcommon/llallocator.cpp
+++ b/indra/llcommon/llallocator.cpp
@@ -27,47 +27,6 @@
#include "linden_common.h"
#include "llallocator.h"
-#if (LL_USE_TCMALLOC && LL_USE_HEAP_PROFILER)
-
-#include "google/heap-profiler.h"
-#include "google/commandlineflags_public.h"
-
-DECLARE_bool(heap_profile_use_stack_trace);
-//DECLARE_double(tcmalloc_release_rate);
-
-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
//
@@ -87,8 +46,6 @@ std::string LLAllocator::getRawProfile()
return std::string();
}
-#endif // LL_USE_TCMALLOC
-
LLAllocatorHeapProfile const & LLAllocator::getProfile()
{
mProf.mLines.clear();
diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp
index 439ff4e628..2d665c611b 100644
--- a/indra/llcommon/llcommon.cpp
+++ b/indra/llcommon/llcommon.cpp
@@ -41,7 +41,6 @@ static LLTrace::ThreadRecorder* sMasterThreadRecorder = NULL;
//static
void LLCommon::initClass()
{
- LLMemory::initClass();
if (!sAprInitialized)
{
ll_init_apr();
@@ -70,5 +69,4 @@ void LLCommon::cleanupClass()
ll_cleanup_apr();
sAprInitialized = FALSE;
}
- SUBSYSTEM_CLEANUP(LLMemory);
}
diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp
index 3ffce4810a..1e1dfd2602 100644
--- a/indra/llcommon/llcoros.cpp
+++ b/indra/llcommon/llcoros.cpp
@@ -151,7 +151,11 @@ LLCoros::LLCoros():
// Previously we used
// boost::context::guarded_stack_allocator::default_stacksize();
// empirically this is 64KB on Windows and Linux. Try quadrupling.
+#if ADDRESS_SIZE == 64
+ mStackSize(512*1024)
+#else
mStackSize(256*1024)
+#endif
{
// Register our cleanup() method for "mainloop" ticks
LLEventPumps::instance().obtain("mainloop").listen(
diff --git a/indra/llcommon/lldependencies.h b/indra/llcommon/lldependencies.h
index 125bd6a835..db2bbab8b0 100644
--- a/indra/llcommon/lldependencies.h
+++ b/indra/llcommon/lldependencies.h
@@ -124,8 +124,8 @@ public:
virtual std::string describe(bool full=true) const;
protected:
- typedef std::vector< std::pair<int, int> > EdgeList;
- typedef std::vector<int> VertexList;
+ typedef std::vector< std::pair<std::size_t, std::size_t> > EdgeList;
+ typedef std::vector<std::size_t> VertexList;
VertexList topo_sort(int vertices, const EdgeList& edges) const;
/**
@@ -508,7 +508,7 @@ public:
// been explicitly added. Rely on std::map rejecting a second attempt
// to insert the same key. Use the map's size() as the vertex number
// to get a distinct value for each successful insertion.
- typedef std::map<KEY, int> VertexMap;
+ typedef std::map<KEY, std::size_t> VertexMap;
VertexMap vmap;
// Nest each of these loops because !@#$%? MSVC warns us that its
// former broken behavior has finally been fixed -- and our builds
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index e6407ecf22..2ddb3edbdd 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -1067,7 +1067,15 @@ namespace LLError
{
return false;
}
-
+
+ // If we hit a logging request very late during shutdown processing,
+ // when either of the relevant LLSingletons has already been deleted,
+ // DO NOT resurrect them.
+ if (Settings::wasDeleted() || Globals::wasDeleted())
+ {
+ return false;
+ }
+
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
s->mShouldLogCallCounter++;
@@ -1106,7 +1114,10 @@ namespace LLError
std::ostringstream* Log::out()
{
LogLock lock;
- if (lock.ok())
+ // If we hit a logging request very late during shutdown processing,
+ // when either of the relevant LLSingletons has already been deleted,
+ // DO NOT resurrect them.
+ if (lock.ok() && ! (Settings::wasDeleted() || Globals::wasDeleted()))
{
Globals* g = Globals::getInstance();
@@ -1116,41 +1127,49 @@ namespace LLError
return &g->messageStream;
}
}
-
+
return new std::ostringstream;
}
-
+
void Log::flush(std::ostringstream* out, char* message)
- {
- LogLock lock;
- if (!lock.ok())
- {
- return;
- }
-
- if(strlen(out->str().c_str()) < 128)
- {
- strcpy(message, out->str().c_str());
- }
- else
- {
- strncpy(message, out->str().c_str(), 127);
- message[127] = '\0' ;
- }
-
- Globals* g = Globals::getInstance();
- if (out == &g->messageStream)
- {
- g->messageStream.clear();
- g->messageStream.str("");
- g->messageStreamInUse = false;
- }
- else
- {
- delete out;
- }
- return ;
- }
+ {
+ LogLock lock;
+ if (!lock.ok())
+ {
+ return;
+ }
+
+ // If we hit a logging request very late during shutdown processing,
+ // when either of the relevant LLSingletons has already been deleted,
+ // DO NOT resurrect them.
+ if (Settings::wasDeleted() || Globals::wasDeleted())
+ {
+ return;
+ }
+
+ if(strlen(out->str().c_str()) < 128)
+ {
+ strcpy(message, out->str().c_str());
+ }
+ else
+ {
+ strncpy(message, out->str().c_str(), 127);
+ message[127] = '\0' ;
+ }
+
+ Globals* g = Globals::getInstance();
+ if (out == &g->messageStream)
+ {
+ g->messageStream.clear();
+ g->messageStream.str("");
+ g->messageStreamInUse = false;
+ }
+ else
+ {
+ delete out;
+ }
+ return ;
+ }
void Log::flush(std::ostringstream* out, const CallSite& site)
{
@@ -1159,7 +1178,15 @@ namespace LLError
{
return;
}
-
+
+ // If we hit a logging request very late during shutdown processing,
+ // when either of the relevant LLSingletons has already been deleted,
+ // DO NOT resurrect them.
+ if (Settings::wasDeleted() || Globals::wasDeleted())
+ {
+ return;
+ }
+
Globals* g = Globals::getInstance();
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
diff --git a/indra/llcommon/lleventdispatcher.h b/indra/llcommon/lleventdispatcher.h
index 7acc61de4e..9e1244ef5b 100644
--- a/indra/llcommon/lleventdispatcher.h
+++ b/indra/llcommon/lleventdispatcher.h
@@ -47,13 +47,13 @@
// namespace) that a global 'nil' macro breaks badly.
#if defined(nil)
// Capture the value of the macro 'nil', hoping int is an appropriate type.
-static const int nil_(nil);
+static const auto nil_(nil);
// Now forget the macro.
#undef nil
// Finally, reintroduce 'nil' as a properly-scoped alias for the previously-
// defined const 'nil_'. Make it static since otherwise it produces duplicate-
// symbol link errors later.
-static const int& nil(nil_);
+static const auto& nil(nil_);
#endif
#include <string>
diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp
index 97270e4931..a3856e4fc4 100644
--- a/indra/llcommon/llevents.cpp
+++ b/indra/llcommon/llevents.cpp
@@ -281,7 +281,8 @@ const std::string LLEventPump::ANONYMOUS = std::string();
LLEventPump::LLEventPump(const std::string& name, bool tweak):
// Register every new instance with LLEventPumps
- mName(LLEventPumps::instance().registerNew(*this, name, tweak)),
+ mRegistry(LLEventPumps::instance().getHandle()),
+ mName(mRegistry.get()->registerNew(*this, name, tweak)),
mSignal(new LLStandardSignal()),
mEnabled(true)
{}
@@ -292,8 +293,13 @@ LLEventPump::LLEventPump(const std::string& name, bool tweak):
LLEventPump::~LLEventPump()
{
- // Unregister this doomed instance from LLEventPumps
- LLEventPumps::instance().unregister(*this);
+ // Unregister this doomed instance from LLEventPumps -- but only if
+ // LLEventPumps is still around!
+ LLEventPumps* registry = mRegistry.get();
+ if (registry)
+ {
+ registry->unregister(*this);
+ }
}
// static data member
diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h
index 7cff7dfd45..1d51c660ed 100644
--- a/indra/llcommon/llevents.h
+++ b/indra/llcommon/llevents.h
@@ -62,6 +62,7 @@
#include "lldependencies.h"
#include "llstl.h"
#include "llexception.h"
+#include "llhandle.h"
/*==========================================================================*|
// override this to allow binding free functions with more parameters
@@ -227,7 +228,15 @@ class LLEventPump;
* LLEventPumps is a Singleton manager through which one typically accesses
* this subsystem.
*/
-class LL_COMMON_API LLEventPumps: public LLSingleton<LLEventPumps>
+// LLEventPumps isa LLHandleProvider only for (hopefully rare) long-lived
+// class objects that must refer to this class late in their lifespan, say in
+// the destructor. Specifically, the case that matters is a possible reference
+// after LLEventPumps::deleteSingleton(). (Lingering LLEventPump instances are
+// capable of this.) In that case, instead of calling LLEventPumps::instance()
+// again -- resurrecting the deleted LLSingleton -- store an
+// LLHandle<LLEventPumps> and test it before use.
+class LL_COMMON_API LLEventPumps: public LLSingleton<LLEventPumps>,
+ public LLHandleProvider<LLEventPumps>
{
LLSINGLETON(LLEventPumps);
public:
@@ -590,6 +599,9 @@ private:
return this->listen_impl(name, listener, after, before);
}
+ // must precede mName; see LLEventPump::LLEventPump()
+ LLHandle<LLEventPumps> mRegistry;
+
std::string mName;
protected:
@@ -817,14 +829,14 @@ public:
mConnection(new LLBoundListener)
{
}
-
+
/// Copy constructor. Copy shared_ptrs to original instance data.
LLListenerWrapperBase(const LLListenerWrapperBase& that):
mName(that.mName),
mConnection(that.mConnection)
{
}
- virtual ~LLListenerWrapperBase() {}
+ virtual ~LLListenerWrapperBase() {}
/// Ask LLEventPump::listen() for the listener name
virtual void accept_name(const std::string& name) const
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index f56e5596f5..2024d707da 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -90,33 +90,15 @@ public:
#if LL_FASTTIMER_USE_RDTSC
static U32 getCPUClockCount32()
{
- U32 ret_val;
- __asm
- {
- _emit 0x0f
- _emit 0x31
- shr eax,8
- shl edx,24
- or eax, edx
- mov dword ptr [ret_val], eax
- }
- return ret_val;
+ unsigned __int64 val = __rdtsc();
+ val = val >> 8;
+ return static_cast<U32>(val);
}
// return full timer value, *not* shifted by 8 bits
static U64 getCPUClockCount64()
{
- U64 ret_val;
- __asm
- {
- _emit 0x0f
- _emit 0x31
- mov eax,eax
- mov edx,edx
- mov dword ptr [ret_val+4], edx
- mov dword ptr [ret_val], eax
- }
- return ret_val;
+ return static_cast<U64>( __rdtsc() );
}
#else
@@ -173,16 +155,16 @@ public:
// Mac+Linux+Solaris FAST x86 implementation of CPU clock
static U32 getCPUClockCount32()
{
- U64 x;
- __asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
- return (U32)(x >> 8);
+ U32 low(0),high(0);
+ __asm__ volatile (".byte 0x0f, 0x31": "=a"(low), "=d"(high) );
+ return (low>>8) | (high<<24);
}
static U64 getCPUClockCount64()
{
- U64 x;
- __asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
- return x;
+ U32 low(0),high(0);
+ __asm__ volatile (".byte 0x0f, 0x31": "=a"(low), "=d"(high) );
+ return (U64)low | ( ((U64)high) << 32);
}
#endif
diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h
index d8f84daf2b..37eb75881c 100644
--- a/indra/llcommon/llfile.h
+++ b/indra/llcommon/llfile.h
@@ -45,7 +45,7 @@ typedef FILE LLFILE;
typedef struct _stat llstat;
#else
typedef struct stat llstat;
-#include <bits/postypes.h>
+#include <sys/types.h>
#endif
#ifndef S_ISREG
diff --git a/indra/llcommon/llhandle.h b/indra/llcommon/llhandle.h
index feb5f41848..570cd330b8 100644
--- a/indra/llcommon/llhandle.h
+++ b/indra/llcommon/llhandle.h
@@ -28,6 +28,7 @@
#define LLHANDLE_H
#include "llpointer.h"
+#include "llrefcount.h"
#include "llexception.h"
#include <stdexcept>
#include <boost/type_traits/is_convertible.hpp>
diff --git a/indra/llcommon/llheteromap.h b/indra/llcommon/llheteromap.h
index 9d6f303d08..7e96172333 100644
--- a/indra/llcommon/llheteromap.h
+++ b/indra/llcommon/llheteromap.h
@@ -77,7 +77,7 @@ private:
// not always equal &typeid(A) in some other part. Use special comparator.
struct type_info_ptr_comp
{
- bool operator()(const std::type_info* lhs, const std::type_info* rhs)
+ bool operator()(const std::type_info* lhs, const std::type_info* rhs) const
{
return lhs->before(*rhs);
}
diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h
index 9783644e66..910c8dbd99 100644
--- a/indra/llcommon/llinstancetracker.h
+++ b/indra/llcommon/llinstancetracker.h
@@ -35,6 +35,31 @@
#include <boost/iterator/transform_iterator.hpp>
#include <boost/iterator/indirect_iterator.hpp>
+// As of 2017-05-06, as far as nat knows, only clang supports __has_feature().
+// Unfortunately VS2013's preprocessor shortcut logic doesn't prevent it from
+// producing (fatal) warnings for defined(__clang__) && __has_feature(...).
+// Have to work around that.
+#if ! defined(__clang__)
+#define __has_feature(x) 0
+#endif // __clang__
+
+#if defined(LL_TEST_llinstancetracker) && __has_feature(cxx_noexcept)
+// ~LLInstanceTracker() performs llassert_always() validation. That's fine in
+// production code, since the llassert_always() is implemented as an LL_ERRS
+// message, which will crash-with-message. In our integration test executable,
+// though, this llassert_always() throws an exception instead so we can test
+// error conditions and continue running the test. However -- as of C++11,
+// destructors are implicitly noexcept(true). Unless we mark
+// ~LLInstanceTracker() noexcept(false), the test executable crashes even on
+// the ATTEMPT to throw.
+#define LLINSTANCETRACKER_DTOR_NOEXCEPT noexcept(false)
+#else
+// If we're building for production, or in fact building *any other* test, or
+// we're using a compiler that doesn't support __has_feature(), or we're not
+// compiling with a C++ version that supports noexcept -- don't specify it.
+#define LLINSTANCETRACKER_DTOR_NOEXCEPT
+#endif
+
/**
* Base class manages "class-static" data that must actually have singleton
* semantics: one instance per process, rather than one instance per module as
@@ -198,11 +223,11 @@ protected:
getStatic();
add_(key);
}
- virtual ~LLInstanceTracker()
+ virtual ~LLInstanceTracker() LLINSTANCETRACKER_DTOR_NOEXCEPT
{
// it's unsafe to delete instances of this type while all instances are being iterated over.
llassert_always(getStatic().getDepth() == 0);
- remove_();
+ remove_();
}
virtual void setKey(KEY key) { remove_(); add_(key); }
virtual const KEY& getKey() const { return mInstanceKey; }
@@ -335,7 +360,7 @@ protected:
getStatic();
getSet_().insert(static_cast<T*>(this));
}
- virtual ~LLInstanceTracker()
+ virtual ~LLInstanceTracker() LLINSTANCETRACKER_DTOR_NOEXCEPT
{
// it's unsafe to delete instances of this type while all instances are being iterated over.
llassert_always(getStatic().getDepth() == 0);
diff --git a/indra/llcommon/llmake.h b/indra/llcommon/llmake.h
index 9a662a0640..08744f90fb 100644
--- a/indra/llcommon/llmake.h
+++ b/indra/llcommon/llmake.h
@@ -12,12 +12,10 @@
*
* also relevant:
*
- * Template parameter deduction for constructors
- * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0091r0.html
- *
- * https://github.com/viboes/std-make
- *
- * but obviously we're not there yet.
+ * Template argument deduction for class templates
+ * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0091r3.html
+ * was apparently adopted in June 2016? Unclear when compilers will
+ * portably support this, but there is hope.
*
* $LicenseInfo:firstyear=2015&license=viewerlgpl$
* Copyright (c) 2015, Linden Research, Inc.
diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp
index 3a8eabac09..049e962638 100644
--- a/indra/llcommon/llmemory.cpp
+++ b/indra/llcommon/llmemory.cpp
@@ -44,10 +44,10 @@
#include "llsys.h"
#include "llframetimer.h"
#include "lltrace.h"
+#include "llerror.h"
//----------------------------------------------------------------------------
//static
-char* LLMemory::reserveMem = 0;
U32Kilobytes LLMemory::sAvailPhysicalMemInKB(U32_MAX);
U32Kilobytes LLMemory::sMaxPhysicalMemInKB(0);
static LLTrace::SampleStatHandle<F64Megabytes> sAllocatedMem("allocated_mem", "active memory in use by application");
@@ -78,29 +78,6 @@ void ll_assert_aligned_func(uintptr_t ptr,U32 alignment)
#endif
}
-//static
-void LLMemory::initClass()
-{
- if (!reserveMem)
- {
- reserveMem = new char[16*1024]; // reserve 16K for out of memory error handling
- }
-}
-
-//static
-void LLMemory::cleanupClass()
-{
- delete [] reserveMem;
- reserveMem = NULL;
-}
-
-//static
-void LLMemory::freeReserve()
-{
- delete [] reserveMem;
- reserveMem = NULL;
-}
-
//static
void LLMemory::initMaxHeapSizeGB(F32Gigabytes max_heap_size, BOOL prevent_heap_failure)
{
@@ -111,19 +88,18 @@ void LLMemory::initMaxHeapSizeGB(F32Gigabytes max_heap_size, BOOL prevent_heap_f
//static
void LLMemory::updateMemoryInfo()
{
-#if LL_WINDOWS
- HANDLE self = GetCurrentProcess();
+#if LL_WINDOWS
PROCESS_MEMORY_COUNTERS counters;
-
- if (!GetProcessMemoryInfo(self, &counters, sizeof(counters)))
+
+ if (!GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters)))
{
LL_WARNS() << "GetProcessMemoryInfo failed" << LL_ENDL;
return ;
}
- sAllocatedMemInKB = (U32Bytes)(counters.WorkingSetSize) ;
+ sAllocatedMemInKB = U64Bytes(counters.WorkingSetSize) ;
sample(sAllocatedMem, sAllocatedMemInKB);
- sAllocatedPageSizeInKB = (U32Bytes)(counters.PagefileUsage) ;
+ sAllocatedPageSizeInKB = U64Bytes(counters.PagefileUsage) ;
sample(sVirtualMem, sAllocatedPageSizeInKB);
U32Kilobytes avail_phys, avail_virtual;
@@ -140,9 +116,9 @@ void LLMemory::updateMemoryInfo()
}
#else
//not valid for other systems for now.
- sAllocatedMemInKB = (U32Bytes)LLMemory::getCurrentRSS();
- sMaxPhysicalMemInKB = (U32Bytes)U32_MAX ;
- sAvailPhysicalMemInKB = (U32Bytes)U32_MAX ;
+ sAllocatedMemInKB = U64Bytes(LLMemory::getCurrentRSS());
+ sMaxPhysicalMemInKB = U64Bytes(U32_MAX);
+ sAvailPhysicalMemInKB = U64Bytes(U32_MAX);
#endif
return ;
@@ -169,7 +145,7 @@ void* LLMemory::tryToAlloc(void* address, U32 size)
return address ;
#else
return (void*)0x01 ; //skip checking
-#endif
+#endif
}
//static
@@ -183,7 +159,7 @@ void LLMemory::logMemoryInfo(BOOL update)
LL_INFOS() << "Current allocated physical memory(KB): " << sAllocatedMemInKB << LL_ENDL ;
LL_INFOS() << "Current allocated page size (KB): " << sAllocatedPageSizeInKB << LL_ENDL ;
- LL_INFOS() << "Current availabe physical memory(KB): " << sAvailPhysicalMemInKB << LL_ENDL ;
+ LL_INFOS() << "Current available physical memory(KB): " << sAvailPhysicalMemInKB << LL_ENDL ;
LL_INFOS() << "Current max usable memory(KB): " << sMaxPhysicalMemInKB << LL_ENDL ;
LL_INFOS() << "--- private pool information -- " << LL_ENDL ;
@@ -263,12 +239,12 @@ U32Kilobytes LLMemory::getAllocatedMemKB()
#if defined(LL_WINDOWS)
+//static
U64 LLMemory::getCurrentRSS()
{
- HANDLE self = GetCurrentProcess();
PROCESS_MEMORY_COUNTERS counters;
-
- if (!GetProcessMemoryInfo(self, &counters, sizeof(counters)))
+
+ if (!GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters)))
{
LL_WARNS() << "GetProcessMemoryInfo failed" << LL_ENDL;
return 0;
@@ -277,35 +253,8 @@ U64 LLMemory::getCurrentRSS()
return counters.WorkingSetSize;
}
-//static
-U32 LLMemory::getWorkingSetSize()
-{
- PROCESS_MEMORY_COUNTERS pmc ;
- U32 ret = 0 ;
-
- if (GetProcessMemoryInfo( GetCurrentProcess(), &pmc, sizeof(pmc)) )
- {
- ret = pmc.WorkingSetSize ;
- }
-
- return ret ;
-}
-
#elif defined(LL_DARWIN)
-/*
- The API used here is not capable of dealing with 64-bit memory sizes, but is available before 10.4.
-
- Once we start requiring 10.4, we can use the updated API, which looks like this:
-
- task_basic_info_64_data_t basicInfo;
- mach_msg_type_number_t basicInfoCount = TASK_BASIC_INFO_64_COUNT;
- if (task_info(mach_task_self(), TASK_BASIC_INFO_64, (task_info_t)&basicInfo, &basicInfoCount) == KERN_SUCCESS)
-
- Of course, this doesn't gain us anything unless we start building the viewer as a 64-bit executable, since that's the only way
- for our memory allocation to exceed 2^32.
-*/
-
// if (sysctl(ctl, 2, &page_size, &size, NULL, 0) == -1)
// {
// LL_WARNS() << "Couldn't get page size" << LL_ENDL;
@@ -318,16 +267,15 @@ U32 LLMemory::getWorkingSetSize()
U64 LLMemory::getCurrentRSS()
{
U64 residentSize = 0;
- task_basic_info_data_t basicInfo;
- mach_msg_type_number_t basicInfoCount = TASK_BASIC_INFO_COUNT;
- if (task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&basicInfo, &basicInfoCount) == KERN_SUCCESS)
+ mach_task_basic_info_data_t basicInfo;
+ mach_msg_type_number_t basicInfoCount = MACH_TASK_BASIC_INFO_COUNT;
+ if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&basicInfo, &basicInfoCount) == KERN_SUCCESS)
{
- residentSize = basicInfo.resident_size;
-
- // If we ever wanted it, the process virtual size is also available as:
- // virtualSize = basicInfo.virtual_size;
-
-// LL_INFOS() << "resident size is " << residentSize << LL_ENDL;
+// residentSize = basicInfo.resident_size;
+ // Although this method is defined to return the "resident set size,"
+ // in fact what callers want from it is the total virtual memory
+ // consumed by the application.
+ residentSize = basicInfo.virtual_size;
}
else
{
@@ -337,11 +285,6 @@ U64 LLMemory::getCurrentRSS()
return residentSize;
}
-U32 LLMemory::getWorkingSetSize()
-{
- return 0 ;
-}
-
#elif defined(LL_LINUX)
U64 LLMemory::getCurrentRSS()
@@ -353,7 +296,7 @@ U64 LLMemory::getCurrentRSS()
if (fp == NULL)
{
LL_WARNS() << "couldn't open " << statPath << LL_ENDL;
- goto bail;
+ return 0;
}
// Eee-yew! See Documentation/filesystems/proc.txt in your
@@ -372,15 +315,9 @@ U64 LLMemory::getCurrentRSS()
fclose(fp);
-bail:
return rss;
}
-U32 LLMemory::getWorkingSetSize()
-{
- return 0 ;
-}
-
#elif LL_SOLARIS
#include <sys/types.h>
#include <sys/stat.h>
@@ -410,11 +347,6 @@ U64 LLMemory::getCurrentRSS()
return((U64)proc_psinfo.pr_rssize * 1024);
}
-U32 LLMemory::getWorkingSetSize()
-{
- return 0 ;
-}
-
#else
U64 LLMemory::getCurrentRSS()
@@ -422,11 +354,6 @@ U64 LLMemory::getCurrentRSS()
return 0;
}
-U32 LLMemory::getWorkingSetSize()
-{
- return 0;
-}
-
#endif
//--------------------------------------------------------------------------------------------------
@@ -591,7 +518,7 @@ char* LLPrivateMemoryPool::LLMemoryBlock::allocate()
void LLPrivateMemoryPool::LLMemoryBlock::freeMem(void* addr)
{
//bit index
- U32 idx = ((U32)addr - (U32)mBuffer - mDummySize) / mSlotSize ;
+ uintptr_t idx = ((uintptr_t)addr - (uintptr_t)mBuffer - mDummySize) / mSlotSize ;
U32* bits = &mUsageBits ;
if(idx >= 32)
@@ -773,7 +700,7 @@ char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size)
void LLPrivateMemoryPool::LLMemoryChunk::freeMem(void* addr)
{
- U32 blk_idx = getPageIndex((U32)addr) ;
+ U32 blk_idx = getPageIndex((uintptr_t)addr) ;
LLMemoryBlock* blk = (LLMemoryBlock*)(mMetaBuffer + blk_idx * sizeof(LLMemoryBlock)) ;
blk = blk->mSelf ;
@@ -798,7 +725,7 @@ bool LLPrivateMemoryPool::LLMemoryChunk::empty()
bool LLPrivateMemoryPool::LLMemoryChunk::containsAddress(const char* addr) const
{
- return (U32)mBuffer <= (U32)addr && (U32)mBuffer + mBufferSize > (U32)addr ;
+ return (uintptr_t)mBuffer <= (uintptr_t)addr && (uintptr_t)mBuffer + mBufferSize > (uintptr_t)addr ;
}
//debug use
@@ -831,13 +758,13 @@ void LLPrivateMemoryPool::LLMemoryChunk::dump()
for(U32 i = 1 ; i < blk_list.size(); i++)
{
total_size += blk_list[i]->getBufferSize() ;
- if((U32)blk_list[i]->getBuffer() < (U32)blk_list[i-1]->getBuffer() + blk_list[i-1]->getBufferSize())
+ if((uintptr_t)blk_list[i]->getBuffer() < (uintptr_t)blk_list[i-1]->getBuffer() + blk_list[i-1]->getBufferSize())
{
LL_ERRS() << "buffer corrupted." << LL_ENDL ;
}
}
- llassert_always(total_size + mMinBlockSize >= mBufferSize - ((U32)mDataBuffer - (U32)mBuffer)) ;
+ llassert_always(total_size + mMinBlockSize >= mBufferSize - ((uintptr_t)mDataBuffer - (uintptr_t)mBuffer)) ;
U32 blk_num = (mBufferSize - (mDataBuffer - mBuffer)) / mMinBlockSize ;
for(U32 i = 0 ; i < blk_num ; )
@@ -860,7 +787,7 @@ void LLPrivateMemoryPool::LLMemoryChunk::dump()
#endif
#if 0
LL_INFOS() << "---------------------------" << LL_ENDL ;
- LL_INFOS() << "Chunk buffer: " << (U32)getBuffer() << " size: " << getBufferSize() << LL_ENDL ;
+ LL_INFOS() << "Chunk buffer: " << (uintptr_t)getBuffer() << " size: " << getBufferSize() << LL_ENDL ;
LL_INFOS() << "available blocks ... " << LL_ENDL ;
for(S32 i = 0 ; i < mBlockLevels ; i++)
@@ -868,7 +795,7 @@ void LLPrivateMemoryPool::LLMemoryChunk::dump()
LLMemoryBlock* blk = mAvailBlockList[i] ;
while(blk)
{
- LL_INFOS() << "blk buffer " << (U32)blk->getBuffer() << " size: " << blk->getBufferSize() << LL_ENDL ;
+ LL_INFOS() << "blk buffer " << (uintptr_t)blk->getBuffer() << " size: " << blk->getBufferSize() << LL_ENDL ;
blk = blk->mNext ;
}
}
@@ -879,7 +806,7 @@ void LLPrivateMemoryPool::LLMemoryChunk::dump()
LLMemoryBlock* blk = mFreeSpaceList[i] ;
while(blk)
{
- LL_INFOS() << "blk buffer " << (U32)blk->getBuffer() << " size: " << blk->getBufferSize() << LL_ENDL ;
+ LL_INFOS() << "blk buffer " << (uintptr_t)blk->getBuffer() << " size: " << blk->getBufferSize() << LL_ENDL ;
blk = blk->mNext ;
}
}
@@ -1155,9 +1082,9 @@ void LLPrivateMemoryPool::LLMemoryChunk::addToAvailBlockList(LLMemoryBlock* blk)
return ;
}
-U32 LLPrivateMemoryPool::LLMemoryChunk::getPageIndex(U32 addr)
+U32 LLPrivateMemoryPool::LLMemoryChunk::getPageIndex(uintptr_t addr)
{
- return (addr - (U32)mDataBuffer) / mMinBlockSize ;
+ return (addr - (uintptr_t)mDataBuffer) / mMinBlockSize ;
}
//for mAvailBlockList
@@ -1495,7 +1422,7 @@ void LLPrivateMemoryPool::removeChunk(LLMemoryChunk* chunk)
U16 LLPrivateMemoryPool::findHashKey(const char* addr)
{
- return (((U32)addr) / CHUNK_SIZE) % mHashFactor ;
+ return (((uintptr_t)addr) / CHUNK_SIZE) % mHashFactor ;
}
LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::findChunk(const char* addr)
@@ -1720,7 +1647,7 @@ LLPrivateMemoryPoolManager::~LLPrivateMemoryPoolManager()
S32 k = 0 ;
for(mem_allocation_info_t::iterator iter = sMemAllocationTracker.begin() ; iter != sMemAllocationTracker.end() ; ++iter)
{
- LL_INFOS() << k++ << ", " << (U32)iter->first << " : " << iter->second << LL_ENDL ;
+ LL_INFOS() << k++ << ", " << (uintptr_t)iter->first << " : " << iter->second << LL_ENDL ;
}
sMemAllocationTracker.clear() ;
}
diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index 575edddc43..c37967e10e 100644
--- a/indra/llcommon/llmemory.h
+++ b/indra/llcommon/llmemory.h
@@ -138,7 +138,6 @@ template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address)
//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
-#if !LL_USE_TCMALLOC
inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed with ll_aligned_free_16().
{
#if defined(LL_WINDOWS)
@@ -187,13 +186,6 @@ inline void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size) // r
#endif
}
-#else // USE_TCMALLOC
-// ll_aligned_foo_16 are not needed with tcmalloc
-#define ll_aligned_malloc_16 malloc
-#define ll_aligned_realloc_16(a,b,c) realloc(a,b)
-#define ll_aligned_free_16 free
-#endif // USE_TCMALLOC
-
inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed with ll_aligned_free_32().
{
#if defined(LL_WINDOWS)
@@ -342,13 +334,9 @@ inline void ll_memcpy_nonaliased_aligned_16(char* __restrict dst, const char* __
class LL_COMMON_API LLMemory
{
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();
- static U32 getWorkingSetSize();
static void* tryToAlloc(void* address, U32 size);
static void initMaxHeapSizeGB(F32Gigabytes max_heap_size, BOOL prevent_heap_failure);
static void updateMemoryInfo() ;
@@ -359,7 +347,6 @@ public:
static U32Kilobytes getMaxMemKB() ;
static U32Kilobytes getAllocatedMemKB() ;
private:
- static char* reserveMem;
static U32Kilobytes sAvailPhysicalMemInKB ;
static U32Kilobytes sMaxPhysicalMemInKB ;
static U32Kilobytes sAllocatedMemInKB;
@@ -423,7 +410,7 @@ public:
{
bool operator()(const LLMemoryBlock* const& lhs, const LLMemoryBlock* const& rhs)
{
- return (U32)lhs->getBuffer() < (U32)rhs->getBuffer();
+ return (uintptr_t)lhs->getBuffer() < (uintptr_t)rhs->getBuffer();
}
};
};
@@ -454,7 +441,7 @@ public:
void dump() ;
private:
- U32 getPageIndex(U32 addr) ;
+ U32 getPageIndex(uintptr_t addr) ;
U32 getBlockLevel(U32 size) ;
U16 getPageLevel(U32 size) ;
LLMemoryBlock* addBlock(U32 blk_idx) ;
diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h
index 2c4bcc91f6..2879038c36 100644
--- a/indra/llcommon/llpreprocessor.h
+++ b/indra/llcommon/llpreprocessor.h
@@ -138,6 +138,12 @@
#pragma warning( 3 : 4266 ) // 'function' : no override available for virtual member function from base 'type'; function is hidden
#pragma warning (disable : 4180) // qualifier applied to function type has no meaning; ignored
//#pragma warning( disable : 4284 ) // silly MS warning deep inside their <map> include file
+
+#if ADDRESS_SIZE == 64
+// That one is all over the place for x64 builds.
+#pragma warning( disable : 4267 ) // 'var' : conversion from 'size_t' to 'type', possible loss of data)
+#endif
+
#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)
#pragma warning( disable : 4996 ) // warning: deprecated
@@ -186,13 +192,9 @@
# define LL_COMMON_API
#endif // LL_COMMON_LINK_SHARED
-#if LL_WINDOWS
-#define LL_TYPEOF(exp) decltype(exp)
-#elif LL_LINUX
-#define LL_TYPEOF(exp) typeof(exp)
-#elif LL_DARWIN
-#define LL_TYPEOF(exp) typeof(exp)
-#endif
+// With C++11, decltype() is standard. We no longer need a platform-dependent
+// macro to get the type of an expression.
+#define LL_TYPEOF(expr) decltype(expr)
#define LL_TO_STRING_HELPER(x) #x
#define LL_TO_STRING(x) LL_TO_STRING_HELPER(x)
diff --git a/indra/llcommon/llprocess.cpp b/indra/llcommon/llprocess.cpp
index 8c321d06b9..5753efdc59 100644
--- a/indra/llcommon/llprocess.cpp
+++ b/indra/llcommon/llprocess.cpp
@@ -517,6 +517,10 @@ LLProcessPtr LLProcess::create(const LLSDOrParams& params)
LLProcess::LLProcess(const LLSDOrParams& params):
mAutokill(params.autokill),
+ // Because 'autokill' originally meant both 'autokill' and 'attached', to
+ // preserve existing semantics, we promise that mAttached defaults to the
+ // same setting as mAutokill.
+ mAttached(params.attached.isProvided()? params.attached : params.autokill),
mPipes(NSLOTS)
{
// Hmm, when you construct a ptr_vector with a size, it merely reserves
@@ -625,9 +629,9 @@ LLProcess::LLProcess(const LLSDOrParams& params):
// std handles and the like, and that's a bit more detachment than we
// want. autokill=false just means not to implicitly kill the child when
// the parent terminates!
-// chkapr(apr_procattr_detach_set(procattr, params.autokill? 0 : 1));
+// chkapr(apr_procattr_detach_set(procattr, mAutokill? 0 : 1));
- if (params.autokill)
+ if (mAutokill)
{
#if ! defined(APR_HAS_PROCATTR_AUTOKILL_SET)
// Our special preprocessor symbol isn't even defined -- wrong APR
@@ -696,7 +700,7 @@ LLProcess::LLProcess(const LLSDOrParams& params):
// take steps to terminate the child. This is all suspenders-and-belt: in
// theory our destructor should kill an autokill child, but in practice
// that doesn't always work (e.g. VWR-21538).
- if (params.autokill)
+ if (mAutokill)
{
/*==========================================================================*|
// NO: There may be an APR bug, not sure -- but at least on Mac, when
@@ -799,7 +803,7 @@ LLProcess::~LLProcess()
sProcessListener.dropPoll(*this);
}
- if (mAutokill)
+ if (mAttached)
{
kill("destructor");
}
diff --git a/indra/llcommon/llprocess.h b/indra/llcommon/llprocess.h
index bfac4567a5..e3386ad88e 100644
--- a/indra/llcommon/llprocess.h
+++ b/indra/llcommon/llprocess.h
@@ -167,6 +167,7 @@ public:
args("args"),
cwd("cwd"),
autokill("autokill", true),
+ attached("attached", true),
files("files"),
postend("postend"),
desc("desc")
@@ -183,9 +184,31 @@ public:
Multiple<std::string> args;
/// current working directory, if need it changed
Optional<std::string> cwd;
- /// implicitly kill process on destruction of LLProcess object
- /// (default true)
+ /// implicitly kill child process on termination of parent, whether
+ /// voluntary or crash (default true)
Optional<bool> autokill;
+ /// implicitly kill process on destruction of LLProcess object
+ /// (default same as autokill)
+ ///
+ /// Originally, 'autokill' conflated two concepts: kill child process on
+ /// - destruction of its LLProcess object, and
+ /// - termination of parent process, voluntary or otherwise.
+ ///
+ /// It's useful to tease these apart. Some child processes are sent a
+ /// "clean up and terminate" message before the associated LLProcess
+ /// object is destroyed. A child process launched with attached=false
+ /// has an extra time window from the destruction of its LLProcess
+ /// until parent-process termination in which to perform its own
+ /// orderly shutdown, yet autokill=true still guarantees that we won't
+ /// accumulate orphan instances of such processes indefinitely. With
+ /// attached=true, if a child process cannot clean up between the
+ /// shutdown message and LLProcess destruction (presumably very soon
+ /// thereafter), it's forcibly killed anyway -- which can lead to
+ /// distressing user-visible crash indications.
+ ///
+ /// (The usefulness of attached=true with autokill=false is less
+ /// clear, but we don't prohibit that combination.)
+ Optional<bool> attached;
/**
* Up to three FileParam items: for child stdin, stdout, stderr.
* Passing two FileParam entries means default treatment for stderr,
@@ -540,7 +563,7 @@ private:
std::string mDesc;
std::string mPostend;
apr_proc_t mProcess;
- bool mAutokill;
+ bool mAutokill, mAttached;
Status mStatus;
// explicitly want this ptr_vector to be able to store NULLs
typedef boost::ptr_vector< boost::nullable<BasePipe> > PipeVector;
diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp
index e3e1d0c391..446c312ca9 100644
--- a/indra/llcommon/llprocessor.cpp
+++ b/indra/llcommon/llprocessor.cpp
@@ -26,9 +26,11 @@
#include "linden_common.h"
#include "llprocessor.h"
-
+#include "llstring.h"
+#include "stringize.h"
#include "llerror.h"
+#include <iomanip>
//#include <memory>
#if LL_WINDOWS
@@ -188,7 +190,7 @@ namespace
case 0xF: return "Intel Pentium 4";
case 0x10: return "Intel Itanium 2 (IA-64)";
}
- return "Unknown";
+ return STRINGIZE("Intel <unknown 0x" << std::hex << composed_family << ">");
}
std::string amd_CPUFamilyName(int composed_family)
@@ -201,26 +203,26 @@ namespace
case 0xF: return "AMD K8";
case 0x10: return "AMD K8L";
}
- return "Unknown";
+ return STRINGIZE("AMD <unknown 0x" << std::hex << composed_family << ">");
}
std::string compute_CPUFamilyName(const char* cpu_vendor, int family, int ext_family)
{
const char* intel_string = "GenuineIntel";
const char* amd_string = "AuthenticAMD";
- if(!strncmp(cpu_vendor, intel_string, strlen(intel_string)))
+ if (LLStringUtil::startsWith(cpu_vendor, intel_string))
{
U32 composed_family = family + ext_family;
return intel_CPUFamilyName(composed_family);
}
- else if(!strncmp(cpu_vendor, amd_string, strlen(amd_string)))
+ else if (LLStringUtil::startsWith(cpu_vendor, amd_string))
{
U32 composed_family = (family == 0xF)
? family + ext_family
: family;
return amd_CPUFamilyName(composed_family);
}
- return "Unknown";
+ return STRINGIZE("Unrecognized CPU vendor <" << cpu_vendor << ">");
}
} // end unnamed namespace
@@ -258,8 +260,8 @@ public:
return hasExtension("Altivec");
}
- std::string getCPUFamilyName() const { return getInfo(eFamilyName, "Unknown").asString(); }
- std::string getCPUBrandName() const { return getInfo(eBrandName, "Unknown").asString(); }
+ std::string getCPUFamilyName() const { return getInfo(eFamilyName, "Unset family").asString(); }
+ std::string getCPUBrandName() const { return getInfo(eBrandName, "Unset brand").asString(); }
// This is virtual to support a different linux format.
// *NOTE:Mani - I didn't want to screw up server use of this data...
@@ -271,7 +273,7 @@ public:
out << "//////////////////////////" << std::endl;
out << "Processor Name: " << getCPUBrandName() << std::endl;
out << "Frequency: " << getCPUFrequency() << " MHz" << std::endl;
- out << "Vendor: " << getInfo(eVendor, "Unknown").asString() << std::endl;
+ out << "Vendor: " << getInfo(eVendor, "Unset vendor").asString() << std::endl;
out << "Family: " << getCPUFamilyName() << " (" << getInfo(eFamily, 0) << ")" << std::endl;
out << "Extended family: " << getInfo(eExtendedFamily, 0) << std::endl;
out << "Model: " << getInfo(eModel, 0) << std::endl;
@@ -398,7 +400,7 @@ static F64 calculate_cpu_frequency(U32 measure_msecs)
HANDLE hThread = GetCurrentThread();
unsigned long dwCurPriorityClass = GetPriorityClass(hProcess);
int iCurThreadPriority = GetThreadPriority(hThread);
- unsigned long dwProcessMask, dwSystemMask, dwNewMask = 1;
+ DWORD_PTR dwProcessMask, dwSystemMask, dwNewMask = 1;
GetProcessAffinityMask(hProcess, &dwProcessMask, &dwSystemMask);
SetPriorityClass(hProcess, REALTIME_PRIORITY_CLASS);
diff --git a/indra/llcommon/llsafehandle.h b/indra/llcommon/llsafehandle.h
index 4226bf04f0..9550e6253e 100644
--- a/indra/llcommon/llsafehandle.h
+++ b/indra/llcommon/llsafehandle.h
@@ -27,6 +27,30 @@
#define LLSAFEHANDLE_H
#include "llerror.h" // *TODO: consider eliminating this
+#include "llsingleton.h"
+
+/*==========================================================================*|
+ ____ ___ _ _ ___ _____ _ _ ____ _____ _
+| _ \ / _ \ | \ | |/ _ \_ _| | | | / ___|| ____| |
+| | | | | | | | \| | | | || | | | | \___ \| _| | |
+| |_| | |_| | | |\ | |_| || | | |_| |___) | |___|_|
+|____/ \___/ |_| \_|\___/ |_| \___/|____/|_____(_)
+
+This handle class is deprecated. Unfortunately it is already in widespread use
+to reference the LLObjectSelection and LLParcelSelection classes, but do not
+apply LLSafeHandle to other classes, or declare new instances.
+
+Instead, use LLPointer or other smart pointer types with appropriate checks
+for NULL. If you're certain the reference cannot (or must not) be NULL,
+consider storing a C++ reference instead -- or use (e.g.) LLCheckedHandle.
+
+When an LLSafeHandle<T> containing NULL is dereferenced, it resolves to a
+canonical "null" T instance. This raises issues about the lifespan of the
+"null" instance. In addition to encouraging sloppy coding practices, it
+potentially masks bugs when code that performs some mutating operation
+inadvertently applies it to the "null" instance. That result might or might
+not ever affect subsequent computations.
+|*==========================================================================*/
// 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
@@ -112,10 +136,6 @@ public:
return *this;
}
-public:
- typedef Type* (*NullFunc)();
- static const NullFunc sNullFunc;
-
protected:
void ref()
{
@@ -150,9 +170,25 @@ protected:
}
}
+ // Define an LLSingleton whose sole purpose is to hold a "null instance"
+ // of the subject Type: the canonical instance to dereference if this
+ // LLSafeHandle actually holds a null pointer. We use LLSingleton
+ // specifically so that the "null instance" can be cleaned up at a well-
+ // defined time, specifically LLSingletonBase::deleteAll().
+ // Of course, as with any LLSingleton, the "null instance" is only
+ // instantiated on demand -- in this case, if you actually try to
+ // dereference an LLSafeHandle containing null.
+ class NullInstanceHolder: public LLSingleton<NullInstanceHolder>
+ {
+ LLSINGLETON_EMPTY_CTOR(NullInstanceHolder);
+ ~NullInstanceHolder() {}
+ public:
+ Type mNullInstance;
+ };
+
static Type* nonNull(Type* ptr)
{
- return ptr == NULL ? sNullFunc() : ptr;
+ return ptr? ptr : &NullInstanceHolder::instance().mNullInstance;
}
protected:
diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp
index a3a87edd88..9fbd78a000 100644
--- a/indra/llcommon/llsingleton.cpp
+++ b/indra/llcommon/llsingleton.cpp
@@ -391,62 +391,20 @@ void LLSingletonBase::deleteAll()
}
}
-/*------------------------ Final cleanup management ------------------------*/
-class LLSingletonBase::MasterRefcount
-{
-public:
- // store a POD int so it will be statically initialized to 0
- int refcount;
-};
-static LLSingletonBase::MasterRefcount sMasterRefcount;
-
-LLSingletonBase::ref_ptr_t LLSingletonBase::get_master_refcount()
-{
- // Calling this method constructs a new ref_ptr_t, which implicitly calls
- // intrusive_ptr_add_ref(MasterRefcount*).
- return &sMasterRefcount;
-}
-
-void intrusive_ptr_add_ref(LLSingletonBase::MasterRefcount* mrc)
-{
- // Count outstanding SingletonLifetimeManager instances.
- ++mrc->refcount;
-}
-
-void intrusive_ptr_release(LLSingletonBase::MasterRefcount* mrc)
-{
- // Notice when each SingletonLifetimeManager instance is destroyed.
- if (! --mrc->refcount)
- {
- // The last instance was destroyed. Time to kill any remaining
- // LLSingletons -- but in dependency order.
- LLSingletonBase::deleteAll();
- }
-}
-
/*---------------------------- Logging helpers -----------------------------*/
namespace {
bool oktolog()
{
// See comments in log() below.
- return sMasterRefcount.refcount && LLError::is_available();
+ return LLError::is_available();
}
void log(LLError::ELevel level,
const char* p1, const char* p2, const char* p3, const char* p4)
{
- // Check whether we're in the implicit final LLSingletonBase::deleteAll()
- // call. We've carefully arranged for deleteAll() to be called when the
- // last SingletonLifetimeManager instance is destroyed -- in other words,
- // when the last translation unit containing an LLSingleton instance
- // cleans up static data. That could happen after std::cerr is destroyed!
// The is_available() test below ensures that we'll stop logging once
// LLError has been cleaned up. If we had a similar portable test for
- // std::cerr, this would be a good place to use it. As we do not, just
- // don't log anything during implicit final deleteAll(). Detect that by
- // the master refcount having gone to zero.
- if (sMasterRefcount.refcount == 0)
- return;
+ // std::cerr, this would be a good place to use it.
// Check LLError::is_available() because some of LLError's infrastructure
// is itself an LLSingleton. If that LLSingleton has not yet been
diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index 1b915dfd6e..859e271e26 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -27,7 +27,6 @@
#include <boost/noncopyable.hpp>
#include <boost/unordered_set.hpp>
-#include <boost/intrusive_ptr.hpp>
#include <list>
#include <vector>
#include <typeinfo>
@@ -36,8 +35,6 @@ class LLSingletonBase: private boost::noncopyable
{
public:
class MasterList;
- class MasterRefcount;
- typedef boost::intrusive_ptr<MasterRefcount> ref_ptr_t;
private:
// All existing LLSingleton instances are tracked in this master list.
@@ -119,9 +116,6 @@ protected:
const char* p3="", const char* p4="");
static std::string demangle(const char* mangled);
- // obtain canonical ref_ptr_t
- static ref_ptr_t get_master_refcount();
-
// Default methods in case subclass doesn't declare them.
virtual void initSingleton() {}
virtual void cleanupSingleton() {}
@@ -175,10 +169,6 @@ public:
static void deleteAll();
};
-// support ref_ptr_t
-void intrusive_ptr_add_ref(LLSingletonBase::MasterRefcount*);
-void intrusive_ptr_release(LLSingletonBase::MasterRefcount*);
-
// Most of the time, we want LLSingleton_manage_master() to forward its
// methods to real LLSingletonBase methods.
template <class T>
@@ -298,8 +288,7 @@ private:
// stores pointer to singleton instance
struct SingletonLifetimeManager
{
- SingletonLifetimeManager():
- mMasterRefcount(LLSingletonBase::get_master_refcount())
+ SingletonLifetimeManager()
{
construct();
}
@@ -317,17 +306,14 @@ private:
// of static-object destruction, mean that we DO NOT WANT this
// destructor to delete this LLSingleton. This destructor will run
// without regard to any other LLSingleton whose cleanup might
- // depend on its existence. What we really want is to count the
- // runtime's attempts to cleanup LLSingleton static data -- and on
- // the very last one, call LLSingletonBase::deleteAll(). That
- // method will properly honor cross-LLSingleton dependencies. This
- // is why we store an intrusive_ptr to a MasterRefcount: our
- // ref_ptr_t member counts SingletonLifetimeManager instances.
- // Once the runtime destroys the last of these, THEN we can delete
- // every remaining LLSingleton.
+ // depend on its existence. If you want to clean up LLSingletons,
+ // call LLSingletonBase::deleteAll() sometime before static-object
+ // destruction begins. That method will properly honor cross-
+ // LLSingleton dependencies. Otherwise we simply leak LLSingleton
+ // instances at shutdown. Since the whole process is terminating
+ // anyway, that's not necessarily a bad thing; it depends on what
+ // resources your LLSingleton instances are managing.
}
-
- LLSingletonBase::ref_ptr_t mMasterRefcount;
};
protected:
@@ -452,6 +438,14 @@ public:
return sData.mInitState == INITIALIZED;
}
+ // Has this singleton been deleted? This can be useful during shutdown
+ // processing to avoid "resurrecting" a singleton we thought we'd already
+ // cleaned up.
+ static bool wasDeleted()
+ {
+ return sData.mInitState == DELETED;
+ }
+
private:
struct SingletonData
{
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 2255e638c2..a6629bc178 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -444,7 +444,7 @@ public:
struct LLDictionaryLess
{
public:
- bool operator()(const std::string& a, const std::string& b)
+ bool operator()(const std::string& a, const std::string& b) const
{
return (LLStringUtil::precedesDict(a, b) ? true : false);
}
diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp
index 1a66612e87..fd1828b1cc 100644
--- a/indra/llcommon/llsys.cpp
+++ b/indra/llcommon/llsys.cpp
@@ -914,22 +914,6 @@ U32Kilobytes LLMemoryInfo::getPhysicalMemoryKB() const
#endif
}
-U32Bytes LLMemoryInfo::getPhysicalMemoryClamped() const
-{
- // Return the total physical memory in bytes, but clamp it
- // to no more than U32_MAX
-
- U32Kilobytes phys_kb = getPhysicalMemoryKB();
- if (phys_kb >= U32Gigabytes(4))
- {
- return U32Bytes(U32_MAX);
- }
- else
- {
- return phys_kb;
- }
-}
-
//static
void LLMemoryInfo::getAvailableMemoryKB(U32Kilobytes& avail_physical_mem_kb, U32Kilobytes& avail_virtual_mem_kb)
{
@@ -1144,10 +1128,10 @@ LLSD LLMemoryInfo::loadStatsMap()
//
{
- vm_statistics_data_t vmstat;
- mach_msg_type_number_t vmstatCount = HOST_VM_INFO_COUNT;
+ vm_statistics64_data_t vmstat;
+ mach_msg_type_number_t vmstatCount = HOST_VM_INFO64_COUNT;
- if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t) &vmstat, &vmstatCount) != KERN_SUCCESS)
+ if (host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t) &vmstat, &vmstatCount) != KERN_SUCCESS)
{
LL_WARNS("LLMemoryInfo") << "Unable to collect memory information" << LL_ENDL;
}
@@ -1205,20 +1189,20 @@ LLSD LLMemoryInfo::loadStatsMap()
//
{
- task_basic_info_64_data_t taskinfo;
- unsigned taskinfoSize = sizeof(taskinfo);
-
- if (task_info(mach_task_self(), TASK_BASIC_INFO_64, (task_info_t) &taskinfo, &taskinfoSize) != KERN_SUCCESS)
+ mach_task_basic_info_data_t taskinfo;
+ mach_msg_type_number_t task_count = MACH_TASK_BASIC_INFO_COUNT;
+ if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t) &taskinfo, &task_count) != KERN_SUCCESS)
{
- LL_WARNS("LLMemoryInfo") << "Unable to collect task information" << LL_ENDL;
- }
- else
- {
- stats.add("Basic suspend count", taskinfo.suspend_count);
- stats.add("Basic virtual memory KB", taskinfo.virtual_size / 1024);
- stats.add("Basic resident memory KB", taskinfo.resident_size / 1024);
- stats.add("Basic new thread policy", taskinfo.policy);
- }
+ LL_WARNS("LLMemoryInfo") << "Unable to collect task information" << LL_ENDL;
+ }
+ else
+ {
+ stats.add("Basic virtual memory KB", taskinfo.virtual_size / 1024);
+ stats.add("Basic resident memory KB", taskinfo.resident_size / 1024);
+ stats.add("Basic max resident memory KB", taskinfo.resident_size_max / 1024);
+ stats.add("Basic new thread policy", taskinfo.policy);
+ stats.add("Basic suspend count", taskinfo.suspend_count);
+ }
}
#elif LL_SOLARIS
diff --git a/indra/llcommon/llsys.h b/indra/llcommon/llsys.h
index 962367f69f..95ef4cf065 100644
--- a/indra/llcommon/llsys.h
+++ b/indra/llcommon/llsys.h
@@ -113,11 +113,6 @@ public:
void stream(std::ostream& s) const; ///< output text info to s
U32Kilobytes getPhysicalMemoryKB() const;
-
- /*! Memory size in bytes, if total memory is >= 4GB then U32_MAX will
- ** be returned.
- */
- U32Bytes getPhysicalMemoryClamped() const; ///< Memory size in clamped bytes
//get the available memory infomation in KiloBytes.
static void getAvailableMemoryKB(U32Kilobytes& avail_physical_mem_kb, U32Kilobytes& avail_virtual_mem_kb);
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index c3f235c6ee..52255bfaeb 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -63,7 +63,7 @@ void set_thread_name( DWORD dwThreadID, const char* threadName)
__try
{
- ::RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(DWORD), (DWORD*)&info );
+ ::RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(DWORD), (ULONG_PTR*)&info );
}
__except(EXCEPTION_CONTINUE_EXECUTION)
{
diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h
index 5f1289dad8..79ff55b739 100644
--- a/indra/llcommon/lltrace.h
+++ b/indra/llcommon/lltrace.h
@@ -57,7 +57,7 @@ class StatBase
{
public:
StatBase(const char* name, const char* description);
- virtual ~StatBase() {};
+ virtual ~StatBase() LLINSTANCETRACKER_DTOR_NOEXCEPT {}
virtual const char* getUnitLabel() const;
const std::string& getName() const { return mName; }
diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp
index 5ba343b183..b27e125d2e 100644
--- a/indra/llcommon/tests/llprocess_test.cpp
+++ b/indra/llcommon/tests/llprocess_test.cpp
@@ -789,6 +789,69 @@ namespace tut
template<> template<>
void object::test<10>()
{
+ set_test_name("attached=false");
+ // almost just like autokill=false, except set autokill=true with
+ // attached=false.
+ NamedTempFile from("from", "not started");
+ NamedTempFile to("to", "");
+ LLProcess::handle phandle(0);
+ {
+ PythonProcessLauncher py(get_test_name(),
+ "from __future__ import with_statement\n"
+ "import sys, time\n"
+ "with open(sys.argv[1], 'w') as f:\n"
+ " f.write('ok')\n"
+ "# wait for 'go' from test program\n"
+ "for i in xrange(60):\n"
+ " time.sleep(1)\n"
+ " with open(sys.argv[2]) as f:\n"
+ " go = f.read()\n"
+ " if go == 'go':\n"
+ " break\n"
+ "else:\n"
+ " with open(sys.argv[1], 'w') as f:\n"
+ " f.write('never saw go')\n"
+ " sys.exit(1)\n"
+ "# okay, saw 'go', write 'ack'\n"
+ "with open(sys.argv[1], 'w') as f:\n"
+ " f.write('ack')\n");
+ py.mParams.args.add(from.getName());
+ py.mParams.args.add(to.getName());
+ py.mParams.autokill = true;
+ py.mParams.attached = false;
+ py.launch();
+ // Capture handle for later
+ phandle = py.mPy->getProcessHandle();
+ // Wait for the script to wake up and do its first write
+ int i = 0, timeout = 60;
+ for ( ; i < timeout; ++i)
+ {
+ yield();
+ if (readfile(from.getName(), "from autokill script") == "ok")
+ break;
+ }
+ // If we broke this loop because of the counter, something's wrong
+ ensure("script never started", i < timeout);
+ // Now destroy the LLProcess, which should NOT kill the child!
+ }
+ // If the destructor killed the child anyway, give it time to die
+ yield(2);
+ // How do we know it's not terminated? By making it respond to
+ // a specific stimulus in a specific way.
+ {
+ std::ofstream outf(to.getName().c_str());
+ outf << "go";
+ } // flush and close.
+ // now wait for the script to terminate... one way or another.
+ waitfor(phandle, "autokill script");
+ // If the LLProcess destructor implicitly called kill(), the
+ // script could not have written 'ack' as we expect.
+ ensure_equals(get_test_name() + " script output", readfile(from.getName()), "ack");
+ }
+
+ template<> template<>
+ void object::test<11>()
+ {
set_test_name("'bogus' test");
CaptureLog recorder;
PythonProcessLauncher py(get_test_name(),
@@ -801,7 +864,7 @@ namespace tut
}
template<> template<>
- void object::test<11>()
+ void object::test<12>()
{
set_test_name("'file' test");
// Replace this test with one or more real 'file' tests when we
@@ -815,7 +878,7 @@ namespace tut
}
template<> template<>
- void object::test<12>()
+ void object::test<13>()
{
set_test_name("'tpipe' test");
// Replace this test with one or more real 'tpipe' tests when we
@@ -832,7 +895,7 @@ namespace tut
}
template<> template<>
- void object::test<13>()
+ void object::test<14>()
{
set_test_name("'npipe' test");
// Replace this test with one or more real 'npipe' tests when we
@@ -850,7 +913,7 @@ namespace tut
}
template<> template<>
- void object::test<14>()
+ void object::test<15>()
{
set_test_name("internal pipe name warning");
CaptureLog recorder;
@@ -914,7 +977,7 @@ namespace tut
} while (0)
template<> template<>
- void object::test<15>()
+ void object::test<16>()
{
set_test_name("get*Pipe() validation");
PythonProcessLauncher py(get_test_name(),
@@ -934,7 +997,7 @@ namespace tut
}
template<> template<>
- void object::test<16>()
+ void object::test<17>()
{
set_test_name("talk to stdin/stdout");
PythonProcessLauncher py(get_test_name(),
@@ -992,7 +1055,7 @@ namespace tut
}
template<> template<>
- void object::test<17>()
+ void object::test<18>()
{
set_test_name("listen for ReadPipe events");
PythonProcessLauncher py(get_test_name(),
@@ -1052,7 +1115,7 @@ namespace tut
}
template<> template<>
- void object::test<18>()
+ void object::test<19>()
{
set_test_name("ReadPipe \"eof\" event");
PythonProcessLauncher py(get_test_name(),
@@ -1078,7 +1141,7 @@ namespace tut
}
template<> template<>
- void object::test<19>()
+ void object::test<20>()
{
set_test_name("setLimit()");
PythonProcessLauncher py(get_test_name(),
@@ -1107,7 +1170,7 @@ namespace tut
}
template<> template<>
- void object::test<20>()
+ void object::test<21>()
{
set_test_name("peek() ReadPipe data");
PythonProcessLauncher py(get_test_name(),
@@ -1160,7 +1223,7 @@ namespace tut
}
template<> template<>
- void object::test<21>()
+ void object::test<22>()
{
set_test_name("bad postend");
std::string pumpname("postend");
@@ -1185,7 +1248,7 @@ namespace tut
}
template<> template<>
- void object::test<22>()
+ void object::test<23>()
{
set_test_name("good postend");
PythonProcessLauncher py(get_test_name(),
@@ -1241,7 +1304,7 @@ namespace tut
};
template<> template<>
- void object::test<23>()
+ void object::test<24>()
{
set_test_name("all data visible at postend");
PythonProcessLauncher py(get_test_name(),
diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp
index 81b930e1e2..8836230640 100644
--- a/indra/llcommon/tests/llsdserialize_test.cpp
+++ b/indra/llcommon/tests/llsdserialize_test.cpp
@@ -1553,7 +1553,7 @@ namespace tut
params.executable = PYTHON;
params.args.add(scriptfile.getName());
LLProcessPtr py(LLProcess::create(params));
- ensure(STRINGIZE("Couldn't launch " << desc << " script"), py);
+ ensure(STRINGIZE("Couldn't launch " << desc << " script"), bool(py));
// Implementing timeout would mean messing with alarm() and
// catching SIGALRM... later maybe...
int status(0);