summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2019-04-26 11:17:53 -0400
committerNat Goodspeed <nat@lindenlab.com>2019-04-26 11:17:53 -0400
commit0d596aa4de2f583862274350ce6287c0ed8c2bec (patch)
tree90a6ca5b29d5c99b585233d059e16dccc23a2e19 /indra/llcommon
parent70aa89f708254c47766f4629e9131ea492829129 (diff)
parent85b431d5137886927efef35ca558bc8a998a5212 (diff)
Automated merge with file:///Users/nat/linden/viewer-gridselect
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/CMakeLists.txt2
-rw-r--r--indra/llcommon/llapp.h3
-rw-r--r--indra/llcommon/llapr.cpp79
-rw-r--r--indra/llcommon/llapr.h85
-rw-r--r--indra/llcommon/llatomic.cpp28
-rw-r--r--indra/llcommon/llatomic.h69
-rw-r--r--indra/llcommon/llerror.cpp196
-rw-r--r--indra/llcommon/llfixedbuffer.cpp2
-rw-r--r--indra/llcommon/llinstancetracker.cpp7
-rw-r--r--indra/llcommon/llinstancetracker.h9
-rw-r--r--indra/llcommon/llmutex.cpp133
-rw-r--r--indra/llcommon/llmutex.h85
-rw-r--r--indra/llcommon/llqueuedthread.h6
-rw-r--r--indra/llcommon/llrefcount.cpp109
-rw-r--r--indra/llcommon/llrefcount.h26
-rw-r--r--indra/llcommon/llstring.h11
-rw-r--r--indra/llcommon/llsys.cpp24
-rw-r--r--indra/llcommon/llthread.cpp83
-rw-r--r--indra/llcommon/llthread.h12
-rw-r--r--indra/llcommon/llthreadsafequeue.cpp81
-rw-r--r--indra/llcommon/llthreadsafequeue.h135
-rw-r--r--indra/llcommon/lluri.cpp98
-rw-r--r--indra/llcommon/lluri.h8
-rw-r--r--indra/llcommon/lluuid.cpp2
-rw-r--r--indra/llcommon/llworkerthread.cpp4
-rw-r--r--indra/llcommon/llworkerthread.h2
26 files changed, 570 insertions, 729 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 42ad56f1b0..af41b9e460 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -35,6 +35,7 @@ set(llcommon_SOURCE_FILES
llapp.cpp
llapr.cpp
llassettype.cpp
+ llatomic.cpp
llbase32.cpp
llbase64.cpp
llbitpack.cpp
@@ -135,6 +136,7 @@ set(llcommon_HEADER_FILES
llapp.h
llapr.h
llassettype.h
+ llatomic.h
llbase32.h
llbase64.h
llbitpack.h
diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h
index acd829d864..245c73e3a2 100644
--- a/indra/llcommon/llapp.h
+++ b/indra/llcommon/llapp.h
@@ -30,9 +30,8 @@
#include <map>
#include "llrun.h"
#include "llsd.h"
+#include <atomic>
// Forward declarations
-template <typename Type> class LLAtomic32;
-typedef LLAtomic32<U32> LLAtomicU32;
class LLErrorThread;
class LLLiveFile;
#if LL_LINUX
diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp
index d353d06de2..29f0c7da9a 100644
--- a/indra/llcommon/llapr.cpp
+++ b/indra/llcommon/llapr.cpp
@@ -28,13 +28,12 @@
#include "linden_common.h"
#include "llapr.h"
+#include "llmutex.h"
#include "apr_dso.h"
#include "llthreadlocalstorage.h"
apr_pool_t *gAPRPoolp = NULL; // Global APR memory pool
LLVolatileAPRPool *LLAPRFile::sAPRFilePoolp = NULL ; //global volatile APR memory pool.
-apr_thread_mutex_t *gLogMutexp = NULL;
-apr_thread_mutex_t *gCallStacksLogMutexp = NULL;
const S32 FULL_VOLATILE_APR_POOL = 1024 ; //number of references to LLVolatileAPRPool
@@ -48,10 +47,6 @@ void ll_init_apr()
if (!gAPRPoolp)
{
apr_pool_create(&gAPRPoolp, NULL);
-
- // Initialize the logging mutex
- apr_thread_mutex_create(&gLogMutexp, APR_THREAD_MUTEX_UNNESTED, gAPRPoolp);
- apr_thread_mutex_create(&gCallStacksLogMutexp, APR_THREAD_MUTEX_UNNESTED, gAPRPoolp);
}
if(!LLAPRFile::sAPRFilePoolp)
@@ -75,23 +70,6 @@ void ll_cleanup_apr()
LL_INFOS("APR") << "Cleaning up APR" << LL_ENDL;
- if (gLogMutexp)
- {
- // Clean up the logging mutex
-
- // All other threads NEED to be done before we clean up APR, so this is okay.
- apr_thread_mutex_destroy(gLogMutexp);
- gLogMutexp = NULL;
- }
- if (gCallStacksLogMutexp)
- {
- // Clean up the logging mutex
-
- // All other threads NEED to be done before we clean up APR, so this is okay.
- apr_thread_mutex_destroy(gCallStacksLogMutexp);
- gCallStacksLogMutexp = NULL;
- }
-
LLThreadLocalPointerBase::destroyAllThreadLocalStorage();
if (gAPRPoolp)
@@ -168,26 +146,19 @@ apr_pool_t* LLAPRPool::getAPRPool()
LLVolatileAPRPool::LLVolatileAPRPool(BOOL is_local, apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag)
: LLAPRPool(parent, size, releasePoolFlag),
mNumActiveRef(0),
- mNumTotalRef(0),
- mMutexPool(NULL),
- mMutexp(NULL)
+ mNumTotalRef(0)
{
//create mutex
if(!is_local) //not a local apr_pool, that is: shared by multiple threads.
{
- apr_pool_create(&mMutexPool, NULL); // Create a pool for mutex
- apr_thread_mutex_create(&mMutexp, APR_THREAD_MUTEX_UNNESTED, mMutexPool);
+ mMutexp.reset(new std::mutex());
}
}
LLVolatileAPRPool::~LLVolatileAPRPool()
{
//delete mutex
- if(mMutexp)
- {
- apr_thread_mutex_destroy(mMutexp);
- apr_pool_destroy(mMutexPool);
- }
+ mMutexp.reset();
}
//
@@ -201,7 +172,7 @@ apr_pool_t* LLVolatileAPRPool::getAPRPool()
apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool()
{
- LLScopedLock lock(mMutexp) ;
+ LLScopedLock lock(mMutexp.get()) ;
mNumTotalRef++ ;
mNumActiveRef++ ;
@@ -216,7 +187,7 @@ apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool()
void LLVolatileAPRPool::clearVolatileAPRPool()
{
- LLScopedLock lock(mMutexp) ;
+ LLScopedLock lock(mMutexp.get());
if(mNumActiveRef > 0)
{
@@ -250,44 +221,6 @@ BOOL LLVolatileAPRPool::isFull()
{
return mNumTotalRef > FULL_VOLATILE_APR_POOL ;
}
-//---------------------------------------------------------------------
-//
-// LLScopedLock
-//
-LLScopedLock::LLScopedLock(apr_thread_mutex_t* mutex) : mMutex(mutex)
-{
- if(mutex)
- {
- if(ll_apr_warn_status(apr_thread_mutex_lock(mMutex)))
- {
- mLocked = false;
- }
- else
- {
- mLocked = true;
- }
- }
- else
- {
- mLocked = false;
- }
-}
-
-LLScopedLock::~LLScopedLock()
-{
- unlock();
-}
-
-void LLScopedLock::unlock()
-{
- if(mLocked)
- {
- if(!ll_apr_warn_status(apr_thread_mutex_unlock(mMutex)))
- {
- mLocked = false;
- }
- }
-}
//---------------------------------------------------------------------
diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h
index 1ac5c4e9b2..da50dda103 100644
--- a/indra/llcommon/llapr.h
+++ b/indra/llcommon/llapr.h
@@ -36,15 +36,22 @@
#include <boost/noncopyable.hpp>
#include "llwin32headerslean.h"
#include "apr_thread_proc.h"
-#include "apr_thread_mutex.h"
#include "apr_getopt.h"
#include "apr_signal.h"
-#include "apr_atomic.h"
#include "llstring.h"
-extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp;
-extern apr_thread_mutex_t* gCallStacksLogMutexp;
+#if LL_WINDOWS
+#pragma warning (push)
+#pragma warning (disable:4265)
+#endif
+// warning C4265: 'std::_Pad' : class has virtual functions, but destructor is not virtual
+
+#include <mutex>
+
+#if LL_WINDOWS
+#pragma warning (pop)
+#endif
struct apr_dso_handle_t;
/**
@@ -120,77 +127,9 @@ private:
S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool.
S32 mNumTotalRef ; //number of total pointers pointing to the apr_pool since last creating.
- apr_thread_mutex_t *mMutexp;
- apr_pool_t *mMutexPool;
+ std::unique_ptr<std::mutex> mMutexp;
} ;
-/**
- * @class LLScopedLock
- * @brief Small class to help lock and unlock mutexes.
- *
- * This class is used to have a stack level lock once you already have
- * an apr mutex handy. The constructor handles the lock, and the
- * destructor handles the unlock. Instances of this class are
- * <b>not</b> thread safe.
- */
-class LL_COMMON_API LLScopedLock : private boost::noncopyable
-{
-public:
- /**
- * @brief Constructor which accepts a mutex, and locks it.
- *
- * @param mutex An allocated APR mutex. If you pass in NULL,
- * this wrapper will not lock.
- */
- LLScopedLock(apr_thread_mutex_t* mutex);
-
- /**
- * @brief Destructor which unlocks the mutex if still locked.
- */
- ~LLScopedLock();
-
- /**
- * @brief Check lock.
- */
- bool isLocked() const { return mLocked; }
-
- /**
- * @brief This method unlocks the mutex.
- */
- void unlock();
-
-protected:
- bool mLocked;
- apr_thread_mutex_t* mMutex;
-};
-
-template <typename Type> class LLAtomic32
-{
-public:
- LLAtomic32<Type>() {};
- LLAtomic32<Type>(Type x) {apr_atomic_set32(&mData, apr_uint32_t(x)); };
- ~LLAtomic32<Type>() {};
-
- operator const Type() { apr_uint32_t data = apr_atomic_read32(&mData); return Type(data); }
-
- Type CurrentValue() const { apr_uint32_t data = apr_atomic_read32(const_cast< volatile apr_uint32_t* >(&mData)); return Type(data); }
-
- Type operator =(const Type& x) { apr_atomic_set32(&mData, apr_uint32_t(x)); return Type(mData); }
- void operator -=(Type x) { apr_atomic_sub32(&mData, apr_uint32_t(x)); }
- void operator +=(Type x) { apr_atomic_add32(&mData, apr_uint32_t(x)); }
- Type operator ++(int) { return apr_atomic_inc32(&mData); } // Type++
- Type operator --(int) { return apr_atomic_dec32(&mData); } // approximately --Type (0 if final is 0, non-zero otherwise)
-
- Type operator ++() { return apr_atomic_inc32(&mData); } // Type++
- Type operator --() { return apr_atomic_dec32(&mData); } // approximately --Type (0 if final is 0, non-zero otherwise)
-
-private:
- volatile apr_uint32_t mData;
-};
-
-typedef LLAtomic32<U32> LLAtomicU32;
-typedef LLAtomic32<S32> LLAtomicS32;
-
// File IO convenience functions.
// Returns NULL if the file fails to open, sets *sizep to file size if not NULL
// abbreviated flags
diff --git a/indra/llcommon/llatomic.cpp b/indra/llcommon/llatomic.cpp
new file mode 100644
index 0000000000..93aba1f460
--- /dev/null
+++ b/indra/llcommon/llatomic.cpp
@@ -0,0 +1,28 @@
+/**
+ * @file llatomic.cpp
+ *
+ * $LicenseInfo:firstyear=2018&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2018, 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 "llatomic.h"
+
+//============================================================================
diff --git a/indra/llcommon/llatomic.h b/indra/llcommon/llatomic.h
new file mode 100644
index 0000000000..8de773846c
--- /dev/null
+++ b/indra/llcommon/llatomic.h
@@ -0,0 +1,69 @@
+/**
+ * @file llatomic.h
+ * @brief Base classes for atomic.
+ *
+ * $LicenseInfo:firstyear=2018&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2018, 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_LLATOMIC_H
+#define LL_LLATOMIC_H
+
+#include "stdtypes.h"
+
+#include <atomic>
+
+template <typename Type, typename AtomicType = std::atomic< Type > > class LLAtomicBase
+{
+public:
+ LLAtomicBase() {};
+ LLAtomicBase(Type x) { mData.store(x); }
+ ~LLAtomicBase() {};
+
+ operator const Type() { return mData; }
+
+ Type CurrentValue() const { return mData; }
+
+ Type operator =(const Type& x) { mData.store(x); return mData; }
+ void operator -=(Type x) { mData -= x; }
+ void operator +=(Type x) { mData += x; }
+ Type operator ++(int) { return mData++; }
+ Type operator --(int) { return mData--; }
+
+ Type operator ++() { return ++mData; }
+ Type operator --() { return --mData; }
+
+private:
+ AtomicType mData;
+};
+
+// Typedefs for specialized versions. Using std::atomic_(u)int32_t to get the optimzed implementation.
+#ifdef LL_WINDOWS
+typedef LLAtomicBase<U32, std::atomic_uint32_t> LLAtomicU32;
+typedef LLAtomicBase<S32, std::atomic_int32_t> LLAtomicS32;
+#else
+typedef LLAtomicBase<U32, std::atomic_uint> LLAtomicU32;
+typedef LLAtomicBase<S32, std::atomic_int> LLAtomicS32;
+#endif
+
+typedef LLAtomicBase<bool, std::atomic_bool> LLAtomicBool;
+
+#endif // LL_LLATOMIC_H
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 7cfd1409b1..335a0995fe 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -390,15 +390,22 @@ namespace
{
llifstream file(filename().c_str());
- if (file.is_open())
+ if (!file.is_open())
{
- LLSDSerialize::fromXML(configuration, file);
+ LL_WARNS() << filename() << " failed to open file; not changing configuration" << LL_ENDL;
+ return false;
+ }
+
+ if (LLSDSerialize::fromXML(configuration, file) == LLSDParser::PARSE_FAILURE)
+ {
+ LL_WARNS() << filename() << " parcing error; not changing configuration" << LL_ENDL;
+ return false;
}
- if (configuration.isUndefined())
+ if (configuration.isUndefined() || !configuration.isMap() || configuration.emptyMap())
{
- LL_WARNS() << filename() << " missing, ill-formed,"
- " or simply undefined; not changing configuration"
+ LL_WARNS() << filename() << " missing, ill-formed, or simply undefined"
+ " content; not changing configuration"
<< LL_ENDL;
return false;
}
@@ -860,19 +867,24 @@ namespace LLError
setEnabledLogTypesMask(config["enabled-log-types-mask"].asInteger());
}
- LLSD sets = config["settings"];
- LLSD::array_const_iterator a, end;
- for (a = sets.beginArray(), end = sets.endArray(); a != end; ++a)
- {
- const LLSD& entry = *a;
-
- ELevel level = decodeLevel(entry["level"]);
-
- setLevels(s->mFunctionLevelMap, entry["functions"], level);
- setLevels(s->mClassLevelMap, entry["classes"], level);
- setLevels(s->mFileLevelMap, entry["files"], level);
- setLevels(s->mTagLevelMap, entry["tags"], level);
- }
+ if (config.has("settings") && config["settings"].isArray())
+ {
+ LLSD sets = config["settings"];
+ LLSD::array_const_iterator a, end;
+ for (a = sets.beginArray(), end = sets.endArray(); a != end; ++a)
+ {
+ const LLSD& entry = *a;
+ if (entry.isMap() && !entry.emptyMap())
+ {
+ ELevel level = decodeLevel(entry["level"]);
+
+ setLevels(s->mFunctionLevelMap, entry["functions"], level);
+ setLevels(s->mClassLevelMap, entry["classes"], level);
+ setLevels(s->mFileLevelMap, entry["files"], level);
+ setLevels(s->mTagLevelMap, entry["tags"], level);
+ }
+ }
+ }
}
}
@@ -1136,6 +1148,9 @@ namespace
}
namespace {
+ LLMutex gLogMutex;
+ LLMutex gCallStacksLogMutex;
+
bool checkLevelMap(const LevelMap& map, const std::string& key,
LLError::ELevel& level)
{
@@ -1175,56 +1190,6 @@ namespace {
}
return found_level;
}
-
- class LogLock
- {
- public:
- LogLock();
- ~LogLock();
- bool ok() const { return mOK; }
- private:
- bool mLocked;
- bool mOK;
- };
-
- LogLock::LogLock()
- : mLocked(false), mOK(false)
- {
- if (!gLogMutexp)
- {
- mOK = true;
- return;
- }
-
- const int MAX_RETRIES = 5;
- for (int attempts = 0; attempts < MAX_RETRIES; ++attempts)
- {
- apr_status_t s = apr_thread_mutex_trylock(gLogMutexp);
- if (!APR_STATUS_IS_EBUSY(s))
- {
- mLocked = true;
- mOK = true;
- return;
- }
-
- ms_sleep(1);
- //apr_thread_yield();
- // Just yielding won't necessarily work, I had problems with
- // this on Linux - doug 12/02/04
- }
-
- // We're hosed, we can't get the mutex. Blah.
- std::cerr << "LogLock::LogLock: failed to get mutex for log"
- << std::endl;
- }
-
- LogLock::~LogLock()
- {
- if (mLocked)
- {
- apr_thread_mutex_unlock(gLogMutexp);
- }
- }
}
namespace LLError
@@ -1232,8 +1197,8 @@ namespace LLError
bool Log::shouldLog(CallSite& site)
{
- LogLock lock;
- if (!lock.ok())
+ LLMutexTrylock lock(&gLogMutex, 5);
+ if (!lock.isLocked())
{
return false;
}
@@ -1283,11 +1248,11 @@ namespace LLError
std::ostringstream* Log::out()
{
- LogLock lock;
+ LLMutexTrylock lock(&gLogMutex,5);
// If we hit a logging request very late during shutdown processing,
// when either of the relevant LLSingletons has already been deleted,
// DO NOT resurrect them.
- if (lock.ok() && ! (Settings::wasDeleted() || Globals::wasDeleted()))
+ if (lock.isLocked() && ! (Settings::wasDeleted() || Globals::wasDeleted()))
{
Globals* g = Globals::getInstance();
@@ -1303,8 +1268,8 @@ namespace LLError
void Log::flush(std::ostringstream* out, char* message)
{
- LogLock lock;
- if (!lock.ok())
+ LLMutexTrylock lock(&gLogMutex,5);
+ if (!lock.isLocked())
{
return;
}
@@ -1343,8 +1308,8 @@ namespace LLError
void Log::flush(std::ostringstream* out, const CallSite& site)
{
- LogLock lock;
- if (!lock.ok())
+ LLMutexTrylock lock(&gLogMutex,5);
+ if (!lock.isLocked())
{
return;
}
@@ -1514,69 +1479,6 @@ namespace LLError
char** LLCallStacks::sBuffer = NULL ;
S32 LLCallStacks::sIndex = 0 ;
-#define SINGLE_THREADED 1
-
- class CallStacksLogLock
- {
- public:
- CallStacksLogLock();
- ~CallStacksLogLock();
-
-#if SINGLE_THREADED
- bool ok() const { return true; }
-#else
- bool ok() const { return mOK; }
- private:
- bool mLocked;
- bool mOK;
-#endif
- };
-
-#if SINGLE_THREADED
- CallStacksLogLock::CallStacksLogLock()
- {
- }
- CallStacksLogLock::~CallStacksLogLock()
- {
- }
-#else
- CallStacksLogLock::CallStacksLogLock()
- : mLocked(false), mOK(false)
- {
- if (!gCallStacksLogMutexp)
- {
- mOK = true;
- return;
- }
-
- const int MAX_RETRIES = 5;
- for (int attempts = 0; attempts < MAX_RETRIES; ++attempts)
- {
- apr_status_t s = apr_thread_mutex_trylock(gCallStacksLogMutexp);
- if (!APR_STATUS_IS_EBUSY(s))
- {
- mLocked = true;
- mOK = true;
- return;
- }
-
- ms_sleep(1);
- }
-
- // We're hosed, we can't get the mutex. Blah.
- std::cerr << "CallStacksLogLock::CallStacksLogLock: failed to get mutex for log"
- << std::endl;
- }
-
- CallStacksLogLock::~CallStacksLogLock()
- {
- if (mLocked)
- {
- apr_thread_mutex_unlock(gCallStacksLogMutexp);
- }
- }
-#endif
-
//static
void LLCallStacks::allocateStackBuffer()
{
@@ -1605,8 +1507,8 @@ namespace LLError
//static
void LLCallStacks::push(const char* function, const int line)
{
- CallStacksLogLock lock;
- if (!lock.ok())
+ LLMutexTrylock lock(&gCallStacksLogMutex, 5);
+ if (!lock.isLocked())
{
return;
}
@@ -1640,8 +1542,8 @@ namespace LLError
//static
void LLCallStacks::end(std::ostringstream* _out)
{
- CallStacksLogLock lock;
- if (!lock.ok())
+ LLMutexTrylock lock(&gCallStacksLogMutex, 5);
+ if (!lock.isLocked())
{
return;
}
@@ -1662,8 +1564,8 @@ namespace LLError
//static
void LLCallStacks::print()
{
- CallStacksLogLock lock;
- if (!lock.ok())
+ LLMutexTrylock lock(&gCallStacksLogMutex, 5);
+ if (!lock.isLocked())
{
return;
}
@@ -1700,8 +1602,8 @@ namespace LLError
bool debugLoggingEnabled(const std::string& tag)
{
- LogLock lock;
- if (!lock.ok())
+ LLMutexTrylock lock(&gLogMutex, 5);
+ if (!lock.isLocked())
{
return false;
}
diff --git a/indra/llcommon/llfixedbuffer.cpp b/indra/llcommon/llfixedbuffer.cpp
index d394f179fb..bd4db8be84 100644
--- a/indra/llcommon/llfixedbuffer.cpp
+++ b/indra/llcommon/llfixedbuffer.cpp
@@ -31,7 +31,7 @@
LLFixedBuffer::LLFixedBuffer(const U32 max_lines)
: LLLineBuffer(),
mMaxLines(max_lines),
- mMutex(NULL)
+ mMutex()
{
mTimer.reset();
}
diff --git a/indra/llcommon/llinstancetracker.cpp b/indra/llcommon/llinstancetracker.cpp
index 11fc53f8c8..3f990f4869 100644
--- a/indra/llcommon/llinstancetracker.cpp
+++ b/indra/llcommon/llinstancetracker.cpp
@@ -36,17 +36,16 @@
void LLInstanceTrackerBase::StaticBase::incrementDepth()
{
- apr_atomic_inc32(&sIterationNestDepth);
+ ++sIterationNestDepth;
}
void LLInstanceTrackerBase::StaticBase::decrementDepth()
{
llassert(sIterationNestDepth);
- apr_atomic_dec32(&sIterationNestDepth);
+ --sIterationNestDepth;
}
U32 LLInstanceTrackerBase::StaticBase::getDepth()
{
- apr_uint32_t data = apr_atomic_read32(&sIterationNestDepth);
- return data;
+ return sIterationNestDepth;
}
diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h
index 910c8dbd99..363d0bcbd5 100644
--- a/indra/llcommon/llinstancetracker.h
+++ b/indra/llcommon/llinstancetracker.h
@@ -28,6 +28,7 @@
#ifndef LL_LLINSTANCETRACKER_H
#define LL_LLINSTANCETRACKER_H
+#include <atomic>
#include <map>
#include <typeinfo>
@@ -81,8 +82,12 @@ protected:
void decrementDepth();
U32 getDepth();
private:
- U32 sIterationNestDepth;
- };
+#ifdef LL_WINDOWS
+ std::atomic_uint32_t sIterationNestDepth;
+#else
+ std::atomic_uint sIterationNestDepth;
+#endif
+ };
};
LL_COMMON_API void assert_main_thread();
diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp
index 9c13ef9e30..75f43a4704 100644
--- a/indra/llcommon/llmutex.cpp
+++ b/indra/llcommon/llmutex.cpp
@@ -24,47 +24,22 @@
*/
#include "linden_common.h"
-#include "llapr.h"
-
-#include "apr_portable.h"
#include "llmutex.h"
#include "llthread.h"
+#include "lltimer.h"
//============================================================================
-LLMutex::LLMutex(apr_pool_t *poolp) :
- mAPRMutexp(NULL), mCount(0), mLockingThread(NO_THREAD)
+LLMutex::LLMutex() :
+ mCount(0),
+ mLockingThread(NO_THREAD)
{
- //if (poolp)
- //{
- // mIsLocalPool = FALSE;
- // mAPRPoolp = poolp;
- //}
- //else
- {
- mIsLocalPool = TRUE;
- apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
- }
- apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mAPRPoolp);
}
LLMutex::~LLMutex()
{
-#if MUTEX_DEBUG
- //bad assertion, the subclass LLSignal might be "locked", and that's OK
- //llassert_always(!isLocked()); // better not be locked!
-#endif
- if (ll_apr_is_initialized())
- {
- apr_thread_mutex_destroy(mAPRMutexp);
- if (mIsLocalPool)
- {
- apr_pool_destroy(mAPRPoolp);
- }
- }
- mAPRMutexp = NULL;
}
@@ -76,7 +51,7 @@ void LLMutex::lock()
return;
}
- apr_thread_mutex_lock(mAPRMutexp);
+ mMutex.lock();
#if MUTEX_DEBUG
// Have to have the lock before we can access the debug info
@@ -106,19 +81,18 @@ void LLMutex::unlock()
#endif
mLockingThread = NO_THREAD;
- apr_thread_mutex_unlock(mAPRMutexp);
+ mMutex.unlock();
}
bool LLMutex::isLocked()
{
- apr_status_t status = apr_thread_mutex_trylock(mAPRMutexp);
- if (APR_STATUS_IS_EBUSY(status))
+ if (!mMutex.try_lock())
{
return true;
}
else
{
- apr_thread_mutex_unlock(mAPRMutexp);
+ mMutex.unlock();
return false;
}
}
@@ -141,8 +115,7 @@ bool LLMutex::trylock()
return true;
}
- apr_status_t status(apr_thread_mutex_trylock(mAPRMutexp));
- if (APR_STATUS_IS_EBUSY(status))
+ if (!mMutex.try_lock())
{
return false;
}
@@ -161,45 +134,95 @@ bool LLMutex::trylock()
//============================================================================
-LLCondition::LLCondition(apr_pool_t *poolp) :
- LLMutex(poolp)
+LLCondition::LLCondition() :
+ LLMutex()
{
- // base class (LLMutex) has already ensured that mAPRPoolp is set up.
-
- apr_thread_cond_create(&mAPRCondp, mAPRPoolp);
}
LLCondition::~LLCondition()
{
- apr_thread_cond_destroy(mAPRCondp);
- mAPRCondp = NULL;
}
void LLCondition::wait()
{
- if (!isLocked())
- { //mAPRMutexp MUST be locked before calling apr_thread_cond_wait
- apr_thread_mutex_lock(mAPRMutexp);
-#if MUTEX_DEBUG
- // avoid asserts on destruction in non-release builds
- U32 id = LLThread::currentID();
- mIsLocked[id] = TRUE;
-#endif
- }
- apr_thread_cond_wait(mAPRCondp, mAPRMutexp);
+ std::unique_lock< std::mutex > lock(mMutex);
+ mCond.wait(lock);
}
void LLCondition::signal()
{
- apr_thread_cond_signal(mAPRCondp);
+ mCond.notify_one();
}
void LLCondition::broadcast()
{
- apr_thread_cond_broadcast(mAPRCondp);
+ mCond.notify_all();
+}
+
+
+
+LLMutexTrylock::LLMutexTrylock(LLMutex* mutex)
+ : mMutex(mutex),
+ mLocked(false)
+{
+ if (mMutex)
+ mLocked = mMutex->trylock();
+}
+
+LLMutexTrylock::LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms)
+ : mMutex(mutex),
+ mLocked(false)
+{
+ if (!mMutex)
+ return;
+
+ for (U32 i = 0; i < aTries; ++i)
+ {
+ mLocked = mMutex->trylock();
+ if (mLocked)
+ break;
+ ms_sleep(delay_ms);
+ }
}
+LLMutexTrylock::~LLMutexTrylock()
+{
+ if (mMutex && mLocked)
+ mMutex->unlock();
+}
+
+
+//---------------------------------------------------------------------
+//
+// LLScopedLock
+//
+LLScopedLock::LLScopedLock(std::mutex* mutex) : mMutex(mutex)
+{
+ if(mutex)
+ {
+ mutex->lock();
+ mLocked = true;
+ }
+ else
+ {
+ mLocked = false;
+ }
+}
+
+LLScopedLock::~LLScopedLock()
+{
+ unlock();
+}
+
+void LLScopedLock::unlock()
+{
+ if(mLocked)
+ {
+ mMutex->unlock();
+ mLocked = false;
+ }
+}
//============================================================================
diff --git a/indra/llcommon/llmutex.h b/indra/llcommon/llmutex.h
index ea535cee86..f841d7f950 100644
--- a/indra/llcommon/llmutex.h
+++ b/indra/llcommon/llmutex.h
@@ -28,6 +28,19 @@
#define LL_LLMUTEX_H
#include "stdtypes.h"
+#include <boost/noncopyable.hpp>
+
+#if LL_WINDOWS
+#pragma warning (push)
+#pragma warning (disable:4265)
+#endif
+// 'std::_Pad' : class has virtual functions, but destructor is not virtual
+#include <mutex>
+#include <condition_variable>
+
+#if LL_WINDOWS
+#pragma warning (pop)
+#endif
//============================================================================
@@ -37,10 +50,6 @@
#include <map>
#endif
-struct apr_thread_mutex_t;
-struct apr_pool_t;
-struct apr_thread_cond_t;
-
class LL_COMMON_API LLMutex
{
public:
@@ -49,7 +58,7 @@ public:
NO_THREAD = 0xFFFFFFFF
} e_locking_thread;
- LLMutex(apr_pool_t *apr_poolp = NULL); // NULL pool constructs a new pool for the mutex
+ LLMutex();
virtual ~LLMutex();
void lock(); // blocks
@@ -60,13 +69,10 @@ public:
U32 lockingThread() const; //get ID of locking thread
protected:
- apr_thread_mutex_t *mAPRMutexp;
+ std::mutex mMutex;
mutable U32 mCount;
mutable U32 mLockingThread;
- apr_pool_t *mAPRPoolp;
- BOOL mIsLocalPool;
-
#if MUTEX_DEBUG
std::map<U32, BOOL> mIsLocked;
#endif
@@ -76,7 +82,7 @@ protected:
class LL_COMMON_API LLCondition : public LLMutex
{
public:
- LLCondition(apr_pool_t* apr_poolp); // Defaults to global pool, could use the thread pool as well.
+ LLCondition();
~LLCondition();
void wait(); // blocks
@@ -84,7 +90,7 @@ public:
void broadcast();
protected:
- apr_thread_cond_t* mAPRCondp;
+ std::condition_variable mCond;
};
class LLMutexLock
@@ -119,19 +125,9 @@ private:
class LLMutexTrylock
{
public:
- LLMutexTrylock(LLMutex* mutex)
- : mMutex(mutex),
- mLocked(false)
- {
- if (mMutex)
- mLocked = mMutex->trylock();
- }
-
- ~LLMutexTrylock()
- {
- if (mMutex && mLocked)
- mMutex->unlock();
- }
+ LLMutexTrylock(LLMutex* mutex);
+ LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms = 10);
+ ~LLMutexTrylock();
bool isLocked() const
{
@@ -142,4 +138,43 @@ private:
LLMutex* mMutex;
bool mLocked;
};
-#endif // LL_LLTHREAD_H
+
+/**
+* @class LLScopedLock
+* @brief Small class to help lock and unlock mutexes.
+*
+* The constructor handles the lock, and the destructor handles
+* the unlock. Instances of this class are <b>not</b> thread safe.
+*/
+class LL_COMMON_API LLScopedLock : private boost::noncopyable
+{
+public:
+ /**
+ * @brief Constructor which accepts a mutex, and locks it.
+ *
+ * @param mutex An allocated mutex. If you pass in NULL,
+ * this wrapper will not lock.
+ */
+ LLScopedLock(std::mutex* mutex);
+
+ /**
+ * @brief Destructor which unlocks the mutex if still locked.
+ */
+ ~LLScopedLock();
+
+ /**
+ * @brief Check lock.
+ */
+ bool isLocked() const { return mLocked; }
+
+ /**
+ * @brief This method unlocks the mutex.
+ */
+ void unlock();
+
+protected:
+ bool mLocked;
+ std::mutex* mMutex;
+};
+
+#endif // LL_LLMUTEX_H
diff --git a/indra/llcommon/llqueuedthread.h b/indra/llcommon/llqueuedthread.h
index d3704b0fe2..5d3f873646 100644
--- a/indra/llcommon/llqueuedthread.h
+++ b/indra/llcommon/llqueuedthread.h
@@ -32,7 +32,7 @@
#include <map>
#include <set>
-#include "llapr.h"
+#include "llatomic.h"
#include "llthread.h"
#include "llsimplehash.h"
@@ -128,7 +128,7 @@ public:
};
protected:
- LLAtomic32<status_t> mStatus;
+ LLAtomicBase<status_t> mStatus;
U32 mPriority;
U32 mFlags;
};
@@ -198,7 +198,7 @@ public:
protected:
BOOL mThreaded; // if false, run on main thread and do updates during update()
BOOL mStarted; // required when mThreaded is false to call startThread() from update()
- LLAtomic32<BOOL> mIdleThread; // request queue is empty (or we are quitting) and the thread is idle
+ LLAtomicBool mIdleThread; // request queue is empty (or we are quitting) and the thread is idle
typedef std::set<QueuedRequest*, queued_request_less> request_queue_t;
request_queue_t mRequestQueue;
diff --git a/indra/llcommon/llrefcount.cpp b/indra/llcommon/llrefcount.cpp
index a638df2c7c..29a5ca6f24 100644
--- a/indra/llcommon/llrefcount.cpp
+++ b/indra/llcommon/llrefcount.cpp
@@ -29,25 +29,9 @@
#include "llerror.h"
-#if LL_REF_COUNT_DEBUG
-#include "llthread.h"
-#include "llapr.h"
-#endif
-
LLRefCount::LLRefCount(const LLRefCount& other)
: mRef(0)
{
-#if LL_REF_COUNT_DEBUG
- if(gAPRPoolp)
- {
- mMutexp = new LLMutex(gAPRPoolp) ;
- }
- else
- {
- mMutexp = NULL ;
- }
- mCrashAtUnlock = FALSE ;
-#endif
}
LLRefCount& LLRefCount::operator=(const LLRefCount&)
@@ -59,17 +43,6 @@ LLRefCount& LLRefCount::operator=(const LLRefCount&)
LLRefCount::LLRefCount() :
mRef(0)
{
-#if LL_REF_COUNT_DEBUG
- if(gAPRPoolp)
- {
- mMutexp = new LLMutex(gAPRPoolp) ;
- }
- else
- {
- mMutexp = NULL ;
- }
- mCrashAtUnlock = FALSE ;
-#endif
}
LLRefCount::~LLRefCount()
@@ -78,87 +51,5 @@ LLRefCount::~LLRefCount()
{
LL_ERRS() << "deleting non-zero reference" << LL_ENDL;
}
-
-#if LL_REF_COUNT_DEBUG
- if(gAPRPoolp)
- {
- delete mMutexp ;
- }
-#endif
}
-#if LL_REF_COUNT_DEBUG
-void LLRefCount::ref() const
-{
- if(mMutexp)
- {
- if(mMutexp->isLocked())
- {
- mCrashAtUnlock = TRUE ;
- LL_ERRS() << "the mutex is locked by the thread: " << mLockedThreadID
- << " Current thread: " << LLThread::currentID() << LL_ENDL ;
- }
-
- mMutexp->lock() ;
- mLockedThreadID = LLThread::currentID() ;
-
- mRef++;
-
- if(mCrashAtUnlock)
- {
- while(1); //crash here.
- }
- mMutexp->unlock() ;
- }
- else
- {
- mRef++;
- }
-}
-
-S32 LLRefCount::unref() const
-{
- if(mMutexp)
- {
- if(mMutexp->isLocked())
- {
- mCrashAtUnlock = TRUE ;
- LL_ERRS() << "the mutex is locked by the thread: " << mLockedThreadID
- << " Current thread: " << LLThread::currentID() << LL_ENDL ;
- }
-
- mMutexp->lock() ;
- mLockedThreadID = LLThread::currentID() ;
-
- llassert(mRef >= 1);
- if (0 == --mRef)
- {
- if(mCrashAtUnlock)
- {
- while(1); //crash here.
- }
- mMutexp->unlock() ;
-
- delete this;
- return 0;
- }
-
- if(mCrashAtUnlock)
- {
- while(1); //crash here.
- }
- mMutexp->unlock() ;
- return mRef;
- }
- else
- {
- llassert(mRef >= 1);
- if (0 == --mRef)
- {
- delete this;
- return 0;
- }
- return mRef;
- }
-}
-#endif
diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h
index 1107973569..fb0411d27b 100644
--- a/indra/llcommon/llrefcount.h
+++ b/indra/llcommon/llrefcount.h
@@ -29,12 +29,7 @@
#include <boost/noncopyable.hpp>
#include <boost/intrusive_ptr.hpp>
#include "llmutex.h"
-#include "llapr.h"
-
-#define LL_REF_COUNT_DEBUG 0
-#if LL_REF_COUNT_DEBUG
-class LLMutex ;
-#endif
+#include "llatomic.h"
//----------------------------------------------------------------------------
// RefCount objects should generally only be accessed by way of LLPointer<>'s
@@ -51,10 +46,6 @@ protected:
public:
LLRefCount();
-#if LL_REF_COUNT_DEBUG
- void ref() const ;
- S32 unref() const ;
-#else
inline void ref() const
{
mRef++;
@@ -69,8 +60,7 @@ public:
return 0;
}
return mRef;
- }
-#endif
+ }
//NOTE: when passing around a const LLRefCount object, this can return different results
// at different types, since mRef is mutable
@@ -81,12 +71,6 @@ public:
private:
mutable S32 mRef;
-
-#if LL_REF_COUNT_DEBUG
- LLMutex* mMutexp ;
- mutable U32 mLockedThreadID ;
- mutable BOOL mCrashAtUnlock ;
-#endif
};
@@ -123,8 +107,8 @@ public:
void unref()
{
llassert(mRef >= 1);
- if ((--mRef) == 0) // See note in llapr.h on atomic decrement operator return value.
- {
+ if ((--mRef) == 0)
+ {
// If we hit zero, the caller should be the only smart pointer owning the object and we can delete it.
// It is technically possible for a vanilla pointer to mess this up, or another thread to
// jump in, find this object, create another smart pointer and end up dangling, but if
@@ -140,7 +124,7 @@ public:
}
private:
- LLAtomic32< S32 > mRef;
+ LLAtomicS32 mRef;
};
/**
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 30bec3a6f8..b619a9e48c 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -1735,7 +1735,8 @@ bool LLStringUtilBase<T>::startsWith(
const string_type& substr)
{
if(string.empty() || (substr.empty())) return false;
- if(0 == string.find(substr)) return true;
+ if (substr.length() > string.length()) return false;
+ if (0 == string.compare(0, substr.length(), substr)) return true;
return false;
}
@@ -1746,9 +1747,11 @@ bool LLStringUtilBase<T>::endsWith(
const string_type& 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()));
+ size_t sub_len = substr.length();
+ size_t str_len = string.length();
+ if (sub_len > str_len) return false;
+ if (0 == string.compare(str_len - sub_len, sub_len, substr)) return true;
+ return false;
}
// static
diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp
index 1ef6c538ba..1f8d558fbe 100644
--- a/indra/llcommon/llsys.cpp
+++ b/indra/llcommon/llsys.cpp
@@ -268,10 +268,32 @@ LLOSInfo::LLOSInfo() :
}
}
+ S32 ubr = 0; // Windows 10 Update Build Revision, can be retrieved from a registry
+ if (mMajorVer == 10)
+ {
+ DWORD cbData(sizeof(DWORD));
+ DWORD data(0);
+ HKEY key;
+ BOOL ret_code = RegOpenKeyExW(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), 0, KEY_READ, &key);
+ if (ERROR_SUCCESS == ret_code)
+ {
+ ret_code = RegQueryValueExW(key, L"UBR", 0, NULL, reinterpret_cast<LPBYTE>(&data), &cbData);
+ if (ERROR_SUCCESS == ret_code)
+ {
+ ubr = data;
+ }
+ }
+ }
+
mOSString = mOSStringSimple;
if (mBuild > 0)
{
- mOSString += llformat("(Build %d)", mBuild);
+ mOSString += llformat("(Build %d", mBuild);
+ if (ubr > 0)
+ {
+ mOSString += llformat(".%d", ubr);
+ }
+ mOSString += ")";
}
LLStringUtil::trim(mOSStringSimple);
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index f066e9a4cd..a4171729db 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -116,29 +116,27 @@ void LLThread::registerThreadID()
//
// Handed to the APR thread creation function
//
-void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap)
+void LLThread::threadRun()
{
- LLThread *threadp = (LLThread *)datap;
-
#ifdef LL_WINDOWS
- set_thread_name(-1, threadp->mName.c_str());
+ set_thread_name(-1, mName.c_str());
#endif
// for now, hard code all LLThreads to report to single master thread recorder, which is known to be running on main thread
- threadp->mRecorder = new LLTrace::ThreadRecorder(*LLTrace::get_master_thread_recorder());
+ mRecorder = new LLTrace::ThreadRecorder(*LLTrace::get_master_thread_recorder());
- sThreadID = threadp->mID;
+ sThreadID = mID;
// Run the user supplied function
do
{
try
{
- threadp->run();
+ run();
}
catch (const LLContinueError &e)
{
- LL_WARNS("THREAD") << "ContinueException on thread '" << threadp->mName <<
+ LL_WARNS("THREAD") << "ContinueException on thread '" << mName <<
"' reentering run(). Error what is: '" << e.what() << "'" << LL_ENDL;
//output possible call stacks to log file.
LLError::LLCallStacks::print();
@@ -153,41 +151,27 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
//LL_INFOS() << "LLThread::staticRun() Exiting: " << threadp->mName << LL_ENDL;
- delete threadp->mRecorder;
- threadp->mRecorder = NULL;
+ delete mRecorder;
+ mRecorder = NULL;
// We're done with the run function, this thread is done executing now.
//NB: we are using this flag to sync across threads...we really need memory barriers here
// Todo: add LLMutex per thread instead of flag?
// We are using "while (mStatus != STOPPED) {ms_sleep();}" everywhere.
- threadp->mStatus = STOPPED;
-
- return NULL;
+ mStatus = STOPPED;
}
LLThread::LLThread(const std::string& name, apr_pool_t *poolp) :
mPaused(FALSE),
mName(name),
- mAPRThreadp(NULL),
+ mThreadp(NULL),
mStatus(STOPPED),
mRecorder(NULL)
{
mID = ++sIDIter;
-
- // Thread creation probably CAN be paranoid about APR being initialized, if necessary
- if (poolp)
- {
- mIsLocalPool = FALSE;
- mAPRPoolp = poolp;
- }
- else
- {
- mIsLocalPool = TRUE;
- apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
- }
- mRunCondition = new LLCondition(mAPRPoolp);
- mDataLock = new LLMutex(mAPRPoolp);
+ mRunCondition = new LLCondition();
+ mDataLock = new LLMutex();
mLocalAPRFilePoolp = NULL ;
}
@@ -217,7 +201,7 @@ void LLThread::shutdown()
// Warning! If you somehow call the thread destructor from itself,
// the thread will die in an unclean fashion!
- if (mAPRThreadp)
+ if (mThreadp)
{
if (!isStopped())
{
@@ -248,14 +232,19 @@ void LLThread::shutdown()
{
// This thread just wouldn't stop, even though we gave it time
//LL_WARNS() << "LLThread::~LLThread() exiting thread before clean exit!" << LL_ENDL;
- // Put a stake in its heart.
- apr_thread_exit(mAPRThreadp, -1);
+ // Put a stake in its heart. (A very hostile method to force a thread to quit)
+#if LL_WINDOWS
+ TerminateThread(mNativeHandle, 0);
+#else
+ pthread_cancel(mNativeHandle);
+#endif
+
delete mRecorder;
mRecorder = NULL;
mStatus = STOPPED;
return;
}
- mAPRThreadp = NULL;
+ mThreadp = NULL;
}
delete mRunCondition;
@@ -263,12 +252,6 @@ void LLThread::shutdown()
delete mDataLock;
mDataLock = NULL;
-
- if (mIsLocalPool && mAPRPoolp)
- {
- apr_pool_destroy(mAPRPoolp);
- mAPRPoolp = 0;
- }
if (mRecorder)
{
@@ -287,19 +270,15 @@ void LLThread::start()
// Set thread state to running
mStatus = RUNNING;
- 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);
+ try
+ {
+ mThreadp = new std::thread(std::bind(&LLThread::threadRun, this));
+ mNativeHandle = mThreadp->native_handle();
}
- else
+ catch (std::system_error& ex)
{
mStatus = STOPPED;
- LL_WARNS() << "failed to start thread " << mName << LL_ENDL;
- ll_apr_warn_status(status);
+ LL_WARNS() << "failed to start thread " << mName << " " << ex.what() << LL_ENDL;
}
}
@@ -376,11 +355,7 @@ U32 LLThread::currentID()
// static
void LLThread::yield()
{
-#if LL_LINUX || LL_SOLARIS
- sched_yield(); // annoyingly, apr_thread_yield is a noop on linux...
-#else
- apr_thread_yield();
-#endif
+ std::this_thread::yield();
}
void LLThread::wake()
@@ -413,7 +388,7 @@ void LLThreadSafeRefCount::initThreadSafeRefCount()
{
if (!sMutex)
{
- sMutex = new LLMutex(0);
+ sMutex = new LLMutex();
}
}
diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h
index dda7fa8ffb..863c9051f3 100644
--- a/indra/llcommon/llthread.h
+++ b/indra/llcommon/llthread.h
@@ -29,10 +29,10 @@
#include "llapp.h"
#include "llapr.h"
-#include "apr_thread_cond.h"
#include "boost/intrusive_ptr.hpp"
#include "llmutex.h"
#include "llrefcount.h"
+#include <thread>
LL_COMMON_API void assert_main_thread();
@@ -86,7 +86,6 @@ public:
// this kicks off the apr thread
void start(void);
- apr_pool_t *getAPRPool() { return mAPRPoolp; }
LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; }
U32 getID() const { return mID; }
@@ -97,19 +96,18 @@ public:
static void registerThreadID();
private:
- BOOL mPaused;
+ bool mPaused;
+ std::thread::native_handle_type mNativeHandle; // for termination in case of issues
// static function passed to APR thread creation routine
- static void *APR_THREAD_FUNC staticRun(struct apr_thread_t *apr_threadp, void *datap);
+ void threadRun();
protected:
std::string mName;
class LLCondition* mRunCondition;
LLMutex* mDataLock;
- apr_thread_t *mAPRThreadp;
- apr_pool_t *mAPRPoolp;
- BOOL mIsLocalPool;
+ std::thread *mThreadp;
EThreadStatus mStatus;
U32 mID;
LLTrace::ThreadRecorder* mRecorder;
diff --git a/indra/llcommon/llthreadsafequeue.cpp b/indra/llcommon/llthreadsafequeue.cpp
index 491f920c0f..bde36999ba 100644
--- a/indra/llcommon/llthreadsafequeue.cpp
+++ b/indra/llcommon/llthreadsafequeue.cpp
@@ -24,87 +24,6 @@
*/
#include "linden_common.h"
-#include <apr_pools.h>
-#include <apr_queue.h>
#include "llthreadsafequeue.h"
-#include "llexception.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) LLTHROW(LLThreadSafeQueueError("failed to allocate pool"));
- } else {
- ; // No op.
- }
-
- apr_status_t status = apr_queue_create(&mQueue, capacity, mPool);
- if(status != APR_SUCCESS) LLTHROW(LLThreadSafeQueueError("failed to allocate queue"));
-}
-
-
-LLThreadSafeQueueImplementation::~LLThreadSafeQueueImplementation()
-{
- if(mQueue != 0) {
- if(apr_queue_size(mQueue) != 0) LL_WARNS() <<
- "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) {
- LLTHROW(LLThreadSafeQueueInterrupt());
- } else if(status != APR_SUCCESS) {
- LLTHROW(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) {
- LLTHROW(LLThreadSafeQueueInterrupt());
- } else if(status != APR_SUCCESS) {
- LLTHROW(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
index 45289ef0b4..b0bddac8e5 100644
--- a/indra/llcommon/llthreadsafequeue.h
+++ b/indra/llcommon/llthreadsafequeue.h
@@ -28,12 +28,20 @@
#define LL_LLTHREADSAFEQUEUE_H
#include "llexception.h"
+#include <deque>
#include <string>
+#if LL_WINDOWS
+#pragma warning (push)
+#pragma warning (disable:4265)
+#endif
+// 'std::_Pad' : class has virtual functions, but destructor is not virtual
+#include <mutex>
+#include <condition_variable>
-struct apr_pool_t; // From apr_pools.h
-class LLThreadSafeQueueImplementation; // See below.
-
+#if LL_WINDOWS
+#pragma warning (pop)
+#endif
//
// A general queue exception.
@@ -64,31 +72,6 @@ public:
}
};
-
-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.
//
@@ -100,7 +83,7 @@ public:
// 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);
+ LLThreadSafeQueue(U32 capacity = 1024);
// Add an element to the front of queue (will block if the queue has
// reached capacity).
@@ -128,77 +111,103 @@ public:
size_t size();
private:
- LLThreadSafeQueueImplementation mImplementation;
-};
-
+ std::deque< ElementT > mStorage;
+ U32 mCapacity;
+ std::mutex mLock;
+ std::condition_variable mCapacityCond;
+ std::condition_variable mEmptyCond;
+};
// LLThreadSafeQueue
//-----------------------------------------------------------------------------
-
template<typename ElementT>
-LLThreadSafeQueue<ElementT>::LLThreadSafeQueue(apr_pool_t * pool, unsigned int capacity):
- mImplementation(pool, capacity)
+LLThreadSafeQueue<ElementT>::LLThreadSafeQueue(U32 capacity) :
+mCapacity(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;
- }
+ while (true)
+ {
+ std::unique_lock<std::mutex> lock1(mLock);
+
+ if (mStorage.size() < mCapacity)
+ {
+ mStorage.push_front(element);
+ mEmptyCond.notify_one();
+ return;
+ }
+
+ // Storage Full. Wait for signal.
+ mCapacityCond.wait(lock1);
+ }
}
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;
+ std::unique_lock<std::mutex> lock1(mLock, std::defer_lock);
+ if (!lock1.try_lock())
+ return false;
+
+ if (mStorage.size() >= mCapacity)
+ return false;
+
+ mStorage.push_front(element);
+ mEmptyCond.notify_one();
+ return true;
}
template<typename ElementT>
ElementT LLThreadSafeQueue<ElementT>::popBack(void)
{
- ElementT * element = reinterpret_cast<ElementT *> (mImplementation.popBack());
- ElementT result(*element);
- delete element;
- return result;
+ while (true)
+ {
+ std::unique_lock<std::mutex> lock1(mLock);
+
+ if (!mStorage.empty())
+ {
+ ElementT value = mStorage.back();
+ mStorage.pop_back();
+ mCapacityCond.notify_one();
+ return value;
+ }
+
+ // Storage empty. Wait for signal.
+ mEmptyCond.wait(lock1);
+ }
}
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;
+ std::unique_lock<std::mutex> lock1(mLock, std::defer_lock);
+ if (!lock1.try_lock())
+ return false;
+
+ if (mStorage.empty())
+ return false;
+
+ element = mStorage.back();
+ mStorage.pop_back();
+ mCapacityCond.notify_one();
+ return true;
}
template<typename ElementT>
size_t LLThreadSafeQueue<ElementT>::size(void)
{
- return mImplementation.size();
+ std::lock_guard<std::mutex> lock(mLock);
+ return mStorage.size();
}
-
#endif
diff --git a/indra/llcommon/lluri.cpp b/indra/llcommon/lluri.cpp
index 758b98e143..9942bc0cf8 100644
--- a/indra/llcommon/lluri.cpp
+++ b/indra/llcommon/lluri.cpp
@@ -173,6 +173,19 @@ namespace
"-._~";
return s;
}
+ const std::string path()
+ {
+ static const std::string s =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789"
+ "$-_.+"
+ "!*'(),"
+ "{}|\\^~[]`"
+ "<>#%"
+ ";/?:@&=";
+ return s;
+ }
const std::string sub_delims()
{
static const std::string s = "!$&'()*+,;=";
@@ -187,6 +200,12 @@ namespace
{ return LLURI::escape(s, unreserved() + ":@!$'()*+,"); } // sub_delims - "&;=" + ":@"
std::string escapeQueryValue(const std::string& s)
{ return LLURI::escape(s, unreserved() + ":@!$'()*+,="); } // sub_delims - "&;" + ":@"
+ std::string escapeUriQuery(const std::string& s)
+ { return LLURI::escape(s, unreserved() + ":@?&$;*+=%/"); }
+ std::string escapeUriData(const std::string& s)
+ { return LLURI::escape(s, unreserved() + "%"); }
+ std::string escapeUriPath(const std::string& s)
+ { return LLURI::escape(s, path()); }
}
//static
@@ -202,6 +221,85 @@ std::string LLURI::escape(const std::string& str)
return escape(str, default_allowed, true);
}
+//static
+std::string LLURI::escapePathAndData(const std::string &str)
+{
+ std::string result;
+
+ const std::string data_marker = "data:";
+ if (str.compare(0, data_marker.length(), data_marker) == 0)
+ {
+ // This is not url, but data, data part needs to be properly escaped
+ // data part is separated by ',' from header. Minimal data uri is "data:,"
+ // See "data URI scheme"
+ size_t separator = str.find(',');
+ if (separator != std::string::npos)
+ {
+ size_t header_size = separator + 1;
+ std::string header = str.substr(0, header_size);
+ // base64 is url-safe
+ if (header.find("base64") != std::string::npos)
+ {
+ // assume url-safe data
+ result = str;
+ }
+ else
+ {
+ std::string data = str.substr(header_size, str.length() - header_size);
+
+ // Notes: File can be partially pre-escaped, that's why escaping ignores '%'
+ // It somewhat limits user from displaying strings like "%20" in text
+ // but that's how viewer worked for a while and user can double-escape it
+
+
+ // Header doesn't need escaping
+ result = header + escapeUriData(data);
+ }
+ }
+ }
+ else
+ {
+ // try processing it as path with query separator
+ // The query component is indicated by the first question
+ // mark("?") character and terminated by a number sign("#")
+ size_t delim_pos = str.find('?');
+ if (delim_pos == std::string::npos)
+ {
+ // alternate separator
+ delim_pos = str.find(';');
+ }
+
+ if (delim_pos != std::string::npos)
+ {
+ size_t path_size = delim_pos + 1;
+ std::string query;
+ std::string fragment;
+
+ size_t fragment_pos = str.find('#');
+ if (fragment_pos != std::string::npos)
+ {
+ query = str.substr(path_size, fragment_pos - path_size);
+ fragment = str.substr(fragment_pos);
+ }
+ else
+ {
+ query = str.substr(path_size);
+ }
+
+ std::string path = str.substr(0, path_size);
+
+ result = escapeUriPath(path) + escapeUriQuery(query) + escapeUriPath(fragment);
+ }
+ }
+
+ if (result.empty())
+ {
+ // Not a known scheme or no data part, try just escaping as Uri path
+ result = escapeUriPath(str);
+ }
+ return result;
+}
+
LLURI::LLURI()
{
}
diff --git a/indra/llcommon/lluri.h b/indra/llcommon/lluri.h
index 9e44cc7da2..b8fca0ca51 100644
--- a/indra/llcommon/lluri.h
+++ b/indra/llcommon/lluri.h
@@ -158,6 +158,14 @@ public:
bool is_allowed_sorted = false);
/**
+ * @brief Break string into data part and path or sheme
+ * and escape path (if present) and data.
+ * Data part is not allowed to have path related symbols
+ * @param str The raw URI to escape.
+ */
+ static std::string escapePathAndData(const std::string &str);
+
+ /**
* @brief unescape an escaped URI string.
*
* @param str The escped URI to unescape.
diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp
index d4af2c6b01..8f33d789eb 100644
--- a/indra/llcommon/lluuid.cpp
+++ b/indra/llcommon/lluuid.cpp
@@ -738,7 +738,7 @@ void LLUUID::getCurrentTime(uuid_time_t *timestamp)
getSystemTime(&time_last);
uuids_this_tick = uuids_per_tick;
init = TRUE;
- mMutex = new LLMutex(NULL);
+ mMutex = new LLMutex();
}
uuid_time_t time_now = {0,0};
diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp
index 4c197dc1d6..4b91b2caca 100644
--- a/indra/llcommon/llworkerthread.cpp
+++ b/indra/llcommon/llworkerthread.cpp
@@ -37,7 +37,7 @@
LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded, bool should_pause) :
LLQueuedThread(name, threaded, should_pause)
{
- mDeleteMutex = new LLMutex(NULL);
+ mDeleteMutex = new LLMutex();
if(!mLocalAPRFilePoolp)
{
@@ -204,7 +204,7 @@ LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& na
mWorkerClassName(name),
mRequestHandle(LLWorkerThread::nullHandle()),
mRequestPriority(LLWorkerThread::PRIORITY_NORMAL),
- mMutex(NULL),
+ mMutex(),
mWorkFlags(0)
{
if (!mWorkerThread)
diff --git a/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h
index 09776816a8..b1a6f61360 100644
--- a/indra/llcommon/llworkerthread.h
+++ b/indra/llcommon/llworkerthread.h
@@ -33,7 +33,7 @@
#include <string>
#include "llqueuedthread.h"
-#include "llapr.h"
+#include "llatomic.h"
#define USE_FRAME_CALLBACK_MANAGER 0