diff options
Diffstat (limited to 'indra/llcommon')
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 9c49f7eff4..cfca42809a 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); | 
