summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
authorBrad Payne (Vir Linden) <vir@lindenlab.com>2010-12-02 17:06:08 -0500
committerBrad Payne (Vir Linden) <vir@lindenlab.com>2010-12-02 17:06:08 -0500
commitd529abbfe62c879e4c0e6397e55cc80030b735b8 (patch)
tree192c9f41686a8f6c32626b6b514978ae29a02b02 /indra/llcommon
parentf0bca5f0683db1540b640191ab2780224aceb800 (diff)
parent680328dd78e1d31a2f8836919a0f6140a76af5f4 (diff)
merge
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/CMakeLists.txt4
-rw-r--r--indra/llcommon/indra_constants.h11
-rw-r--r--[-rwxr-xr-x]indra/llcommon/llfasttimer_class.cpp1
-rw-r--r--indra/llcommon/llfasttimer_class.h1
-rw-r--r--indra/llcommon/llfile.cpp5
-rw-r--r--indra/llcommon/llmetricperformancetester.cpp254
-rw-r--r--indra/llcommon/llmetricperformancetester.h206
-rw-r--r--indra/llcommon/llprocesslauncher.cpp5
-rw-r--r--indra/llcommon/llprocesslauncher.h2
-rw-r--r--indra/llcommon/llthread.cpp30
-rw-r--r--indra/llcommon/llthreadsafequeue.cpp109
-rw-r--r--indra/llcommon/llthreadsafequeue.h205
-rw-r--r--indra/llcommon/llversionviewer.h2
13 files changed, 824 insertions, 11 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 7bad780dd8..9342a22d46 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -70,6 +70,7 @@ set(llcommon_SOURCE_FILES
llmemorystream.cpp
llmemtype.cpp
llmetrics.cpp
+ llmetricperformancetester.cpp
llmortician.cpp
lloptioninterface.cpp
llptrto.cpp
@@ -92,6 +93,7 @@ set(llcommon_SOURCE_FILES
llstringtable.cpp
llsys.cpp
llthread.cpp
+ llthreadsafequeue.cpp
lltimer.cpp
lluri.cpp
lluuid.cpp
@@ -186,6 +188,7 @@ set(llcommon_HEADER_FILES
llmemorystream.h
llmemtype.h
llmetrics.h
+ llmetricperformancetester.h
llmortician.h
llnametable.h
lloptioninterface.h
@@ -223,6 +226,7 @@ set(llcommon_HEADER_FILES
llstringtable.h
llsys.h
llthread.h
+ llthreadsafequeue.h
lltimer.h
lltreeiterators.h
lluri.h
diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h
index b0618bfe59..95cb606240 100644
--- a/indra/llcommon/indra_constants.h
+++ b/indra/llcommon/indra_constants.h
@@ -245,9 +245,6 @@ const U8 SIM_ACCESS_ADULT = 42; // Seriously Adult Only
const U8 SIM_ACCESS_DOWN = 254;
const U8 SIM_ACCESS_MAX = SIM_ACCESS_ADULT;
-// group constants
-const S32 MAX_AGENT_GROUPS = 25;
-
// attachment constants
const S32 MAX_AGENT_ATTACHMENTS = 38;
const U8 ATTACHMENT_ADD = 0x80;
@@ -300,6 +297,14 @@ const U32 START_LOCATION_ID_COUNT = 6;
// group constants
const U32 GROUP_MIN_SIZE = 2;
+// gMaxAgentGroups is now sent by login.cgi, which
+// looks it up from globals.xml.
+//
+// For now we need an old default value however,
+// so the viewer can be deployed ahead of login.cgi.
+//
+const S32 DEFAULT_MAX_AGENT_GROUPS = 25;
+
// radius within which a chat message is fully audible
const F32 CHAT_WHISPER_RADIUS = 10.f;
const F32 CHAT_NORMAL_RADIUS = 20.f;
diff --git a/indra/llcommon/llfasttimer_class.cpp b/indra/llcommon/llfasttimer_class.cpp
index 558a4dc005..c084166ccc 100755..100644
--- a/indra/llcommon/llfasttimer_class.cpp
+++ b/indra/llcommon/llfasttimer_class.cpp
@@ -59,6 +59,7 @@ bool LLFastTimer::sPauseHistory = 0;
bool LLFastTimer::sResetHistory = 0;
LLFastTimer::CurTimerData LLFastTimer::sCurTimerData;
BOOL LLFastTimer::sLog = FALSE;
+std::string LLFastTimer::sLogName = "";
BOOL LLFastTimer::sMetricLog = FALSE;
LLMutex* LLFastTimer::sLogLock = NULL;
std::queue<LLSD> LLFastTimer::sLogQueue;
diff --git a/indra/llcommon/llfasttimer_class.h b/indra/llcommon/llfasttimer_class.h
index 8dd686dc38..2a645315c9 100644
--- a/indra/llcommon/llfasttimer_class.h
+++ b/indra/llcommon/llfasttimer_class.h
@@ -219,6 +219,7 @@ public:
static std::queue<LLSD> sLogQueue;
static BOOL sLog;
static BOOL sMetricLog;
+ static std::string sLogName;
static bool sPauseHistory;
static bool sResetHistory;
static U64 sTimerCycles;
diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp
index 289ce0bc2c..8f02391e75 100644
--- a/indra/llcommon/llfile.cpp
+++ b/indra/llcommon/llfile.cpp
@@ -318,7 +318,12 @@ void llofstream::close()
if(is_open())
{
if (_Filebuffer->close() == 0)
+ {
_Myios::setstate(ios_base::failbit); /*Flawfinder: ignore*/
+ }
+ delete _Filebuffer;
+ _Filebuffer = NULL;
+ _ShouldClose = false;
}
}
diff --git a/indra/llcommon/llmetricperformancetester.cpp b/indra/llcommon/llmetricperformancetester.cpp
new file mode 100644
index 0000000000..5fa3a5ea07
--- /dev/null
+++ b/indra/llcommon/llmetricperformancetester.cpp
@@ -0,0 +1,254 @@
+/**
+ * @file llmetricperformancetester.cpp
+ * @brief LLMetricPerformanceTesterBasic and LLMetricPerformanceTesterWithSession classes implementation
+ *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "indra_constants.h"
+#include "llerror.h"
+#include "llsdserialize.h"
+#include "llstat.h"
+#include "lltreeiterators.h"
+#include "llmetricperformancetester.h"
+
+//----------------------------------------------------------------------------------------------
+// LLMetricPerformanceTesterBasic : static methods and testers management
+//----------------------------------------------------------------------------------------------
+
+LLMetricPerformanceTesterBasic::name_tester_map_t LLMetricPerformanceTesterBasic::sTesterMap ;
+
+/*static*/
+void LLMetricPerformanceTesterBasic::cleanClass()
+{
+ for (name_tester_map_t::iterator iter = sTesterMap.begin() ; iter != sTesterMap.end() ; ++iter)
+ {
+ delete iter->second ;
+ }
+ sTesterMap.clear() ;
+}
+
+/*static*/
+BOOL LLMetricPerformanceTesterBasic::addTester(LLMetricPerformanceTesterBasic* tester)
+{
+ llassert_always(tester != NULL);
+ std::string name = tester->getTesterName() ;
+ if (getTester(name))
+ {
+ llerrs << "Tester name is already used by some other tester : " << name << llendl ;
+ return FALSE;
+ }
+
+ sTesterMap.insert(std::make_pair(name, tester));
+ return TRUE;
+}
+
+/*static*/
+LLMetricPerformanceTesterBasic* LLMetricPerformanceTesterBasic::getTester(std::string name)
+{
+ // Check for the requested metric name
+ name_tester_map_t::iterator found_it = sTesterMap.find(name) ;
+ if (found_it != sTesterMap.end())
+ {
+ return found_it->second ;
+ }
+ return NULL ;
+}
+
+/*static*/
+// Return TRUE if this metric is requested or if the general default "catch all" metric is requested
+BOOL LLMetricPerformanceTesterBasic::isMetricLogRequested(std::string name)
+{
+ return (LLFastTimer::sMetricLog && ((LLFastTimer::sLogName == name) || (LLFastTimer::sLogName == DEFAULT_METRIC_NAME)));
+}
+
+
+//----------------------------------------------------------------------------------------------
+// LLMetricPerformanceTesterBasic : Tester instance methods
+//----------------------------------------------------------------------------------------------
+
+LLMetricPerformanceTesterBasic::LLMetricPerformanceTesterBasic(std::string name) :
+ mName(name),
+ mCount(0)
+{
+ if (mName == std::string())
+ {
+ llerrs << "LLMetricPerformanceTesterBasic construction invalid : Empty name passed to constructor" << llendl ;
+ }
+
+ mValidInstance = LLMetricPerformanceTesterBasic::addTester(this) ;
+}
+
+LLMetricPerformanceTesterBasic::~LLMetricPerformanceTesterBasic()
+{
+}
+
+void LLMetricPerformanceTesterBasic::preOutputTestResults(LLSD* sd)
+{
+ incrementCurrentCount() ;
+ (*sd)[getCurrentLabelName()]["Name"] = mName ;
+}
+
+void LLMetricPerformanceTesterBasic::postOutputTestResults(LLSD* sd)
+{
+ LLMutexLock lock(LLFastTimer::sLogLock);
+ LLFastTimer::sLogQueue.push((*sd));
+}
+
+void LLMetricPerformanceTesterBasic::outputTestResults()
+{
+ LLSD sd;
+
+ preOutputTestResults(&sd) ;
+ outputTestRecord(&sd) ;
+ postOutputTestResults(&sd) ;
+}
+
+void LLMetricPerformanceTesterBasic::addMetric(std::string str)
+{
+ mMetricStrings.push_back(str) ;
+}
+
+/*virtual*/
+void LLMetricPerformanceTesterBasic::analyzePerformance(std::ofstream* os, LLSD* base, LLSD* current)
+{
+ resetCurrentCount() ;
+
+ std::string current_label = getCurrentLabelName();
+ BOOL in_base = (*base).has(current_label) ;
+ BOOL in_current = (*current).has(current_label) ;
+
+ while(in_base || in_current)
+ {
+ LLSD::String label = current_label ;
+
+ if(in_base && in_current)
+ {
+ *os << llformat("%s\n", label.c_str()) ;
+
+ for(U32 index = 0 ; index < mMetricStrings.size() ; index++)
+ {
+ switch((*current)[label][ mMetricStrings[index] ].type())
+ {
+ case LLSD::TypeInteger:
+ compareTestResults(os, mMetricStrings[index],
+ (S32)((*base)[label][ mMetricStrings[index] ].asInteger()), (S32)((*current)[label][ mMetricStrings[index] ].asInteger())) ;
+ break ;
+ case LLSD::TypeReal:
+ compareTestResults(os, mMetricStrings[index],
+ (F32)((*base)[label][ mMetricStrings[index] ].asReal()), (F32)((*current)[label][ mMetricStrings[index] ].asReal())) ;
+ break;
+ default:
+ llerrs << "unsupported metric " << mMetricStrings[index] << " LLSD type: " << (S32)(*current)[label][ mMetricStrings[index] ].type() << llendl ;
+ }
+ }
+ }
+
+ incrementCurrentCount();
+ current_label = getCurrentLabelName();
+ in_base = (*base).has(current_label) ;
+ in_current = (*current).has(current_label) ;
+ }
+}
+
+/*virtual*/
+void LLMetricPerformanceTesterBasic::compareTestResults(std::ofstream* os, std::string metric_string, S32 v_base, S32 v_current)
+{
+ *os << llformat(" ,%s, %d, %d, %d, %.4f\n", metric_string.c_str(), v_base, v_current,
+ v_current - v_base, (v_base != 0) ? 100.f * v_current / v_base : 0) ;
+}
+
+/*virtual*/
+void LLMetricPerformanceTesterBasic::compareTestResults(std::ofstream* os, std::string metric_string, F32 v_base, F32 v_current)
+{
+ *os << llformat(" ,%s, %.4f, %.4f, %.4f, %.4f\n", metric_string.c_str(), v_base, v_current,
+ v_current - v_base, (fabs(v_base) > 0.0001f) ? 100.f * v_current / v_base : 0.f ) ;
+}
+
+//----------------------------------------------------------------------------------------------
+// LLMetricPerformanceTesterWithSession
+//----------------------------------------------------------------------------------------------
+
+LLMetricPerformanceTesterWithSession::LLMetricPerformanceTesterWithSession(std::string name) :
+ LLMetricPerformanceTesterBasic(name),
+ mBaseSessionp(NULL),
+ mCurrentSessionp(NULL)
+{
+}
+
+LLMetricPerformanceTesterWithSession::~LLMetricPerformanceTesterWithSession()
+{
+ if (mBaseSessionp)
+ {
+ delete mBaseSessionp ;
+ mBaseSessionp = NULL ;
+ }
+ if (mCurrentSessionp)
+ {
+ delete mCurrentSessionp ;
+ mCurrentSessionp = NULL ;
+ }
+}
+
+/*virtual*/
+void LLMetricPerformanceTesterWithSession::analyzePerformance(std::ofstream* os, LLSD* base, LLSD* current)
+{
+ // Load the base session
+ resetCurrentCount() ;
+ mBaseSessionp = loadTestSession(base) ;
+
+ // Load the current session
+ resetCurrentCount() ;
+ mCurrentSessionp = loadTestSession(current) ;
+
+ if (!mBaseSessionp || !mCurrentSessionp)
+ {
+ llerrs << "Error loading test sessions." << llendl ;
+ }
+
+ // Compare
+ compareTestSessions(os) ;
+
+ // Release memory
+ if (mBaseSessionp)
+ {
+ delete mBaseSessionp ;
+ mBaseSessionp = NULL ;
+ }
+ if (mCurrentSessionp)
+ {
+ delete mCurrentSessionp ;
+ mCurrentSessionp = NULL ;
+ }
+}
+
+
+//----------------------------------------------------------------------------------------------
+// LLTestSession
+//----------------------------------------------------------------------------------------------
+
+LLMetricPerformanceTesterWithSession::LLTestSession::~LLTestSession()
+{
+}
+
diff --git a/indra/llcommon/llmetricperformancetester.h b/indra/llcommon/llmetricperformancetester.h
new file mode 100644
index 0000000000..925010ac96
--- /dev/null
+++ b/indra/llcommon/llmetricperformancetester.h
@@ -0,0 +1,206 @@
+/**
+ * @file llmetricperformancetester.h
+ * @brief LLMetricPerformanceTesterBasic and LLMetricPerformanceTesterWithSession classes definition
+ *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_METRICPERFORMANCETESTER_H
+#define LL_METRICPERFORMANCETESTER_H
+
+const std::string DEFAULT_METRIC_NAME("metric");
+
+/**
+ * @class LLMetricPerformanceTesterBasic
+ * @brief Performance Metric Base Class
+ */
+class LL_COMMON_API LLMetricPerformanceTesterBasic
+{
+public:
+ /**
+ * @brief Creates a basic tester instance.
+ * @param[in] name - Unique string identifying this tester instance.
+ */
+ LLMetricPerformanceTesterBasic(std::string name);
+ virtual ~LLMetricPerformanceTesterBasic();
+
+ /**
+ * @return Returns true if the instance has been added to the tester map.
+ * Need to be tested after creation of a tester instance so to know if the tester is correctly handled.
+ * A tester might not be added to the map if another tester with the same name already exists.
+ */
+ BOOL isValid() const { return mValidInstance; }
+
+ /**
+ * @brief Write a set of test results to the log LLSD.
+ */
+ void outputTestResults() ;
+
+ /**
+ * @brief Compare the test results.
+ * By default, compares the test results against the baseline one by one, item by item,
+ * in the increasing order of the LLSD record counter, starting from the first one.
+ */
+ virtual void analyzePerformance(std::ofstream* os, LLSD* base, LLSD* current) ;
+
+ /**
+ * @return Returns the number of the test metrics in this tester instance.
+ */
+ S32 getNumberOfMetrics() const { return mMetricStrings.size() ;}
+ /**
+ * @return Returns the metric name at index
+ * @param[in] index - Index on the list of metrics managed by this tester instance.
+ */
+ std::string getMetricName(S32 index) const { return mMetricStrings[index] ;}
+
+protected:
+ /**
+ * @return Returns the name of this tester instance.
+ */
+ std::string getTesterName() const { return mName ;}
+
+ /**
+ * @brief Insert a new metric to be managed by this tester instance.
+ * @param[in] str - Unique string identifying the new metric.
+ */
+ void addMetric(std::string str) ;
+
+ /**
+ * @brief Compare test results, provided in 2 flavors: compare integers and compare floats.
+ * @param[out] os - Formatted output string holding the compared values.
+ * @param[in] metric_string - Name of the metric.
+ * @param[in] v_base - Base value of the metric.
+ * @param[in] v_current - Current value of the metric.
+ */
+ virtual void compareTestResults(std::ofstream* os, std::string metric_string, S32 v_base, S32 v_current) ;
+ virtual void compareTestResults(std::ofstream* os, std::string metric_string, F32 v_base, F32 v_current) ;
+
+ /**
+ * @brief Reset internal record count. Count starts with 1.
+ */
+ void resetCurrentCount() { mCount = 1; }
+ /**
+ * @brief Increment internal record count.
+ */
+ void incrementCurrentCount() { mCount++; }
+ /**
+ * @return Returns the label to be used for the current count. It's "TesterName"-"Count".
+ */
+ std::string getCurrentLabelName() const { return llformat("%s-%d", mName.c_str(), mCount) ;}
+
+ /**
+ * @brief Write a test record to the LLSD. Implementers need to overload this method.
+ * @param[out] sd - The LLSD record to store metric data into.
+ */
+ virtual void outputTestRecord(LLSD* sd) = 0 ;
+
+private:
+ void preOutputTestResults(LLSD* sd) ;
+ void postOutputTestResults(LLSD* sd) ;
+
+ std::string mName ; // Name of this tester instance
+ S32 mCount ; // Current record count
+ BOOL mValidInstance; // TRUE if the instance is managed by the map
+ std::vector< std::string > mMetricStrings ; // Metrics strings
+
+// Static members managing the collection of testers
+public:
+ // Map of all the tester instances in use
+ typedef std::map< std::string, LLMetricPerformanceTesterBasic* > name_tester_map_t;
+ static name_tester_map_t sTesterMap ;
+
+ /**
+ * @return Returns a pointer to the tester
+ * @param[in] name - Name of the tester instance queried.
+ */
+ static LLMetricPerformanceTesterBasic* getTester(std::string name) ;
+
+ /**
+ * @return Returns TRUE if that metric *or* the default catch all metric has been requested to be logged
+ * @param[in] name - Name of the tester queried.
+ */
+ static BOOL isMetricLogRequested(std::string name);
+
+ /**
+ * @return Returns TRUE if there's a tester defined, FALSE otherwise.
+ */
+ static BOOL hasMetricPerformanceTesters() { return !sTesterMap.empty() ;}
+ /**
+ * @brief Delete all testers and reset the tester map
+ */
+ static void cleanClass() ;
+
+private:
+ // Add a tester to the map. Returns false if adding fails.
+ static BOOL addTester(LLMetricPerformanceTesterBasic* tester) ;
+};
+
+/**
+ * @class LLMetricPerformanceTesterWithSession
+ * @brief Performance Metric Class with custom session
+ */
+class LL_COMMON_API LLMetricPerformanceTesterWithSession : public LLMetricPerformanceTesterBasic
+{
+public:
+ /**
+ * @param[in] name - Unique string identifying this tester instance.
+ */
+ LLMetricPerformanceTesterWithSession(std::string name);
+ virtual ~LLMetricPerformanceTesterWithSession();
+
+ /**
+ * @brief Compare the test results.
+ * This will be loading the base and current sessions and compare them using the virtual
+ * abstract methods loadTestSession() and compareTestSessions()
+ */
+ virtual void analyzePerformance(std::ofstream* os, LLSD* base, LLSD* current) ;
+
+protected:
+ /**
+ * @class LLMetricPerformanceTesterWithSession::LLTestSession
+ * @brief Defines an interface for the two abstract virtual functions loadTestSession() and compareTestSessions()
+ */
+ class LL_COMMON_API LLTestSession
+ {
+ public:
+ virtual ~LLTestSession() ;
+ };
+
+ /**
+ * @brief Convert an LLSD log into a test session.
+ * @param[in] log - The LLSD record
+ * @return Returns the record as a test session
+ */
+ virtual LLMetricPerformanceTesterWithSession::LLTestSession* loadTestSession(LLSD* log) = 0;
+
+ /**
+ * @brief Compare the base session and the target session. Assumes base and current sessions have been loaded.
+ * @param[out] os - The comparison result as a standard stream
+ */
+ virtual void compareTestSessions(std::ofstream* os) = 0;
+
+ LLTestSession* mBaseSessionp;
+ LLTestSession* mCurrentSessionp;
+};
+
+#endif
+
diff --git a/indra/llcommon/llprocesslauncher.cpp b/indra/llcommon/llprocesslauncher.cpp
index 99308c94e7..81e5f8820d 100644
--- a/indra/llcommon/llprocesslauncher.cpp
+++ b/indra/llcommon/llprocesslauncher.cpp
@@ -58,6 +58,11 @@ void LLProcessLauncher::setWorkingDirectory(const std::string &dir)
mWorkingDir = dir;
}
+const std::string& LLProcessLauncher::getExecutable() const
+{
+ return mExecutable;
+}
+
void LLProcessLauncher::clearArguments()
{
mLaunchArguments.clear();
diff --git a/indra/llcommon/llprocesslauncher.h b/indra/llcommon/llprocesslauncher.h
index 479aeb664a..954c249147 100644
--- a/indra/llcommon/llprocesslauncher.h
+++ b/indra/llcommon/llprocesslauncher.h
@@ -47,6 +47,8 @@ public:
void setExecutable(const std::string &executable);
void setWorkingDirectory(const std::string &dir);
+ const std::string& getExecutable() const;
+
void clearArguments();
void addArgument(const std::string &arg);
void addArgument(const char *arg);
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index 84da54f26d..f0b7ac5def 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -78,9 +78,6 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
{
LLThread *threadp = (LLThread *)datap;
- // Set thread state to running
- threadp->mStatus = RUNNING;
-
#if !LL_DARWIN
sThreadID = threadp->mID;
#endif
@@ -168,26 +165,45 @@ void LLThread::shutdown()
{
// This thread just wouldn't stop, even though we gave it time
//llwarns << "LLThread::~LLThread() exiting thread before clean exit!" << llendl;
+ // Put a stake in its heart.
+ apr_thread_exit(mAPRThreadp, -1);
return;
}
mAPRThreadp = NULL;
}
delete mRunCondition;
+ mRunCondition = 0;
- if (mIsLocalPool)
+ if (mIsLocalPool && mAPRPoolp)
{
apr_pool_destroy(mAPRPoolp);
+ mAPRPoolp = 0;
}
}
void LLThread::start()
{
- apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, mAPRPoolp);
+ llassert(isStopped());
+
+ // Set thread state to running
+ mStatus = RUNNING;
- // We won't bother joining
- apr_thread_detach(mAPRThreadp);
+ apr_status_t status =
+ apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, mAPRPoolp);
+
+ if(status == APR_SUCCESS)
+ {
+ // We won't bother joining
+ apr_thread_detach(mAPRThreadp);
+ }
+ else
+ {
+ mStatus = STOPPED;
+ llwarns << "failed to start thread " << mName << llendl;
+ ll_apr_warn_status(status);
+ }
}
//============================================================================
diff --git a/indra/llcommon/llthreadsafequeue.cpp b/indra/llcommon/llthreadsafequeue.cpp
new file mode 100644
index 0000000000..8a73e632a9
--- /dev/null
+++ b/indra/llcommon/llthreadsafequeue.cpp
@@ -0,0 +1,109 @@
+/**
+ * @file llthread.cpp
+ *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+#include <apr_pools.h>
+#include <apr_queue.h>
+#include "llthreadsafequeue.h"
+
+
+
+// LLThreadSafeQueueImplementation
+//-----------------------------------------------------------------------------
+
+
+LLThreadSafeQueueImplementation::LLThreadSafeQueueImplementation(apr_pool_t * pool, unsigned int capacity):
+ mOwnsPool(pool == 0),
+ mPool(pool),
+ mQueue(0)
+{
+ if(mOwnsPool) {
+ apr_status_t status = apr_pool_create(&mPool, 0);
+ if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate pool");
+ } else {
+ ; // No op.
+ }
+
+ apr_status_t status = apr_queue_create(&mQueue, capacity, mPool);
+ if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate queue");
+}
+
+
+LLThreadSafeQueueImplementation::~LLThreadSafeQueueImplementation()
+{
+ if(mQueue != 0) {
+ if(apr_queue_size(mQueue) != 0) llwarns <<
+ "terminating queue which still contains " << apr_queue_size(mQueue) <<
+ " elements;" << "memory will be leaked" << LL_ENDL;
+ apr_queue_term(mQueue);
+ }
+ if(mOwnsPool && (mPool != 0)) apr_pool_destroy(mPool);
+}
+
+
+void LLThreadSafeQueueImplementation::pushFront(void * element)
+{
+ apr_status_t status = apr_queue_push(mQueue, element);
+
+ if(status == APR_EINTR) {
+ throw LLThreadSafeQueueInterrupt();
+ } else if(status != APR_SUCCESS) {
+ throw LLThreadSafeQueueError("push failed");
+ } else {
+ ; // Success.
+ }
+}
+
+
+bool LLThreadSafeQueueImplementation::tryPushFront(void * element){
+ return apr_queue_trypush(mQueue, element) == APR_SUCCESS;
+}
+
+
+void * LLThreadSafeQueueImplementation::popBack(void)
+{
+ void * element;
+ apr_status_t status = apr_queue_pop(mQueue, &element);
+
+ if(status == APR_EINTR) {
+ throw LLThreadSafeQueueInterrupt();
+ } else if(status != APR_SUCCESS) {
+ throw LLThreadSafeQueueError("pop failed");
+ } else {
+ return element;
+ }
+}
+
+
+bool LLThreadSafeQueueImplementation::tryPopBack(void *& element)
+{
+ return apr_queue_trypop(mQueue, &element) == APR_SUCCESS;
+}
+
+
+size_t LLThreadSafeQueueImplementation::size()
+{
+ return apr_queue_size(mQueue);
+}
diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h
new file mode 100644
index 0000000000..58cac38769
--- /dev/null
+++ b/indra/llcommon/llthreadsafequeue.h
@@ -0,0 +1,205 @@
+/**
+ * @file llthreadsafequeue.h
+ * @brief Base classes for thread, mutex and condition handling.
+ *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLTHREADSAFEQUEUE_H
+#define LL_LLTHREADSAFEQUEUE_H
+
+
+#include <string>
+#include <stdexcept>
+
+
+struct apr_pool_t; // From apr_pools.h
+class LLThreadSafeQueueImplementation; // See below.
+
+
+//
+// A general queue exception.
+//
+class LL_COMMON_API LLThreadSafeQueueError:
+public std::runtime_error
+{
+public:
+ LLThreadSafeQueueError(std::string const & message):
+ std::runtime_error(message)
+ {
+ ; // No op.
+ }
+};
+
+
+//
+// An exception raised when blocking operations are interrupted.
+//
+class LL_COMMON_API LLThreadSafeQueueInterrupt:
+ public LLThreadSafeQueueError
+{
+public:
+ LLThreadSafeQueueInterrupt(void):
+ LLThreadSafeQueueError("queue operation interrupted")
+ {
+ ; // No op.
+ }
+};
+
+
+struct apr_queue_t; // From apr_queue.h
+
+
+//
+// Implementation details.
+//
+class LL_COMMON_API LLThreadSafeQueueImplementation
+{
+public:
+ LLThreadSafeQueueImplementation(apr_pool_t * pool, unsigned int capacity);
+ ~LLThreadSafeQueueImplementation();
+ void pushFront(void * element);
+ bool tryPushFront(void * element);
+ void * popBack(void);
+ bool tryPopBack(void *& element);
+ size_t size();
+
+private:
+ bool mOwnsPool;
+ apr_pool_t * mPool;
+ apr_queue_t * mQueue;
+};
+
+
+//
+// Implements a thread safe FIFO.
+//
+template<typename ElementT>
+class LLThreadSafeQueue
+{
+public:
+ typedef ElementT value_type;
+
+ // If the pool is set to NULL one will be allocated and managed by this
+ // queue.
+ LLThreadSafeQueue(apr_pool_t * pool = 0, unsigned int capacity = 1024);
+
+ // Add an element to the front of queue (will block if the queue has
+ // reached capacity).
+ //
+ // This call will raise an interrupt error if the queue is deleted while
+ // the caller is blocked.
+ void pushFront(ElementT const & element);
+
+ // Try to add an element to the front ofqueue without blocking. Returns
+ // true only if the element was actually added.
+ bool tryPushFront(ElementT const & element);
+
+ // Pop the element at the end of the queue (will block if the queue is
+ // empty).
+ //
+ // This call will raise an interrupt error if the queue is deleted while
+ // the caller is blocked.
+ ElementT popBack(void);
+
+ // Pop an element from the end of the queue if there is one available.
+ // Returns true only if an element was popped.
+ bool tryPopBack(ElementT & element);
+
+ // Returns the size of the queue.
+ size_t size();
+
+private:
+ LLThreadSafeQueueImplementation mImplementation;
+};
+
+
+
+// LLThreadSafeQueue
+//-----------------------------------------------------------------------------
+
+
+template<typename ElementT>
+LLThreadSafeQueue<ElementT>::LLThreadSafeQueue(apr_pool_t * pool, unsigned int capacity):
+ mImplementation(pool, capacity)
+{
+ ; // No op.
+}
+
+
+template<typename ElementT>
+void LLThreadSafeQueue<ElementT>::pushFront(ElementT const & element)
+{
+ ElementT * elementCopy = new ElementT(element);
+ try {
+ mImplementation.pushFront(elementCopy);
+ } catch (LLThreadSafeQueueInterrupt) {
+ delete elementCopy;
+ throw;
+ }
+}
+
+
+template<typename ElementT>
+bool LLThreadSafeQueue<ElementT>::tryPushFront(ElementT const & element)
+{
+ ElementT * elementCopy = new ElementT(element);
+ bool result = mImplementation.tryPushFront(elementCopy);
+ if(!result) delete elementCopy;
+ return result;
+}
+
+
+template<typename ElementT>
+ElementT LLThreadSafeQueue<ElementT>::popBack(void)
+{
+ ElementT * element = reinterpret_cast<ElementT *> (mImplementation.popBack());
+ ElementT result(*element);
+ delete element;
+ return result;
+}
+
+
+template<typename ElementT>
+bool LLThreadSafeQueue<ElementT>::tryPopBack(ElementT & element)
+{
+ void * storedElement;
+ bool result = mImplementation.tryPopBack(storedElement);
+ if(result) {
+ ElementT * elementPtr = reinterpret_cast<ElementT *>(storedElement);
+ element = *elementPtr;
+ delete elementPtr;
+ } else {
+ ; // No op.
+ }
+ return result;
+}
+
+
+template<typename ElementT>
+size_t LLThreadSafeQueue<ElementT>::size(void)
+{
+ return mImplementation.size();
+}
+
+
+#endif
diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h
index b209e4aa38..d6fa5b1997 100644
--- a/indra/llcommon/llversionviewer.h
+++ b/indra/llcommon/llversionviewer.h
@@ -28,7 +28,7 @@
#define LL_LLVERSIONVIEWER_H
const S32 LL_VERSION_MAJOR = 2;
-const S32 LL_VERSION_MINOR = 4;
+const S32 LL_VERSION_MINOR = 5;
const S32 LL_VERSION_PATCH = 0;
const S32 LL_VERSION_BUILD = 0;