summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
authorAaron Brashears <aaronb@lindenlab.com>2009-05-18 23:38:35 +0000
committerAaron Brashears <aaronb@lindenlab.com>2009-05-18 23:38:35 +0000
commit6df2755ba6b24d0cefd52ce175b0212dd46c9b10 (patch)
tree833bc29e7bd5438eb89f34119ae157efe6258b2c /indra/llcommon
parent0257214763203708e8e29d09346e777b95cdfce6 (diff)
Result of svn merge -r119432:120464 svn+ssh://svn/svn/linden/branches/http_database/merge-03 into trunk. QAR-1462
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/CMakeLists.txt2
-rw-r--r--indra/llcommon/llapp.cpp32
-rw-r--r--indra/llcommon/llapp.h45
-rw-r--r--indra/llcommon/llerror.cpp7
-rw-r--r--indra/llcommon/llliveappconfig.cpp32
-rw-r--r--indra/llcommon/llliveappconfig.h34
-rw-r--r--indra/llcommon/lllivefile.cpp35
-rw-r--r--indra/llcommon/lllivefile.h50
-rw-r--r--indra/llcommon/llstat.cpp11
-rw-r--r--indra/llcommon/llstring.h46
-rw-r--r--indra/llcommon/lluri.cpp5
-rw-r--r--indra/llcommon/lluri.h17
12 files changed, 240 insertions, 76 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 3f14be6e18..d6a9e10707 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -32,7 +32,6 @@ set(llcommon_SOURCE_FILES
llformat.cpp
llframetimer.cpp
llheartbeat.cpp
- llindraconfigfile.cpp
llliveappconfig.cpp
lllivefile.cpp
lllog.cpp
@@ -118,7 +117,6 @@ set(llcommon_HEADER_FILES
llheartbeat.h
llhttpstatuscodes.h
llindexedqueue.h
- llindraconfigfile.h
llkeythrottle.h
lllinkedqueue.h
llliveappconfig.h
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index 199315f34e..968b92d1e7 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -38,7 +38,9 @@
#include "llerrorcontrol.h"
#include "llerrorthread.h"
#include "llframetimer.h"
+#include "lllivefile.h"
#include "llmemory.h"
+#include "llstl.h" // for DeletePointer()
#include "lltimer.h"
//
@@ -91,7 +93,6 @@ LLAppChildCallback LLApp::sDefaultChildCallback = NULL;
LLApp::LLApp() : mThreadErrorp(NULL)
{
commonCtor();
- startErrorThread();
}
void LLApp::commonCtor()
@@ -106,9 +107,6 @@ void LLApp::commonCtor()
sSigChildCount = new LLAtomicU32(0);
#endif
- // Setup error handling
- setupErrorHandling();
-
// initialize the options structure. We need to make this an array
// because the structured data will not auto-allocate if we
// reference an invalid location with the [] operator.
@@ -141,6 +139,11 @@ LLApp::~LLApp()
delete sSigChildCount;
sSigChildCount = NULL;
#endif
+
+ // reclaim live file memory
+ std::for_each(mLiveFiles.begin(), mLiveFiles.end(), DeletePointer());
+ mLiveFiles.clear();
+
setStopped();
// HACK: wait for the error thread to clean itself
ms_sleep(20);
@@ -214,6 +217,15 @@ bool LLApp::parseCommandOptions(int argc, char** argv)
return true;
}
+
+void LLApp::manageLiveFile(LLLiveFile* livefile)
+{
+ if(!livefile) return;
+ livefile->checkAndReload();
+ livefile->addToEventTimer();
+ mLiveFiles.push_back(livefile);
+}
+
bool LLApp::setOptionData(OptionPriority level, LLSD data)
{
if((level < 0)
@@ -275,6 +287,7 @@ void LLApp::setupErrorHandling()
#endif
+ startErrorThread();
}
void LLApp::startErrorThread()
@@ -283,10 +296,13 @@ void LLApp::startErrorThread()
// Start the error handling thread, which is responsible for taking action
// when the app goes into the APP_STATUS_ERROR state
//
- llinfos << "Starting error thread" << llendl;
- mThreadErrorp = new LLErrorThread();
- mThreadErrorp->setUserData((void *) this);
- mThreadErrorp->start();
+ if(!mThreadErrorp)
+ {
+ llinfos << "Starting error thread" << llendl;
+ mThreadErrorp = new LLErrorThread();
+ mThreadErrorp->setUserData((void *) this);
+ mThreadErrorp->start();
+ }
}
void LLApp::setErrorHandler(LLAppErrorHandler handler)
diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h
index f8a593c33d..cc60ba0b80 100644
--- a/indra/llcommon/llapp.h
+++ b/indra/llcommon/llapp.h
@@ -40,8 +40,7 @@
// Forward declarations
class LLErrorThread;
-class LLApp;
-
+class LLLiveFile;
typedef void (*LLAppErrorHandler)();
typedef void (*LLAppChildCallback)(int pid, bool exited, int status);
@@ -128,6 +127,19 @@ public:
bool parseCommandOptions(int argc, char** argv);
/**
+ * @brief Keep track of live files automatically.
+ *
+ * *TODO: it currently uses the <code>addToEventTimer()</code> API
+ * instead of the runner. I should probalby use the runner.
+ *
+ * *NOTE: DO NOT add the livefile instance to any kind of check loop.
+ *
+ * @param livefile A valid instance of an LLLiveFile. This LLApp
+ * instance will delete the livefile instance.
+ */
+ void manageLiveFile(LLLiveFile* livefile);
+
+ /**
* @brief Set the options at the specified priority.
*
* This function completely replaces the options at the priority
@@ -194,11 +206,26 @@ public:
#endif
static int getPid();
- //
- // Error handling methods
- //
+ /** @name Error handling methods */
+ //@{
+ /**
+ * @brief Do our generic platform-specific error-handling setup --
+ * signals on unix, structured exceptions on windows.
+ *
+ * DO call this method if your app will either spawn children or be
+ * spawned by a launcher.
+ * Call just after app object construction.
+ * (Otherwise your app will crash when getting signals,
+ * and will not core dump.)
+ *
+ * DO NOT call this method if your application has specialized
+ * error handling code.
+ */
+ void setupErrorHandling();
+
void setErrorHandler(LLAppErrorHandler handler);
void setSyncErrorHandler(LLAppErrorHandler handler);
+ //@}
#if !LL_WINDOWS
//
@@ -214,8 +241,9 @@ public:
void setDefaultChildCallback(LLAppChildCallback callback);
// Fork and do the proper signal handling/error handling mojo
- // WARNING: You need to make sure your signal handling callback is correct after
- // you fork, because not all threads are duplicated when you fork!
+ // *NOTE: You need to make sure your signal handling callback is
+ // correct after you fork, because not all threads are duplicated
+ // when you fork!
pid_t fork();
#endif
@@ -255,7 +283,6 @@ protected:
private:
void startErrorThread();
- void setupErrorHandling(); // Do platform-specific error-handling setup (signals, structured exceptions)
static void runErrorHandler(); // run shortly after we detect an error, ran in the relatively robust context of the LLErrorThread - preferred.
static void runSyncErrorHandler(); // run IMMEDIATELY when we get an error, ran in the context of the faulting thread.
@@ -278,6 +305,8 @@ private:
// The application options.
LLSD mOptions;
+ // The live files for this application
+ std::vector<LLLiveFile*> mLiveFiles;
//@}
private:
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index e8c95d0a76..d671decccb 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -289,7 +289,7 @@ namespace
public:
static LogControlFile& fromDirectory(const std::string& dir);
- virtual void loadFile();
+ virtual bool loadFile();
private:
LogControlFile(const std::string &filename)
@@ -317,7 +317,7 @@ namespace
// NB: This instance is never freed
}
- void LogControlFile::loadFile()
+ bool LogControlFile::loadFile()
{
LLSD configuration;
@@ -333,12 +333,13 @@ namespace
llwarns << filename() << " missing, ill-formed,"
" or simply undefined; not changing configuration"
<< llendl;
- return;
+ return false;
}
}
LLError::configure(configuration);
llinfos << "logging reconfigured from " << filename() << llendl;
+ return true;
}
diff --git a/indra/llcommon/llliveappconfig.cpp b/indra/llcommon/llliveappconfig.cpp
index e1bfc11a03..75bdfee8b7 100644
--- a/indra/llcommon/llliveappconfig.cpp
+++ b/indra/llcommon/llliveappconfig.cpp
@@ -38,9 +38,12 @@
#include "llsd.h"
#include "llsdserialize.h"
-LLLiveAppConfig::LLLiveAppConfig(LLApp* app, const std::string& filename, F32 refresh_period)
-: LLLiveFile(filename, refresh_period),
- mApp(app)
+LLLiveAppConfig::LLLiveAppConfig(
+ const std::string& filename,
+ F32 refresh_period,
+ LLApp::OptionPriority priority) :
+ LLLiveFile(filename, refresh_period),
+ mPriority(priority)
{ }
@@ -48,7 +51,7 @@ LLLiveAppConfig::~LLLiveAppConfig()
{ }
// virtual
-void LLLiveAppConfig::loadFile()
+bool LLLiveAppConfig::loadFile()
{
llinfos << "LLLiveAppConfig::loadFile(): reading from "
<< filename() << llendl;
@@ -59,12 +62,25 @@ void LLLiveAppConfig::loadFile()
LLSDSerialize::fromXML(config, file);
if(!config.isMap())
{
- llinfos << "LLDataserverConfig::loadFile(): not an map!"
+ llwarns << "Live app config not an map in " << filename()
<< " Ignoring the data." << llendl;
- return;
+ return false;
}
file.close();
}
- mApp->setOptionData(
- LLApp::PRIORITY_SPECIFIC_CONFIGURATION, config);
+ else
+ {
+ llinfos << "Live file " << filename() << " does not exit." << llendl;
+ }
+ // *NOTE: we do not handle the else case here because we would not
+ // have attempted to load the file unless LLLiveFile had
+ // determined there was a reason to load it. This only happens
+ // when either the file has been updated or it is either suddenly
+ // in existence or has passed out of existence. Therefore, we want
+ // to set the config to an empty config, and return that it
+ // changed.
+
+ LLApp* app = LLApp::instance();
+ if(app) app->setOptionData(mPriority, config);
+ return true;
}
diff --git a/indra/llcommon/llliveappconfig.h b/indra/llcommon/llliveappconfig.h
index 55d84a4778..a6ece6e8b3 100644
--- a/indra/llcommon/llliveappconfig.h
+++ b/indra/llcommon/llliveappconfig.h
@@ -33,25 +33,43 @@
#ifndef LLLIVEAPPCONFIG_H
#define LLLIVEAPPCONFIG_H
+#include "llapp.h"
#include "lllivefile.h"
-class LLApp;
+/**
+ * @class LLLiveAppConfig
+ * @see LLLiveFile
+ *
+ * To use this, instantiate a LLLiveAppConfig object inside your main
+ * loop. The traditional name for it is live_config. Be sure to call
+ * <code>live_config.checkAndReload()</code> periodically.
+ */
class LLLiveAppConfig : public LLLiveFile
{
public:
- // To use this, instantiate a LLLiveAppConfig object inside your main loop.
- // The traditional name for it is live_config.
- // Be sure to call live_config.checkAndReload() periodically.
- LLLiveAppConfig(LLApp* app, const std::string& filename, F32 refresh_period);
- ~LLLiveAppConfig();
+ /**
+ * @brief Constructor
+ *
+ * @param filename. The name of the file for periodically checking
+ * configuration.
+ * @param refresh_period How often the internal timer should
+ * bother checking the filesystem.
+ * @param The application priority level of that configuration file.
+ */
+ LLLiveAppConfig(
+ const std::string& filename,
+ F32 refresh_period,
+ LLApp::OptionPriority priority);
+
+ ~LLLiveAppConfig(); ///< Destructor
protected:
- /*virtual*/ void loadFile();
+ /*virtual*/ bool loadFile();
private:
- LLApp* mApp;
+ LLApp::OptionPriority mPriority;
};
#endif
diff --git a/indra/llcommon/lllivefile.cpp b/indra/llcommon/lllivefile.cpp
index b6f458cb3e..effda6c49c 100644
--- a/indra/llcommon/lllivefile.cpp
+++ b/indra/llcommon/lllivefile.cpp
@@ -35,14 +35,17 @@
#include "llframetimer.h"
#include "lltimer.h"
+const F32 DEFAULT_CONFIG_FILE_REFRESH = 5.0f;
+
+
class LLLiveFile::Impl
{
public:
- Impl(const std::string &filename, const F32 refresh_period);
+ Impl(const std::string& filename, const F32 refresh_period);
~Impl();
bool check();
-
+ void changed();
bool mForceCheck;
F32 mRefreshPeriod;
@@ -50,16 +53,19 @@ public:
std::string mFilename;
time_t mLastModTime;
+ time_t mLastStatTime;
bool mLastExists;
LLEventTimer* mEventTimer;
};
-LLLiveFile::Impl::Impl(const std::string &filename, const F32 refresh_period)
- : mForceCheck(true),
+LLLiveFile::Impl::Impl(const std::string& filename, const F32 refresh_period)
+ :
+ mForceCheck(true),
mRefreshPeriod(refresh_period),
mFilename(filename),
mLastModTime(0),
+ mLastStatTime(0),
mLastExists(false),
mEventTimer(NULL)
{
@@ -70,7 +76,7 @@ LLLiveFile::Impl::~Impl()
delete mEventTimer;
}
-LLLiveFile::LLLiveFile(const std::string &filename, const F32 refresh_period)
+LLLiveFile::LLLiveFile(const std::string& filename, const F32 refresh_period)
: impl(* new Impl(filename, refresh_period))
{
}
@@ -121,17 +127,30 @@ bool LLLiveFile::Impl::check()
// We want to read the file. Update status info for the file.
mLastExists = true;
- mLastModTime = stat_data.st_mtime;
-
+ mLastStatTime = stat_data.st_mtime;
return true;
}
+void LLLiveFile::Impl::changed()
+{
+ // we wanted to read this file, and we were successful.
+ mLastModTime = mLastStatTime;
+}
+
bool LLLiveFile::checkAndReload()
{
bool changed = impl.check();
if (changed)
{
- loadFile();
+ if(loadFile())
+ {
+ impl.changed();
+ this->changed();
+ }
+ else
+ {
+ changed = false;
+ }
}
return changed;
}
diff --git a/indra/llcommon/lllivefile.h b/indra/llcommon/lllivefile.h
index a3a9cf49ab..89b5d95e44 100644
--- a/indra/llcommon/lllivefile.h
+++ b/indra/llcommon/lllivefile.h
@@ -33,29 +33,65 @@
#ifndef LL_LLLIVEFILE_H
#define LL_LLLIVEFILE_H
-const F32 configFileRefreshRate = 5.0; // seconds
+extern const F32 DEFAULT_CONFIG_FILE_REFRESH;
class LLLiveFile
{
public:
- LLLiveFile(const std::string &filename, const F32 refresh_period = 5.f);
+ LLLiveFile(const std::string& filename, const F32 refresh_period = 5.f);
virtual ~LLLiveFile();
+ /**
+ * @brief Check to see if this live file should reload.
+ *
+ * Call this before using anything that was read & cached
+ * from the file.
+ *
+ * This method calls the <code>loadFile()</code> method if
+ * any of:
+ * file has a new modify time since the last check
+ * file used to exist and now does not
+ * file used to not exist but now does
+ * @return Returns true if the file was reloaded.
+ */
bool checkAndReload();
- // Returns true if the file changed in any way
- // Call this before using anything that was read & cached from the file
+
std::string filename() const;
+ /**
+ * @brief Add this live file to an automated recheck.
+ *
+ * Normally, just calling checkAndReload() is enough. In some
+ * cases though, you may need to let the live file periodically
+ * check itself.
+ */
void addToEventTimer();
- // Normally, just calling checkAndReload() is enough. In some cases
- // though, you may need to let the live file periodically check itself.
void setRefreshPeriod(F32 seconds);
protected:
- virtual void loadFile() = 0; // Implement this to load your file if it changed
+ /**
+ * @breif Implement this to load your file if it changed.
+ *
+ * This method is called automatically by <code>checkAndReload()</code>,
+ * so though you must implement this in derived classes, you do
+ * not need to call it manually.
+ * @return Returns true if the file was successfully loaded.
+ */
+ virtual bool loadFile() = 0;
+
+ /**
+ * @brief Implement this method if you want to get a change callback.
+ *
+ * This virtual function will be called automatically at the end
+ * of <code>checkAndReload()</code> if a new configuration was
+ * loaded. This does not track differences between the current and
+ * newly loaded file, so any successful load event will trigger a
+ * <code>changed()</code> callback. Default is to do nothing.
+ */
+ virtual void changed() {}
private:
class Impl;
diff --git a/indra/llcommon/llstat.cpp b/indra/llcommon/llstat.cpp
index e411a1c798..291b019616 100644
--- a/indra/llcommon/llstat.cpp
+++ b/indra/llcommon/llstat.cpp
@@ -62,7 +62,7 @@ public:
static std::string filename();
protected:
- /* virtual */ void loadFile();
+ /* virtual */ bool loadFile();
public:
void init(LLPerfStats* statsp);
@@ -94,12 +94,12 @@ LLStatsConfigFile& LLStatsConfigFile::instance()
/* virtual */
// Load and parse the stats configuration file
-void LLStatsConfigFile::loadFile()
+bool LLStatsConfigFile::loadFile()
{
if (!mStatsp)
{
llwarns << "Tries to load performance configure file without initializing LPerfStats" << llendl;
- return;
+ return false;
}
mChanged = true;
@@ -113,7 +113,7 @@ void LLStatsConfigFile::loadFile()
{
llinfos << "Performance statistics configuration file ill-formed, not recording statistics" << llendl;
mStatsp->setReportPerformanceDuration( 0.f );
- return;
+ return false;
}
}
else
@@ -123,7 +123,7 @@ void LLStatsConfigFile::loadFile()
llinfos << "Performance statistics configuration file deleted, not recording statistics" << llendl;
mStatsp->setReportPerformanceDuration( 0.f );
}
- return;
+ return true;
}
}
@@ -159,6 +159,7 @@ void LLStatsConfigFile::loadFile()
{
llinfos << "Performance stats recording turned off" << llendl;
}
+ return true;
}
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 99a9b9e269..6ba665b8d2 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -228,7 +228,25 @@ public:
// True if this is the head of s.
static BOOL isHead( const std::basic_string<T>& string, const T* s );
-
+
+ /**
+ * @brief Returns true if string starts with substr
+ *
+ * If etither string or substr are empty, this method returns false.
+ */
+ static bool startsWith(
+ const std::basic_string<T>& string,
+ const std::basic_string<T>& substr);
+
+ /**
+ * @brief Returns true if string ends in substr
+ *
+ * If etither string or substr are empty, this method returns false.
+ */
+ static bool endsWith(
+ const std::basic_string<T>& string,
+ const std::basic_string<T>& substr);
+
static void addCRLF(std::basic_string<T>& string);
static void removeCRLF(std::basic_string<T>& string);
@@ -335,7 +353,7 @@ public:
* This function works on bytes rather than glyphs, so this will
* incorrectly truncate non-single byte strings.
* Use utf8str_truncate() for utf8 strings
- * @return a copy of in string minus the trailing count characters.
+ * @return a copy of in string minus the trailing count bytes.
*/
inline std::string chop_tail_copy(
const std::string& in,
@@ -1065,6 +1083,30 @@ BOOL LLStringUtilBase<T>::isHead( const std::basic_string<T>& string, const T* s
}
}
+// static
+template<class T>
+bool LLStringUtilBase<T>::startsWith(
+ const std::basic_string<T>& string,
+ const std::basic_string<T>& substr)
+{
+ if(string.empty() || (substr.empty())) return false;
+ if(0 == string.find(substr)) return true;
+ return false;
+}
+
+// static
+template<class T>
+bool LLStringUtilBase<T>::endsWith(
+ const std::basic_string<T>& string,
+ const std::basic_string<T>& substr)
+{
+ if(string.empty() || (substr.empty())) return false;
+ std::string::size_type idx = string.rfind(substr);
+ if(std::string::npos == idx) return false;
+ return (idx == (string.size() - substr.size()));
+}
+
+
template<class T>
BOOL LLStringUtilBase<T>::convertToBOOL(const std::basic_string<T>& string, BOOL& value)
{
diff --git a/indra/llcommon/lluri.cpp b/indra/llcommon/lluri.cpp
index 3dbc837875..f6e8f01f0e 100644
--- a/indra/llcommon/lluri.cpp
+++ b/indra/llcommon/lluri.cpp
@@ -162,11 +162,10 @@ namespace
{ return LLURI::escape(s, unreserved() + ":@!$'()*+,="); } // sub_delims - "&;" + ":@"
}
-// *TODO: Consider using curl. After http textures gets merged everywhere.
-// static
+//static
std::string LLURI::escape(const std::string& str)
{
- static std::string default_allowed(unreserved() + ":@!$'()*+,=/?&#;");
+ static std::string default_allowed = unreserved();
static bool initialized = false;
if(!initialized)
{
diff --git a/indra/llcommon/lluri.h b/indra/llcommon/lluri.h
index 156d80b97e..8e46e2e89e 100644
--- a/indra/llcommon/lluri.h
+++ b/indra/llcommon/lluri.h
@@ -127,27 +127,16 @@ public:
/** @name Escaping Utilities */
//@{
/**
- * @brief Escape a raw url with a reasonable set of allowed characters.
- *
- * The default set was chosen to match HTTP urls and general
- * guidelines for naming resources. Passing in a raw url does not
- * produce well defined results because you really need to know
- * which segments are path parts because path parts are supposed
- * to be escaped individually. The default set chosen is:
+ * @brief Escape the string passed except for unreserved
*
* ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
* 0123456789
* -._~
- * :@!$'()*+,=/?&#;
*
- * *NOTE: This API is basically broken because it does not
- * allow you to specify significant path characters. For example,
- * if the filename actually contained a /, then you cannot use
- * this function to generate the serialized url for that
- * resource.
+ * @see http://www.ietf.org/rfc/rfc1738.txt
*
* @param str The raw URI to escape.
- * @return Returns the escaped uri or an empty string.
+ * @return Returns the rfc 1738 escaped uri or an empty string.
*/
static std::string escape(const std::string& str);