diff options
31 files changed, 528 insertions, 71 deletions
diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp index 3d27b4a5b5..f4dba16a94 100755 --- a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp +++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp @@ -42,6 +42,7 @@  #include "lldiriterator.h"  #include "v4coloru.h"  #include "llsdserialize.h" +#include "llcleanup.h"  // system libraries  #include <iostream> @@ -634,7 +635,7 @@ int main(int argc, char** argv)  	}  	// Cleanup and exit -	LLImage::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLImage);  	if (fast_timer_log_thread)  	{  		fast_timer_log_thread->shutdown(); diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 1459b9ada2..d2d507d676 100755 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -178,6 +178,7 @@ set(llcommon_HEADER_FILES      llmortician.h      llnametable.h      llpointer.h +    llpounceable.h      llpredicate.h      llpreprocessor.h      llpriqueuemap.h @@ -310,6 +311,7 @@ if (LL_TESTS)    LL_ADD_INTEGRATION_TEST(llprocess "" "${test_libs}")    LL_ADD_INTEGRATION_TEST(llleap "" "${test_libs}")    LL_ADD_INTEGRATION_TEST(llstreamqueue "" "${test_libs}") +  LL_ADD_INTEGRATION_TEST(llpounceable "" "${test_libs}")    # *TODO - reenable these once tcmalloc libs no longer break the build.    #ADD_BUILD_TEST(llallocator llcommon) diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index 5a40845e7d..2c52b11594 100755 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -48,6 +48,7 @@  #include "lleventtimer.h"  #include "google_breakpad/exception_handler.h"  #include "stringize.h" +#include "llcleanup.h"  //  // Signal handling @@ -177,7 +178,7 @@ LLApp::~LLApp()  	if(mExceptionHandler != 0) delete mExceptionHandler; -	LLCommon::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLCommon);  }  // static diff --git a/indra/llcommon/llcleanup.h b/indra/llcommon/llcleanup.h new file mode 100644 index 0000000000..8eda9a7fb3 --- /dev/null +++ b/indra/llcommon/llcleanup.h @@ -0,0 +1,30 @@ +/** + * @file   llcleanup.h + * @author Nat Goodspeed + * @date   2015-05-20 + * @brief  Mechanism for cleaning up subsystem resources + *  + * $LicenseInfo:firstyear=2015&license=viewerlgpl$ + * Copyright (c) 2015, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLCLEANUP_H) +#define LL_LLCLEANUP_H + +#include "llerror.h" + +// Instead of directly calling SomeClass::cleanupClass(), use +// SUBSYSTEM_CLEANUP(SomeClass); +// This logs the call as well as performing it. That gives us a baseline +// subsystem shutdown order against which to compare subsequent dynamic +// shutdown schemes. +#define SUBSYSTEM_CLEANUP(CLASSNAME)                                    \ +    do {                                                                \ +        LL_INFOS("Cleanup") << "Calling " #CLASSNAME "::cleanupClass()" << LL_ENDL; \ +        CLASSNAME::cleanupClass();                                      \ +    } while (0) +// Use ancient do { ... } while (0) macro trick to permit a block of +// statements with the same syntax as a single statement. + +#endif /* ! defined(LL_LLCLEANUP_H) */ diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp index 19642b0982..439ff4e628 100755 --- a/indra/llcommon/llcommon.cpp +++ b/indra/llcommon/llcommon.cpp @@ -31,6 +31,7 @@  #include "llthread.h"  #include "lltrace.h"  #include "lltracethreadrecorder.h" +#include "llcleanup.h"  //static  BOOL LLCommon::sAprInitialized = FALSE; @@ -63,11 +64,11 @@ void LLCommon::cleanupClass()  	sMasterThreadRecorder = NULL;  	LLTrace::set_master_thread_recorder(NULL);  	LLThreadSafeRefCount::cleanupThreadSafeRefCount(); -	LLTimer::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLTimer);  	if (sAprInitialized)  	{  		ll_cleanup_apr();  		sAprInitialized = FALSE;  	} -	LLMemory::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLMemory);  } diff --git a/indra/llcommon/llpounceable.h b/indra/llcommon/llpounceable.h new file mode 100644 index 0000000000..94d508d917 --- /dev/null +++ b/indra/llcommon/llpounceable.h @@ -0,0 +1,217 @@ +/** + * @file   llpounceable.h + * @author Nat Goodspeed + * @date   2015-05-22 + * @brief  LLPounceable is tangentially related to a future: it's a holder for + *         a value that may or may not exist yet. Unlike a future, though, + *         LLPounceable freely allows reading the held value. (If the held + *         type T does not have a distinguished "empty" value, consider using + *         LLPounceable<boost::optional<T>>.) + * + *         LLPounceable::callWhenReady() is this template's claim to fame. It + *         allows its caller to "pounce" on the held value as soon as it + *         becomes non-empty. Call callWhenReady() with any C++ callable + *         accepting T. If the held value is already non-empty, callWhenReady() + *         will immediately call the callable with the held value. If the held + *         value is empty, though, callWhenReady() will enqueue the callable + *         for later. As soon as LLPounceable is assigned a non-empty held + *         value, it will flush the queue of deferred callables. + * + *         Consider a global LLMessageSystem* gMessageSystem. Message system + *         initialization happens at a very specific point during viewer + *         initialization. Other subsystems want to register callbacks on the + *         LLMessageSystem instance as soon as it's initialized, but their own + *         initialization may precede that. If we define gMessageSystem to be + *         an LLPounceable<LLMessageSystem*>, a subsystem can use + *         callWhenReady() to either register immediately (if gMessageSystem + *         is already up and runnning) or register as soon as gMessageSystem + *         is set with a new, initialized instance. + * + * $LicenseInfo:firstyear=2015&license=viewerlgpl$ + * Copyright (c) 2015, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLPOUNCEABLE_H) +#define LL_LLPOUNCEABLE_H + +#include "llsingleton.h" +#include <boost/call_traits.hpp> +#include <boost/type_traits/remove_pointer.hpp> +#include <boost/utility/value_init.hpp> +#include <boost/unordered_map.hpp> +#include <boost/function.hpp> +#include <queue> + +// Forward declare the user template, since we want to be able to point to it +// in some of its implementation classes. +template <typename T, class TAG> +class LLPounceable; + +template <typename T, typename TAG> +struct LLPounceableTraits +{ +    // Call callWhenReady() with any callable accepting T. +    typedef boost::function<void (typename boost::call_traits<T>::param_type)> func_t; +    // Our actual queue is a simple queue of such callables. +    typedef std::queue<func_t> queue_t; +    // owner pointer type +    typedef LLPounceable<T, TAG>* owner_ptr; +}; + +// Tag types distinguish the two different implementations of LLPounceable's +// queue. +struct LLPounceableQueue {}; +struct LLPounceableStatic {}; + +// generic LLPounceableQueueImpl deliberately omitted: only the above tags are +// legal +template <typename T, class TAG> +class LLPounceableQueueImpl; + +// The implementation selected by LLPounceableStatic uses an LLSingleton +// because we can't count on a data member queue being initialized at the time +// we start getting callWhenReady() calls. This is that LLSingleton. +template <typename T> +class LLPounceableQueueSingleton: +    public LLSingleton<LLPounceableQueueSingleton<T> > +{ +private: +    typedef LLPounceableTraits<T, LLPounceableStatic> traits; +    typedef typename traits::owner_ptr owner_ptr; +    typedef typename traits::queue_t queue_t; + +    // For a given held type T, every LLPounceable<T, LLPounceableStatic> +    // instance will call on the SAME LLPounceableQueueSingleton instance -- +    // given how class statics work. We must keep a separate queue for each +    // LLPounceable instance. Use a hash map for that. +    typedef boost::unordered_map<owner_ptr, queue_t> map_t; + +public: +    // Disambiguate queues belonging to different LLPounceables. +    queue_t& get(owner_ptr owner) +    { +        // operator[] has find-or-create semantics -- just what we want! +        return mMap[owner]; +    } + +private: +    map_t mMap; +}; + +// LLPounceableQueueImpl that uses the above LLSingleton +template <typename T> +class LLPounceableQueueImpl<T, LLPounceableStatic> +{ +public: +    typedef LLPounceableTraits<T, LLPounceableStatic> traits; +    typedef typename traits::owner_ptr owner_ptr; +    typedef typename traits::queue_t queue_t; + +    queue_t& get(owner_ptr owner) const +    { +        // this Impl contains nothing; it delegates to the Singleton +        return LLPounceableQueueSingleton<T>::instance().get(owner); +    } +}; + +// The implementation selected by LLPounceableQueue directly contains the +// queue of interest, suitable for an LLPounceable we can trust to be fully +// initialized when it starts getting callWhenReady() calls. +template <typename T> +class LLPounceableQueueImpl<T, LLPounceableQueue> +{ +public: +    typedef LLPounceableTraits<T, LLPounceableQueue> traits; +    typedef typename traits::owner_ptr owner_ptr; +    typedef typename traits::queue_t queue_t; + +    queue_t& get(owner_ptr) +    { +        return mQueue; +    } + +private: +    queue_t mQueue; +}; + +// LLPounceable<T> is for an LLPounceable instance on the heap or the stack. +// LLPounceable<T, LLPounceableStatic> is for a static LLPounceable instance. +template <typename T, class TAG=LLPounceableQueue> +class LLPounceable +{ +private: +    typedef LLPounceableTraits<T, TAG> traits; +    typedef typename traits::owner_ptr owner_ptr; +    typedef typename traits::queue_t queue_t; + +public: +    typedef typename traits::func_t func_t; + +    // By default, both the initial value and the distinguished empty value +    // are a default-constructed T instance. However you can explicitly +    // specify each. +    LLPounceable(typename boost::call_traits<T>::value_type init =boost::value_initialized<T>(), +                 typename boost::call_traits<T>::param_type empty=boost::value_initialized<T>()): +        mHeld(init), +        mEmpty(empty) +    {} + +    // make read access to mHeld as cheap and transparent as possible +    operator T () const { return mHeld; } +    typename boost::remove_pointer<T>::type operator*() const { return *mHeld; } +    typename boost::call_traits<T>::value_type operator->() const { return mHeld; } +    // uncomment 'explicit' as soon as we allow C++11 compilation +    /*explicit*/ operator bool() const { return bool(mHeld); } +    bool operator!() const { return ! mHeld; } + +    // support both assignment (dumb ptr idiom) and reset() (smart ptr) +    void operator=(typename boost::call_traits<T>::param_type value) +    { +        reset(value); +    } + +    void reset(typename boost::call_traits<T>::param_type value) +    { +        mHeld = value; +        // If this new value is non-empty, flush anything pending in the queue. +        if (mHeld != mEmpty) +        { +            queue_t& queue(get_queue()); +            while (! queue.empty()) +            { +                queue.front()(mHeld); +                queue.pop(); +            } +        } +    } + +    // our claim to fame +    void callWhenReady(const func_t& func) +    { +        if (mHeld != mEmpty) +        { +            // If the held value is already non-empty, immediately call func() +            func(mHeld); +        } +        else +        { +            // held value still empty, queue func() for later +            get_queue().push(func); +        } +    } + +private: +    queue_t& get_queue() { return mQueue.get(this); } + +    // Store both the current and the empty value. +    // MAYBE: Might be useful to delegate to LLPounceableTraits the meaning of +    // testing for "empty." For some types we want operator!(); for others we +    // want to compare to a distinguished value. +    typename boost::call_traits<T>::value_type mHeld, mEmpty; +    // This might either contain the queue (LLPounceableQueue) or delegate to +    // an LLSingleton (LLPounceableStatic). +    LLPounceableQueueImpl<T, TAG> mQueue; +}; + +#endif /* ! defined(LL_LLPOUNCEABLE_H) */ diff --git a/indra/llcommon/llregistry.h b/indra/llcommon/llregistry.h index 29950c108d..fde729f8f9 100755 --- a/indra/llcommon/llregistry.h +++ b/indra/llcommon/llregistry.h @@ -269,7 +269,7 @@ public:  		~ScopedRegistrar()  		{ -			if (!singleton_t::destroyed()) +			if (singleton_t::instanceExists())  			{  				popScope();  			} diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 6e6291a165..a4877eed1f 100755 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -166,31 +166,19 @@ public:  		return NULL;  	} -	static DERIVED_TYPE* getIfExists() -	{ -		return sData.mInstance; -	} -  	// Reference version of getInstance()  	// Preferred over getInstance() as it disallows checking for NULL  	static DERIVED_TYPE& instance()  	{  		return *getInstance();  	} -	 -	// Has this singleton been created uet? -	// Use this to avoid accessing singletons before the can safely be constructed + +	// Has this singleton been created yet? +	// Use this to avoid accessing singletons before they can safely be constructed.  	static bool instanceExists()  	{  		return sData.mInitState == INITIALIZED;  	} -	 -	// Has this singleton already been deleted? -	// Use this to avoid accessing singletons from a static object's destructor -	static bool destroyed() -	{ -		return sData.mInitState == DELETED; -	}  private: diff --git a/indra/llcommon/tests/llpounceable_test.cpp b/indra/llcommon/tests/llpounceable_test.cpp new file mode 100644 index 0000000000..1f8cdca145 --- /dev/null +++ b/indra/llcommon/tests/llpounceable_test.cpp @@ -0,0 +1,200 @@ +/** + * @file   llpounceable_test.cpp + * @author Nat Goodspeed + * @date   2015-05-22 + * @brief  Test for llpounceable. + *  + * $LicenseInfo:firstyear=2015&license=viewerlgpl$ + * Copyright (c) 2015, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "llpounceable.h" +// STL headers +// std headers +// external library headers +#include <boost/bind.hpp> +// other Linden headers +#include "../test/lltut.h" + +struct Data +{ +    Data(const std::string& data): +        mData(data) +    {} +    const std::string mData; +}; + +void setter(Data** dest, Data* ptr) +{ +    *dest = ptr; +} + +static Data* static_check = 0; + +// Set up an extern pointer to an LLPounceableStatic so the linker will fill +// in the forward reference from below, before runtime. +extern LLPounceable<Data*, LLPounceableStatic> gForward; + +struct EnqueueCall +{ +    EnqueueCall() +    { +        // Intentionally use a forward reference to an LLPounceableStatic that +        // we believe is NOT YET CONSTRUCTED. This models the scenario in +        // which a constructor in another translation unit runs before +        // constructors in this one. We very specifically want callWhenReady() +        // to work even in that case: we need the LLPounceableQueueImpl to be +        // initialized even if the LLPounceable itself is not. +        gForward.callWhenReady(boost::bind(setter, &static_check, _1)); +    } +} nqcall; +// When this declaration is processed, we should enqueue the +// setter(&static_check, _1) call for when gForward is set non-NULL. Needless +// to remark, we want this call not to crash. + +// Now declare gForward. Its constructor should not run until after nqcall's. +LLPounceable<Data*, LLPounceableStatic> gForward; + +/***************************************************************************** +*   TUT +*****************************************************************************/ +namespace tut +{ +    struct llpounceable_data +    { +    }; +    typedef test_group<llpounceable_data> llpounceable_group; +    typedef llpounceable_group::object object; +    llpounceable_group llpounceablegrp("llpounceable"); + +    template<> template<> +    void object::test<1>() +    { +        set_test_name("LLPounceableStatic out-of-order test"); +        // LLPounceable<T, LLPounceableStatic>::callWhenReady() must work even +        // before LLPounceable's constructor runs. That's the whole point of +        // implementing it with an LLSingleton queue. This models (say) +        // LLPounceableStatic<LLMessageSystem*, LLPounceableStatic>. +        ensure("static_check should still be null", ! static_check); +        Data myData("test<1>"); +        gForward = &myData;         // should run setter +        ensure_equals("static_check should be &myData", static_check, &myData); +    } + +    template<> template<> +    void object::test<2>() +    { +        set_test_name("LLPounceableQueue different queues"); +        // We expect that LLPounceable<T, LLPounceableQueue> should have +        // different queues because that specialization stores the queue +        // directly in the LLPounceable instance. +        Data *aptr = 0, *bptr = 0; +        LLPounceable<Data*> a, b; +        a.callWhenReady(boost::bind(setter, &aptr, _1)); +        b.callWhenReady(boost::bind(setter, &bptr, _1)); +        ensure("aptr should be null", ! aptr); +        ensure("bptr should be null", ! bptr); +        Data adata("a"), bdata("b"); +        a = &adata; +        ensure_equals("aptr should be &adata", aptr, &adata); +        // but we haven't yet set b +        ensure("bptr should still be null", !bptr); +        b = &bdata; +        ensure_equals("bptr should be &bdata", bptr, &bdata); +    } + +    template<> template<> +    void object::test<3>() +    { +        set_test_name("LLPounceableStatic different queues"); +        // LLPounceable<T, LLPounceableStatic> should also have a distinct +        // queue for each instance, but that engages an additional map lookup +        // because there's only one LLSingleton for each T. +        Data *aptr = 0, *bptr = 0; +        LLPounceable<Data*, LLPounceableStatic> a, b; +        a.callWhenReady(boost::bind(setter, &aptr, _1)); +        b.callWhenReady(boost::bind(setter, &bptr, _1)); +        ensure("aptr should be null", ! aptr); +        ensure("bptr should be null", ! bptr); +        Data adata("a"), bdata("b"); +        a = &adata; +        ensure_equals("aptr should be &adata", aptr, &adata); +        // but we haven't yet set b +        ensure("bptr should still be null", !bptr); +        b = &bdata; +        ensure_equals("bptr should be &bdata", bptr, &bdata); +    } + +    template<> template<> +    void object::test<4>() +    { +        set_test_name("LLPounceable<T> looks like T"); +        // We want LLPounceable<T, TAG> to be drop-in replaceable for a plain +        // T for read constructs. In particular, it should behave like a dumb +        // pointer -- and with zero abstraction cost for such usage. +        Data* aptr = 0; +        Data a("a"); +        // should be able to initialize a pounceable (when its constructor +        // runs) +        LLPounceable<Data*> pounceable = &a; +        // should be able to pass LLPounceable<T> to function accepting T +        setter(&aptr, pounceable); +        ensure_equals("aptr should be &a", aptr, &a); +        // should be able to dereference with * +        ensure_equals("deref with *", (*pounceable).mData, "a"); +        // should be able to dereference with -> +        ensure_equals("deref with ->", pounceable->mData, "a"); +        // bool operations +        ensure("test with operator bool()", pounceable); +        ensure("test with operator !()", ! (! pounceable)); +    } + +    template<> template<> +    void object::test<5>() +    { +        set_test_name("Multiple callWhenReady() queue items"); +        Data *p1 = 0, *p2 = 0, *p3 = 0; +        Data a("a"); +        LLPounceable<Data*> pounceable; +        // queue up a couple setter() calls for later +        pounceable.callWhenReady(boost::bind(setter, &p1, _1)); +        pounceable.callWhenReady(boost::bind(setter, &p2, _1)); +        // should still be pending +        ensure("p1 should be null", !p1); +        ensure("p2 should be null", !p2); +        ensure("p3 should be null", !p3); +        pounceable = 0; +        // assigning a new empty value shouldn't flush the queue +        ensure("p1 should still be null", !p1); +        ensure("p2 should still be null", !p2); +        ensure("p3 should still be null", !p3); +        // using whichever syntax +        pounceable.reset(0); +        // try to make ensure messages distinct... tough to pin down which +        // ensure() failed if multiple ensure() calls in the same test<n> have +        // the same message! +        ensure("p1 should again be null", !p1); +        ensure("p2 should again be null", !p2); +        ensure("p3 should again be null", !p3); +        pounceable.reset(&a);       // should flush queue +        ensure_equals("p1 should be &a", p1, &a); +        ensure_equals("p2 should be &a", p2, &a); +        ensure("p3 still not set", !p3); +        // immediate call +        pounceable.callWhenReady(boost::bind(setter, &p3, _1)); +        ensure_equals("p3 should be &a", p3, &a); +    } + +    template<> template<> +    void object::test<6>() +    { +        set_test_name("compile-fail test, uncomment to check"); +        // The following declaration should fail: only LLPounceableQueue and +        // LLPounceableStatic should work as tags. +//      LLPounceable<Data*, int> pounceable; +    } +} // namespace tut diff --git a/indra/llcommon/tests/llsingleton_test.cpp b/indra/llcommon/tests/llsingleton_test.cpp index 385289aefe..bed436283a 100755 --- a/indra/llcommon/tests/llsingleton_test.cpp +++ b/indra/llcommon/tests/llsingleton_test.cpp @@ -65,7 +65,6 @@ namespace tut  		//Delete the instance  		LLSingletonTest::deleteSingleton(); -		ensure(LLSingletonTest::destroyed());  		ensure(!LLSingletonTest::instanceExists());  		//Construct it again. diff --git a/indra/llcorehttp/tests/llcorehttp_test.cpp b/indra/llcorehttp/tests/llcorehttp_test.cpp index e863ddd13f..19a20e663c 100755 --- a/indra/llcorehttp/tests/llcorehttp_test.cpp +++ b/indra/llcorehttp/tests/llcorehttp_test.cpp @@ -46,6 +46,7 @@  #include "test_httprequestqueue.hpp"  #include "llproxy.h" +#include "llcleanup.h"  unsigned long ssl_thread_id_callback(void);  void ssl_locking_callback(int mode, int type, const char * file, int line); @@ -101,7 +102,7 @@ void init_curl()  void term_curl()  { -	LLProxy::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLProxy);  	CRYPTO_set_locking_callback(NULL);  	for (int i(0); i < ssl_mutex_count; ++i) diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp index 7a97c16ea7..0d239c9435 100755 --- a/indra/llcrashlogger/llcrashlogger.cpp +++ b/indra/llcrashlogger/llcrashlogger.cpp @@ -45,6 +45,7 @@  #include "llhttpclient.h"  #include "llsdserialize.h"  #include "llproxy.h" +#include "llcleanup.h"  LLPumpIO* gServicePump = NULL;  BOOL gBreak = false; @@ -587,5 +588,5 @@ bool LLCrashLogger::init()  void LLCrashLogger::commonCleanup()  {  	LLError::logToFile("");   //close crashreport.log -	LLProxy::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLProxy);  } diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index e9ce94ab3b..3c3683f12a 100755 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -77,6 +77,7 @@  #include "v3math.h"  #include "v4math.h"  #include "lltransfertargetvfile.h" +#include "llpounceable.h"  // Constants  //const char* MESSAGE_LOG_FILENAME = "message.log"; @@ -1776,7 +1777,9 @@ std::ostream& operator<<(std::ostream& s, LLMessageSystem &msg)  	return s;  } -LLMessageSystem	*gMessageSystem = NULL; +// LLPounceable supports callWhenReady(), to permit clients to queue up (e.g.) +// callback registrations for when gMessageSystem is first assigned +LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem;  // update appropriate ping info  void	process_complete_ping_check(LLMessageSystem *msgsystem, void** /*user_data*/) @@ -2693,7 +2696,7 @@ void end_messaging_system(bool print_summary)  			LL_INFOS("Messaging") << str.str().c_str() << LL_ENDL;  		} -		delete gMessageSystem; +		delete static_cast<LLMessageSystem*>(gMessageSystem);  		gMessageSystem = NULL;  	}  } diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h index 348b09b992..a6fabf2126 100755 --- a/indra/llmessage/message.h +++ b/indra/llmessage/message.h @@ -60,6 +60,7 @@  #include "llmessagesenderinterface.h"  #include "llstoredmessage.h" +#include "llpounceable.h"  const U32 MESSAGE_MAX_STRINGS_LENGTH = 64;  const U32 MESSAGE_NUMBER_OF_HASH_BUCKETS = 8192; @@ -830,7 +831,7 @@ private:  // external hook into messaging system -extern LLMessageSystem	*gMessageSystem; +extern LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem;  // Must specific overall system version, which is used to determine  // if a patch is available in the message template checksum verification. diff --git a/indra/llmessage/tests/llhttpclient_test.cpp b/indra/llmessage/tests/llhttpclient_test.cpp index a32bfa59ce..9356a14f1f 100755 --- a/indra/llmessage/tests/llhttpclient_test.cpp +++ b/indra/llmessage/tests/llhttpclient_test.cpp @@ -42,6 +42,7 @@  #include "lliosocket.h"  #include "stringize.h" +#include "llcleanup.h"  namespace tut  { @@ -66,7 +67,7 @@ namespace tut  		~HTTPClientTestData()  		{  			delete mClientPump; -			LLProxy::cleanupClass(); +			SUBSYSTEM_CLEANUP(LLProxy);  			apr_pool_destroy(mPool);  		} diff --git a/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp b/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp index 3b04530c1a..e20f61b73f 100755 --- a/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp +++ b/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp @@ -31,11 +31,12 @@  #include "llhost.h"  #include "message.h"  #include "llsd.h" +#include "llpounceable.h"  #include "llhost.cpp" // Needed for copy operator  #include "net.cpp" // Needed by LLHost. -LLMessageSystem * gMessageSystem = NULL; +LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem;  // sensor test doubles  bool gClearRecvWasCalled = false; diff --git a/indra/llmessage/tests/lltrustedmessageservice_test.cpp b/indra/llmessage/tests/lltrustedmessageservice_test.cpp index 55748ad27e..41f982a7e2 100755 --- a/indra/llmessage/tests/lltrustedmessageservice_test.cpp +++ b/indra/llmessage/tests/lltrustedmessageservice_test.cpp @@ -33,8 +33,9 @@  #include "message.h"  #include "llmessageconfig.h"  #include "llhttpnode_stub.cpp" +#include "llpounceable.h" -LLMessageSystem* gMessageSystem = NULL; +LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem;  LLMessageConfig::SenderTrust  LLMessageConfig::getSenderTrustedness(const std::string& msg_name) diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index aabc7ed2e4..cc186f4997 100755 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -60,6 +60,7 @@  #include "llflyoutbutton.h"  #include "llsearcheditor.h"  #include "lltoolbar.h" +#include "llcleanup.h"  // for XUIParse  #include "llquaternion.h" @@ -208,7 +209,7 @@ void LLUI::initClass(const settings_map_t& settings,  void LLUI::cleanupClass()  { -	LLRender2D::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLRender2D);  }  void LLUI::setPopupFuncs(const add_popup_t& add_popup, const remove_popup_t& remove_popup,  const clear_popups_t& clear_popups) diff --git a/indra/llui/tests/llurlentry_stub.cpp b/indra/llui/tests/llurlentry_stub.cpp index 5d3f9ac327..d28f601009 100755 --- a/indra/llui/tests/llurlentry_stub.cpp +++ b/indra/llui/tests/llurlentry_stub.cpp @@ -31,6 +31,7 @@  #include "llcachename.h"  #include "lluuid.h"  #include "message.h" +#include "llpounceable.h"  #include <string> @@ -167,7 +168,7 @@ char const* const _PREHASH_AgentID = (char *)"AgentID";  LLHost LLHost::invalid(INVALID_PORT,INVALID_HOST_IP_ADDRESS); -LLMessageSystem* gMessageSystem = NULL; +LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem;  //  // Stub implementation for LLMessageSystem diff --git a/indra/lscript/lscript_compile/indra.l b/indra/lscript/lscript_compile/indra.l index 7772c95609..d5c71d9987 100755 --- a/indra/lscript/lscript_compile/indra.l +++ b/indra/lscript/lscript_compile/indra.l @@ -102,7 +102,7 @@ int yyerror(const char *fmt, ...);  "event"				{ count(); return(EVENT); }  "jump"				{ count(); return(JUMP); }  "return"			{ count(); return(RETURN); } -"if"				{ count(); return(IF); } +"if"				{ count(); return(IFF); }  "else"				{ count(); return(ELSE); }  "for"				{ count(); return(FOR); }  "do"				{ count(); return(DO); } diff --git a/indra/lscript/lscript_compile/indra.y b/indra/lscript/lscript_compile/indra.y index a0a034d21c..604b5b6b92 100755 --- a/indra/lscript/lscript_compile/indra.y +++ b/indra/lscript/lscript_compile/indra.y @@ -117,7 +117,7 @@  %token					SHIFT_LEFT  %token					SHIFT_RIGHT -%token					IF +%token					IFF         /* IF used by a helper library */  %token					ELSE  %token					FOR  %token					DO @@ -1312,13 +1312,13 @@ statement  	{   		$$ = $1;  	} -	| IF '(' expression ')' statement	%prec LOWER_THAN_ELSE			 +	| IFF '(' expression ')' statement	%prec LOWER_THAN_ELSE			  	{    		$$ = new LLScriptIf(gLine, gColumn, $3, $5);  		$5->mAllowDeclarations = FALSE;  		gAllocationManager->addAllocation($$);  	} -	| IF '(' expression ')' statement ELSE statement					 +	| IFF '(' expression ')' statement ELSE statement					  	{    		$$ = new LLScriptIfElse(gLine, gColumn, $3, $5, $7);  		$5->mAllowDeclarations = FALSE; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 6dc71bc94e..6a64f67f9c 100755 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -226,6 +226,7 @@  #include "llsecapi.h"  #include "llmachineid.h"  #include "llmainlooprepeater.h" +#include "llcleanup.h"  #include "llviewereventrecorder.h" @@ -1764,7 +1765,7 @@ bool LLAppViewer::cleanup()  	gTransferManager.cleanup();  #endif -	LLLocalBitmapMgr::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLLocalBitmapMgr);  	// Note: this is where gWorldMap used to be deleted. @@ -1872,11 +1873,11 @@ bool LLAppViewer::cleanup()  	LLViewerObject::cleanupVOClasses(); -	LLAvatarAppearance::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLAvatarAppearance); -	LLAvatarAppearance::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLAvatarAppearance); -	LLPostProcess::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLPostProcess);  	LLTracker::cleanupInstance(); @@ -1902,12 +1903,12 @@ bool LLAppViewer::cleanup()   	//end_messaging_system(); -	LLFollowCamMgr::cleanupClass(); -	//LLVolumeMgr::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLFollowCamMgr); +	//SUBSYSTEM_CLEANUP(LLVolumeMgr);  	LLPrimitive::cleanupVolumeManager(); -	LLWorldMapView::cleanupClass(); -	LLFolderViewItem::cleanupClass(); -	LLUI::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLWorldMapView); +	SUBSYSTEM_CLEANUP(LLFolderViewItem); +	SUBSYSTEM_CLEANUP(LLUI);  	//  	// Shut down the VFS's AFTER the decode manager cleans up (since it cleans up vfiles). @@ -1916,7 +1917,7 @@ bool LLAppViewer::cleanup()  	//  	LL_INFOS() << "Cleaning up VFS" << LL_ENDL; -	LLVFile::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLVFile);  	LL_INFOS() << "Saving Data" << LL_ENDL; @@ -2020,7 +2021,7 @@ bool LLAppViewer::cleanup()  	// *NOTE:Mani - The following call is not thread safe.   	LL_CHECK_MEMORY -	LLCurl::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLCurl);  	LL_CHECK_MEMORY  	// Non-LLCurl libcurl library @@ -2029,9 +2030,9 @@ bool LLAppViewer::cleanup()  	// NOTE The following call is not thread safe.   	ll_cleanup_ares(); -	LLFilePickerThread::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLFilePickerThread); -	//MUST happen AFTER LLCurl::cleanupClass +	//MUST happen AFTER SUBSYSTEM_CLEANUP(LLCurl)  	delete sTextureCache;      sTextureCache = NULL;  	delete sTextureFetch; @@ -2060,17 +2061,17 @@ bool LLAppViewer::cleanup()  	LL_INFOS() << "Cleaning up Media and Textures" << LL_ENDL;  	//Note: -	//LLViewerMedia::cleanupClass() has to be put before gTextureList.shutdown() +	//SUBSYSTEM_CLEANUP(LLViewerMedia) has to be put before gTextureList.shutdown()  	//because some new image might be generated during cleaning up media. --bao -	LLViewerMedia::cleanupClass(); -	LLViewerParcelMedia::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLViewerMedia); +	SUBSYSTEM_CLEANUP(LLViewerParcelMedia);  	gTextureList.shutdown(); // shutdown again in case a callback added something  	LLUIImageList::getInstance()->cleanUp();  	// This should eventually be done in LLAppViewer -	LLImage::cleanupClass(); -	LLVFSThread::cleanupClass(); -	LLLFSThread::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLImage); +	SUBSYSTEM_CLEANUP(LLVFSThread); +	SUBSYSTEM_CLEANUP(LLLFSThread);  #ifndef LL_RELEASE_FOR_DOWNLOAD  	LL_INFOS() << "Auditing VFS" << LL_ENDL; @@ -2113,9 +2114,9 @@ bool LLAppViewer::cleanup()  		LL_INFOS() << "File launched." << LL_ENDL;  	}  	LL_INFOS() << "Cleaning up LLProxy." << LL_ENDL; -	LLProxy::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLProxy); -	LLWearableType::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLWearableType);  	LLMainLoopRepeater::instance().stop(); diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index ab57e8c170..cacd66aee9 100755 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -101,7 +101,7 @@ LLFloaterIMContainer::~LLFloaterIMContainer()  	gSavedPerAccountSettings.setBOOL("ConversationsMessagePaneCollapsed", mMessagesPane->isCollapsed());  	gSavedPerAccountSettings.setBOOL("ConversationsParticipantListCollapsed", !isParticipantListExpanded()); -	if (!LLSingleton<LLIMMgr>::destroyed()) +	if (LLIMMgr::instanceExists())  	{  		LLIMMgr::getInstance()->removeSessionObserver(this);  	} diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp index 65ac11092c..681203ef4f 100755 --- a/indra/newview/llmutelist.cpp +++ b/indra/newview/llmutelist.cpp @@ -152,7 +152,7 @@ LLMuteList* LLMuteList::getInstance()  {  	// Register callbacks at the first time that we find that the message system has been created.  	static BOOL registered = FALSE; -	if( !registered && gMessageSystem != NULL) +	if( !registered && gMessageSystem)  	{  		registered = TRUE;  		// Register our various callbacks diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 42fc300187..3a85468bda 100755 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -194,6 +194,7 @@  #include "llevents.h"  #include "llstartuplistener.h"  #include "lltoolbarview.h" +#include "llcleanup.h"  #if LL_WINDOWS  #include "lldxhardware.h" @@ -2826,7 +2827,7 @@ void LLStartUp::initNameCache()  void LLStartUp::cleanupNameCache()  { -	LLAvatarNameCache::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLAvatarNameCache);  	delete gCacheName;  	gCacheName = NULL; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 3b0adcf7f4..e7c93926d7 100755 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -130,6 +130,7 @@  #include "llpathfindingmanager.h"  #include "llstartup.h"  #include "boost/unordered_map.hpp" +#include "llcleanup.h"  using namespace LLAvatarAppearanceDefines; @@ -8416,7 +8417,7 @@ class LLWorldPostProcess : public view_listener_t  void handle_flush_name_caches()  { -	LLAvatarNameCache::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLAvatarNameCache);  	if (gCacheName) gCacheName->clear();  } diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index a2c0a91ea6..f463c620d3 100755 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -102,6 +102,7 @@  #include "llmediaentry.h"  #include "llfloaterperms.h"  #include "llvocache.h" +#include "llcleanup.h"  //#define DEBUG_UPDATE_TYPE @@ -527,11 +528,11 @@ void LLViewerObject::initVOClasses()  void LLViewerObject::cleanupVOClasses()  { -	LLVOGrass::cleanupClass(); -	LLVOWater::cleanupClass(); -	LLVOTree::cleanupClass(); -	LLVOAvatar::cleanupClass(); -	LLVOVolume::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLVOGrass); +	SUBSYSTEM_CLEANUP(LLVOWater); +	SUBSYSTEM_CLEANUP(LLVOTree); +	SUBSYSTEM_CLEANUP(LLVOAvatar); +	SUBSYSTEM_CLEANUP(LLVOVolume);  	sObjectDataMap.clear();  } diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index e317989f04..12ff88c517 100755 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -208,6 +208,7 @@  #include "llwindowlistener.h"  #include "llviewerwindowlistener.h"  #include "llpaneltopinfobar.h" +#include "llcleanup.h"  #if LL_WINDOWS  #include <tchar.h> // For Unicode conversion methods @@ -2124,7 +2125,7 @@ void LLViewerWindow::shutdownGL()  	// Shutdown GL cleanly.  Order is very important here.  	//--------------------------------------------------------  	LLFontGL::destroyDefaultFonts(); -	LLFontManager::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLFontManager);  	stop_glerror();  	gSky.cleanup(); @@ -2147,7 +2148,7 @@ void LLViewerWindow::shutdownGL()  	LLWorldMapView::cleanupTextures();  	LLViewerTextureManager::cleanup() ; -	LLImageGL::cleanupClass() ; +	SUBSYSTEM_CLEANUP(LLImageGL) ;  	LL_INFOS() << "All textures and llimagegl images are destroyed!" << LL_ENDL ; @@ -2160,7 +2161,7 @@ void LLViewerWindow::shutdownGL()  	gGL.shutdown(); -	LLVertexBuffer::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLVertexBuffer);  	LL_INFOS() << "LLVertexBuffer cleaned." << LL_ENDL ;  } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 03712c1065..9c1b78626f 100755 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -115,6 +115,7 @@  #include "llpathfindingpathtool.h"  #include "llscenemonitor.h"  #include "llprogressview.h" +#include "llcleanup.h"  #ifdef _DEBUG  // Debug indices is disabled for now for debug performance - djs 4/24/02 @@ -7373,7 +7374,7 @@ void LLPipeline::doResetVertexBuffers(bool forced)  	}  	LLVOPartGroup::destroyGL(); -	LLVertexBuffer::cleanupClass(); +	SUBSYSTEM_CLEANUP(LLVertexBuffer);  	//delete all name pool caches  	LLGLNamePool::cleanupPools(); diff --git a/indra/newview/tests/llremoteparcelrequest_test.cpp b/indra/newview/tests/llremoteparcelrequest_test.cpp index c49b0350e9..5e3649fdae 100755 --- a/indra/newview/tests/llremoteparcelrequest_test.cpp +++ b/indra/newview/tests/llremoteparcelrequest_test.cpp @@ -33,6 +33,7 @@  #include "../llagent.h"  #include "message.h"  #include "llurlentry.h" +#include "llpounceable.h"  namespace {  	const LLUUID TEST_PARCEL_ID("11111111-1111-1111-1111-111111111111"); @@ -61,7 +62,7 @@ void LLMessageSystem::addUUID(char const *,LLUUID const &) { }  void LLMessageSystem::addUUIDFast(char const *,LLUUID const &) { }  void LLMessageSystem::nextBlockFast(char const *) { }  void LLMessageSystem::newMessage(char const *) { } -LLMessageSystem * gMessageSystem; +LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem;  char const* const _PREHASH_AgentID = 0;   // never dereferenced during this test  char const* const _PREHASH_AgentData = 0; // never dereferenced during this test  LLAgent gAgent; diff --git a/indra/test/message_tut.cpp b/indra/test/message_tut.cpp index aa23699de0..b9c025f518 100755 --- a/indra/test/message_tut.cpp +++ b/indra/test/message_tut.cpp @@ -103,7 +103,7 @@ namespace tut  		~LLMessageSystemTestData()  		{  			// not end_messaging_system() -			delete gMessageSystem; +			delete static_cast<LLMessageSystem*>(gMessageSystem);  			gMessageSystem = NULL;  			// rm contents of temp dir  | 
