diff options
-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; } |