diff options
Diffstat (limited to 'indra/llcommon')
| -rw-r--r-- | indra/llcommon/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | indra/llcommon/indra_constants.h | 1 | ||||
| -rw-r--r-- | indra/llcommon/llapp.h | 3 | ||||
| -rw-r--r-- | indra/llcommon/llapr.cpp | 79 | ||||
| -rw-r--r-- | indra/llcommon/llapr.h | 85 | ||||
| -rw-r--r-- | indra/llcommon/llatomic.cpp | 28 | ||||
| -rw-r--r-- | indra/llcommon/llatomic.h | 69 | ||||
| -rw-r--r-- | indra/llcommon/llerror.cpp | 196 | ||||
| -rw-r--r-- | indra/llcommon/llfixedbuffer.cpp | 2 | ||||
| -rw-r--r-- | indra/llcommon/llinstancetracker.cpp | 7 | ||||
| -rw-r--r-- | indra/llcommon/llinstancetracker.h | 9 | ||||
| -rw-r--r-- | indra/llcommon/llmutex.cpp | 133 | ||||
| -rw-r--r-- | indra/llcommon/llmutex.h | 85 | ||||
| -rw-r--r-- | indra/llcommon/llqueuedthread.h | 6 | ||||
| -rw-r--r-- | indra/llcommon/llrefcount.cpp | 109 | ||||
| -rw-r--r-- | indra/llcommon/llrefcount.h | 26 | ||||
| -rw-r--r-- | indra/llcommon/llsys.cpp | 24 | ||||
| -rw-r--r-- | indra/llcommon/llthread.cpp | 83 | ||||
| -rw-r--r-- | indra/llcommon/llthread.h | 12 | ||||
| -rw-r--r-- | indra/llcommon/llthreadsafequeue.cpp | 81 | ||||
| -rw-r--r-- | indra/llcommon/llthreadsafequeue.h | 135 | ||||
| -rw-r--r-- | indra/llcommon/lluuid.cpp | 2 | ||||
| -rw-r--r-- | indra/llcommon/llworkerthread.cpp | 4 | ||||
| -rw-r--r-- | indra/llcommon/llworkerthread.h | 2 | 
24 files changed, 457 insertions, 726 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/indra_constants.h b/indra/llcommon/indra_constants.h index 56b373469a..0fbf4b966b 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -153,7 +153,6 @@ const U8 SIM_ACCESS_DOWN	= 254;  const U8 SIM_ACCESS_MAX 	= SIM_ACCESS_ADULT;  // attachment constants -const S32 MAX_AGENT_ATTACHMENTS = 38;  const U8  ATTACHMENT_ADD = 0x80;  // god levels 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/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/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 | 
