diff options
Diffstat (limited to 'indra')
| -rw-r--r-- | indra/llcommon/llsingleton.h | 205 | ||||
| -rw-r--r-- | indra/llimage/llimage.cpp | 34 | ||||
| -rw-r--r-- | indra/llimage/llimage.h | 31 | ||||
| -rw-r--r-- | indra/llimage/llimagej2c.cpp | 4 | ||||
| -rw-r--r-- | indra/newview/llappviewer.cpp | 3 | ||||
| -rw-r--r-- | indra/newview/llconversationlog.h | 5 | ||||
| -rw-r--r-- | indra/newview/llstartup.cpp | 2 | 
7 files changed, 240 insertions, 44 deletions
| diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 859e271e26..b127f4f529 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -446,6 +446,177 @@ public:          return sData.mInitState == DELETED;      } +protected: +    static EInitState getInitState() +    { +        return sData.mInitState; +    } + +private: +    struct SingletonData +    { +        // explicitly has a default constructor so that member variables are zero initialized in BSS +        // and only changed by singleton logic, not constructor running during startup +        EInitState      mInitState; +        DERIVED_TYPE*   mInstance; +    }; +    static SingletonData sData; +}; + + +template <typename DERIVED_TYPE> +class LLParamSingleton : public LLSingletonBase +{ +private: + +    template <typename... Args> +    static DERIVED_TYPE* constructSingleton(Args&&... args) +    { +        return new DERIVED_TYPE(std::forward<Args>(args)...); +    } + +    // We know of no way to instruct the compiler that every subclass +    // constructor MUST be private. +    // However, we can make the LLPARAMSINGLETON() macro both declare +    // a private constructor and provide the required friend declaration. +    // How can we ensure that every subclass uses LLPARAMSINGLETON()? +    // By making that macro provide a definition for this pure virtual +    // method. If you get "can't instantiate class due to missing pure +    // virtual method" for this method, then add LLPARAMSINGLETON(yourclass) +    // in the subclass body. +    virtual void you_must_use_LLSINGLETON_macro() = 0; + +protected: +    // Pass DERIVED_TYPE explicitly to LLSingletonBase's constructor because, +    // until our subclass constructor completes, *this isn't yet a +    // full-fledged DERIVED_TYPE. +    LLParamSingleton() : LLSingletonBase(LLSingletonBase::tag<DERIVED_TYPE>()) +    { +        // populate base-class function pointer with the static +        // deleteSingleton() function for this particular specialization +        mDeleteSingleton = &deleteSingleton; + +        // add this new instance to the master list +        LLSingleton_manage_master<DERIVED_TYPE>().add(this); +    } + +public: + +    virtual ~LLParamSingleton() +    { +        // remove this instance from the master list +        LLSingleton_manage_master<DERIVED_TYPE>().remove(this); +        sData.mInstance = NULL; +        sData.mInitState = DELETED; +    } + +    // Passes arguments to DERIVED_TYPE's constructor and sets apropriate states +    template <typename... Args> +    static void initParamSingleton(Args&&... args) +    { +        sData.mInitState = CONSTRUCTING; +        sData.mInstance = constructSingleton(std::forward<Args>(args)...); +        sData.mInitState = INITIALIZED; +        // initialize singleton after constructing it so that it can +        // reference other singletons which in turn depend on it, thus +        // breaking cyclic dependencies +        sData.mInstance->initSingleton(); +        // pop this off stack of initializing singletons +        LLSingleton_manage_master<DERIVED_TYPE>().pop_initializing(sData.mInstance); +    } + +    /** +    * @brief Immediately delete the singleton. +    * +    * A subsequent call to LLProxy::getInstance() will construct a new +    * instance of the class. +    * +    * Without an explicit call to LLSingletonBase::deleteAll(), LLSingletons +    * are implicitly destroyed after main() has exited and the C++ runtime is +    * cleaning up statically-constructed objects. Some classes derived from +    * LLSingleton have objects that are part of a runtime system that is +    * terminated before main() exits. Calling the destructor of those objects +    * after the termination of their respective systems can cause crashes and +    * other problems during termination of the project. Using this method to +    * destroy the singleton early can prevent these crashes. +    * +    * An example where this is needed is for a LLSingleton that has an APR +    * object as a member that makes APR calls on destruction. The APR system is +    * shut down explicitly before main() exits. This causes a crash on exit. +    * Using this method before the call to apr_terminate() and NOT calling +    * getInstance() again will prevent the crash. +    */ +    static void deleteSingleton() +    { +        delete sData.mInstance; +        sData.mInstance = NULL; +        sData.mInitState = DELETED; +    } + +    static DERIVED_TYPE* getInstance() +    { +        switch (sData.mInitState) +        { +        case UNINITIALIZED: +            logerrs("Uninitialized param singleton ", +                demangle(typeid(DERIVED_TYPE).name()).c_str()); +            return NULL; + +        case CONSTRUCTING: +            logerrs("Tried to access singleton ", +                demangle(typeid(DERIVED_TYPE).name()).c_str(), +                " from singleton constructor!"); +            return NULL; + +        case INITIALIZING: +            logerrs("State not supported by ", +                demangle(typeid(DERIVED_TYPE).name()).c_str(), +                " since it is a parametric singleton!"); +            break; + +        case INITIALIZED: +            break; + +        case DELETED: +            logerrs("Trying to access deleted param singleton ", +                demangle(typeid(DERIVED_TYPE).name()).c_str()); + +            break; +        } + +        // By this point, if DERIVED_TYPE was pushed onto the initializing +        // stack, it has been popped off. So the top of that stack, if any, is +        // an LLSingleton that directly depends on DERIVED_TYPE. If this call +        // came from another LLSingleton, rather than from vanilla application +        // code, record the dependency. +        sData.mInstance->capture_dependency( +            LLSingleton_manage_master<DERIVED_TYPE>().get_initializing(sData.mInstance), +            sData.mInitState); +        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 yet? +    // Use this to avoid accessing singletons before they can safely be constructed. +    static bool instanceExists() +    { +        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      { @@ -460,6 +631,9 @@ private:  template<typename T>  typename LLSingleton<T>::SingletonData LLSingleton<T>::sData; +template<typename T> +typename LLParamSingleton<T>::SingletonData LLParamSingleton<T>::sData; +  /**   * Use LLSINGLETON(Foo); at the start of an LLSingleton<Foo> subclass body   * when you want to declare an out-of-line constructor: @@ -510,4 +684,35 @@ private:                                                                \      /* LLSINGLETON() is carefully implemented to permit exactly this */ \      LLSINGLETON(DERIVED_CLASS) {} +/** +* Use LLPARAMSINGLETON(Foo); at the start of an LLParamSingleton<Foo> subclass body +* when you want to declare an out-of-line constructor: +* +* @code +*   class Foo: public LLParamSingleton<Foo> +*   { +*       // use this macro at start of every LLSingleton subclass +*       LLPARAMSINGLETON(Foo); +*   public: +*       // ... +*   }; +*   // ... +*   [inline] +*   Foo::Foo() { ... } +* @endcode +* +* Unfortunately, this mechanism does not permit you to define even a simple +* (but nontrivial) constructor within the class body. Use LLPARAMSINGLETON() +* and define the constructor outside the class body. If you must define it +* in a header file, use 'inline' (unless it's a template class) to avoid +* duplicate-symbol errors at link time. +*/ +#define LLPARAMSINGLETON(DERIVED_CLASS, ...)                                      \ +private:                                                                \ +    /* implement LLSingleton pure virtual method whose sole purpose */  \ +    /* is to remind people to use this macro */                         \ +    virtual void you_must_use_LLSINGLETON_macro() {}                    \ +    friend class LLParamSingleton<DERIVED_CLASS>;                            \ +    DERIVED_CLASS(__VA_ARGS__) +  #endif diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 680fbf548f..9dea876114 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -583,39 +583,29 @@ static void bilinear_scale(const U8 *src, U32 srcW, U32 srcH, U32 srcCh, U32 src  // LLImage  //--------------------------------------------------------------------------- -//static -std::string LLImage::sLastErrorMessage; -LLMutex* LLImage::sMutex = NULL; -bool LLImage::sUseNewByteRange = false; -S32  LLImage::sMinimalReverseByteRangePercent = 75; - -//static -void LLImage::initClass(bool use_new_byte_range, S32 minimal_reverse_byte_range_percent) +LLImage::LLImage(bool use_new_byte_range, S32 minimal_reverse_byte_range_percent)  { -	sUseNewByteRange = use_new_byte_range; -    sMinimalReverseByteRangePercent = minimal_reverse_byte_range_percent; -	sMutex = new LLMutex(); +    mMutex = new LLMutex(); +    mUseNewByteRange = use_new_byte_range; +    mMinimalReverseByteRangePercent = minimal_reverse_byte_range_percent;  } -//static -void LLImage::cleanupClass() +LLImage::~LLImage()  { -	delete sMutex; -	sMutex = NULL; +    delete mMutex; +    mMutex = NULL;  } -//static -const std::string& LLImage::getLastError() +const std::string& LLImage::getLastErrorMessage()  {  	static const std::string noerr("No Error"); -	return sLastErrorMessage.empty() ? noerr : sLastErrorMessage; +	return mLastErrorMessage.empty() ? noerr : mLastErrorMessage;  } -//static -void LLImage::setLastError(const std::string& message) +void LLImage::setLastErrorMessage(const std::string& message)  { -	LLMutexLock m(sMutex); -	sLastErrorMessage = message; +	LLMutexLock m(mMutex); +	mLastErrorMessage = message;  }  //--------------------------------------------------------------------------- diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 8ec49d3f0f..e5526ba9c0 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -30,6 +30,7 @@  #include "lluuid.h"  #include "llstring.h"  #include "llpointer.h" +#include "llsingleton.h"  #include "lltrace.h"  const S32 MIN_IMAGE_MIP =  2; // 4x4, only used for expand/contract power of 2 @@ -88,23 +89,25 @@ typedef enum e_image_codec  //============================================================================  // library initialization class -class LLImage +class LLImage : public LLParamSingleton<LLImage>  { +	LLPARAMSINGLETON(LLImage, bool use_new_byte_range = false, S32 minimal_reverse_byte_range_percent = 75); +	~LLImage();  public: -	static void initClass(bool use_new_byte_range = false, S32 minimal_reverse_byte_range_percent = 75); -	static void cleanupClass(); -	static const std::string& getLastError(); -	static void setLastError(const std::string& message); -	 -	static bool useNewByteRange() { return sUseNewByteRange; } -    static S32  getReverseByteRangePercent() { return sMinimalReverseByteRangePercent; } -	 -protected: -	static LLMutex* sMutex; -	static std::string sLastErrorMessage; -	static bool sUseNewByteRange; -    static S32  sMinimalReverseByteRangePercent; +	const std::string& getLastErrorMessage(); +	static const std::string& getLastError() { return getInstance()->getLastErrorMessage(); }; +	void setLastErrorMessage(const std::string& message); +	static void setLastError(const std::string& message) { getInstance()->setLastErrorMessage(message); } + +	bool useNewByteRange() { return mUseNewByteRange; } +	S32  getReverseByteRangePercent() { return mMinimalReverseByteRangePercent; } + +private: +	LLMutex* mMutex; +	std::string mLastErrorMessage; +	bool mUseNewByteRange; +	S32  mMinimalReverseByteRangePercent;  };  //============================================================================ diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 4bff21610f..71cab0554d 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -281,7 +281,7 @@ S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 r  	S32 bytes;  	S32 new_bytes = (S32) (sqrt((F32)(w*h))*(F32)(comp)*rate*1000.f/layer_factor);  	S32 old_bytes = (S32)((F32)(w*h*comp)*rate); -	bytes = (LLImage::useNewByteRange() && (new_bytes < old_bytes) ? new_bytes : old_bytes); +	bytes = (LLImage::getInstance()->useNewByteRange() && (new_bytes < old_bytes) ? new_bytes : old_bytes);  	bytes = llmax(bytes, calcHeaderSizeJ2C());  	return bytes;  } @@ -322,7 +322,7 @@ S32 LLImageJ2C::calcDiscardLevelBytes(S32 bytes)  	{  		S32 bytes_needed = calcDataSize(discard_level);  		// Use TextureReverseByteRange percent (see settings.xml) of the optimal size to qualify as correct rendering for the given discard level -		if (bytes >= (bytes_needed*LLImage::getReverseByteRangePercent()/100)) +		if (bytes >= (bytes_needed*LLImage::getInstance()->getReverseByteRangePercent()/100))  		{  			break;  		} diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 0435c3d398..cb4655cd87 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2040,7 +2040,6 @@ bool LLAppViewer::cleanup()  	LLUIImageList::getInstance()->cleanUp();  	// This should eventually be done in LLAppViewer -	SUBSYSTEM_CLEANUP(LLImage);  	SUBSYSTEM_CLEANUP(LLVFSThread);  	SUBSYSTEM_CLEANUP(LLLFSThread); @@ -2148,7 +2147,7 @@ bool LLAppViewer::initThreads()  {  	static const bool enable_threads = true; -	LLImage::initClass(gSavedSettings.getBOOL("TextureNewByteRange"),gSavedSettings.getS32("TextureReverseByteRange")); +	LLImage::initParamSingleton(gSavedSettings.getBOOL("TextureNewByteRange"),gSavedSettings.getS32("TextureReverseByteRange"));  	LLVFSThread::initClass(enable_threads && false);  	LLLFSThread::initClass(enable_threads && false); diff --git a/indra/newview/llconversationlog.h b/indra/newview/llconversationlog.h index 035cbcb945..38247f8eff 100644 --- a/indra/newview/llconversationlog.h +++ b/indra/newview/llconversationlog.h @@ -107,11 +107,10 @@ private:   * To distinguish two conversations with the same sessionID it's also needed to compare their creation date.   */ -class LLConversationLog : public LLSingleton<LLConversationLog>, LLIMSessionObserver +class LLConversationLog : public LLParamSingleton<LLConversationLog>, LLIMSessionObserver  { -	LLSINGLETON(LLConversationLog); +	LLPARAMSINGLETON(LLConversationLog);  public: -  	void removeConversation(const LLConversation& conversation);  	/** diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 7f9f0da315..82e1d6be4a 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1289,7 +1289,7 @@ bool idle_startup()  		display_startup();  		LLStartUp::setStartupState( STATE_MULTIMEDIA_INIT ); -		LLConversationLog::getInstance(); +		LLConversationLog::initParamSingleton();  		return FALSE;  	} | 
