summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/llcommon/llsingleton.h205
-rw-r--r--indra/llimage/llimage.cpp34
-rw-r--r--indra/llimage/llimage.h31
-rw-r--r--indra/llimage/llimagej2c.cpp4
-rw-r--r--indra/newview/llappviewer.cpp3
-rw-r--r--indra/newview/llconversationlog.h5
-rw-r--r--indra/newview/llstartup.cpp2
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;
}