From cd467cc34f876920b35d3570f50dbad54ce4a42c Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Mon, 3 Oct 2011 16:27:24 -0700 Subject: EXP-1286 : First pass at Drag and Drop of tools. Not functional. Most hooks into the LLToolDragAndDrop system in to support the new AT_WIDGET and SOURCE_VIEWER --- indra/llcommon/llassettype.cpp | 3 ++- indra/llcommon/llassettype.h | 8 ++++++-- indra/llcommon/stdenums.h | 5 +++-- 3 files changed, 11 insertions(+), 5 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index 145dddd543..5e566d6c7c 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -93,7 +93,8 @@ LLAssetDictionary::LLAssetDictionary() addEntry(LLAssetType::AT_LINK, new AssetEntry("LINK", "link", "sym link", false, false, true)); addEntry(LLAssetType::AT_LINK_FOLDER, new AssetEntry("FOLDER_LINK", "link_f", "sym folder link", false, false, true)); - addEntry(LLAssetType::AT_MESH, new AssetEntry("MESH", "mesh", "mesh", false, false, false)); + addEntry(LLAssetType::AT_MESH, new AssetEntry("MESH", "mesh", "mesh", false, false, false)); + addEntry(LLAssetType::AT_WIDGET, new AssetEntry("WIDGET", "widget", "widget", false, false, false)); addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, FALSE, FALSE, FALSE)); }; diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index 74ccd00324..d538accbf7 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -108,9 +108,13 @@ public: AT_LINK_FOLDER = 25, // Inventory folder link + + AT_WIDGET = 40, + // UI Widget: this is *not* an inventory asset type, only a viewer side asset (e.g. button, other ui items...) + AT_MESH = 49, - // Mesh data in our proprietary SLM format - + // Mesh data in our proprietary SLM format + AT_COUNT = 50, // +*********************************************************+ diff --git a/indra/llcommon/stdenums.h b/indra/llcommon/stdenums.h index 556eff8370..40b3364b36 100644 --- a/indra/llcommon/stdenums.h +++ b/indra/llcommon/stdenums.h @@ -49,8 +49,9 @@ enum EDragAndDropType DAD_ANIMATION = 12, DAD_GESTURE = 13, DAD_LINK = 14, - DAD_MESH = 15, - DAD_COUNT = 16, // number of types in this enum + DAD_MESH = 15, + DAD_WIDGET = 16, + DAD_COUNT = 17, // number of types in this enum }; // Reasons for drags to be denied. -- cgit v1.2.3 From 5ef05e151d24e15a175d4f78ff17b6abdd36bbc4 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Wed, 5 Oct 2011 15:21:10 -0600 Subject: fix for SH-2434: Mac viewer sometimes freezes at start up and must be force quit. --- indra/llcommon/llqueuedthread.cpp | 7 ++++++- indra/llcommon/llqueuedthread.h | 2 +- indra/llcommon/llworkerthread.cpp | 4 ++-- indra/llcommon/llworkerthread.h | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp index efd9c4b68f..5dee7a3541 100644 --- a/indra/llcommon/llqueuedthread.cpp +++ b/indra/llcommon/llqueuedthread.cpp @@ -32,7 +32,7 @@ //============================================================================ // MAIN THREAD -LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) : +LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded, bool should_pause) : LLThread(name), mThreaded(threaded), mIdleThread(TRUE), @@ -41,6 +41,11 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) : { if (mThreaded) { + if(should_pause) + { + pause() ; //call this before start the thread. + } + start(); } } diff --git a/indra/llcommon/llqueuedthread.h b/indra/llcommon/llqueuedthread.h index a53b22f6fc..499d13a792 100644 --- a/indra/llcommon/llqueuedthread.h +++ b/indra/llcommon/llqueuedthread.h @@ -149,7 +149,7 @@ public: static handle_t nullHandle() { return handle_t(0); } public: - LLQueuedThread(const std::string& name, bool threaded = true); + LLQueuedThread(const std::string& name, bool threaded = true, bool should_pause = false); virtual ~LLQueuedThread(); virtual void shutdown(); diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp index 6b308bb917..e186621503 100644 --- a/indra/llcommon/llworkerthread.cpp +++ b/indra/llcommon/llworkerthread.cpp @@ -34,8 +34,8 @@ //============================================================================ // Run on MAIN thread -LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded) : - LLQueuedThread(name, threaded) +LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded, bool should_pause) : + LLQueuedThread(name, threaded, should_pause) { mDeleteMutex = new LLMutex; } diff --git a/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h index bef5ef53fe..973b78ca01 100644 --- a/indra/llcommon/llworkerthread.h +++ b/indra/llcommon/llworkerthread.h @@ -83,7 +83,7 @@ private: LLMutex* mDeleteMutex; public: - LLWorkerThread(const std::string& name, bool threaded = true); + LLWorkerThread(const std::string& name, bool threaded = true, bool should_pause = false); ~LLWorkerThread(); /*virtual*/ S32 update(U32 max_time_ms); -- cgit v1.2.3 From 897972636d0fdd0c6dc76e1a337bb43e1aa9bc0c Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Mon, 10 Oct 2011 16:31:56 -0600 Subject: fix for SH-2464: Crash on exit in LLPrivateMemoryPoolManager::freeMem --- indra/llcommon/llmemory.cpp | 41 +++++++++++++++++++++++++++++++++++++++-- indra/llcommon/llmemory.h | 1 + 2 files changed, 40 insertions(+), 2 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 8c02ad8290..7d340483b7 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -1773,6 +1773,7 @@ void LLPrivateMemoryPool::LLChunkHashElement::remove(LLPrivateMemoryPool::LLMemo //class LLPrivateMemoryPoolManager //-------------------------------------------------------------------- LLPrivateMemoryPoolManager* LLPrivateMemoryPoolManager::sInstance = NULL ; +std::vector LLPrivateMemoryPoolManager::sDanglingPoolList ; LLPrivateMemoryPoolManager::LLPrivateMemoryPoolManager(BOOL enabled) { @@ -1797,7 +1798,7 @@ LLPrivateMemoryPoolManager::~LLPrivateMemoryPoolManager() S32 k = 0 ; for(mem_allocation_info_t::iterator iter = sMemAllocationTracker.begin() ; iter != sMemAllocationTracker.end() ; ++iter) { - llinfos << k++ << ", " << iter->second << llendl ; + llinfos << k++ << ", " << (U32)iter->first << " : " << iter->second << llendl ; } sMemAllocationTracker.clear() ; } @@ -1817,7 +1818,17 @@ LLPrivateMemoryPoolManager::~LLPrivateMemoryPoolManager() { if(mPoolList[i]) { - delete mPoolList[i] ; + if(mPoolList[i]->isEmpty()) + { + delete mPoolList[i] ; + } + else + { + //can not delete this pool because it has alloacted memory to be freed. + //move it to the dangling list. + sDanglingPoolList.push_back(mPoolList[i]) ; + } + mPoolList[i] = NULL ; } } @@ -1953,6 +1964,32 @@ void LLPrivateMemoryPoolManager::freeMem(LLPrivateMemoryPool* poolp, void* addr } else { + if(!sInstance) //the private memory manager is destroyed, try the dangling list + { + for(S32 i = 0 ; i < sDanglingPoolList.size(); i++) + { + if(sDanglingPoolList[i]->findChunk((char*)addr)) + { + sDanglingPoolList[i]->freeMem(addr) ; + if(sDanglingPoolList[i]->isEmpty()) + { + delete sDanglingPoolList[i] ; + + if(i < sDanglingPoolList.size() - 1) + { + sDanglingPoolList[i] = sDanglingPoolList[sDanglingPoolList.size() - 1] ; + } + sDanglingPoolList.pop_back() ; + } + + addr = NULL ; + break ; + } + } + } + + llassert_always(!addr) ; //addr should be release before hitting here! + free(addr) ; } } diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index db753f0d8b..25e6c68e88 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -399,6 +399,7 @@ private: std::vector mPoolList ; BOOL mPrivatePoolEnabled; + static std::vector sDanglingPoolList ; public: //debug and statistics info. void updateStatistics() ; -- cgit v1.2.3 From fc2929bf4f6366c3a3386e4b79b0fda7bd0466ba Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 13 Oct 2011 17:06:33 -0500 Subject: SH-2559 Remove fast timer (could be responsible for some crashes). --- indra/llcommon/llsdserialize_xml.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp index bf216d41bf..be9db53906 100644 --- a/indra/llcommon/llsdserialize_xml.cpp +++ b/indra/llcommon/llsdserialize_xml.cpp @@ -354,7 +354,6 @@ static unsigned get_till_eol(std::istream& input, char *buf, unsigned bufsize) return count; } -LLFastTimer::DeclareTimer FTM_SD_PARSE_READ_STREAM("LLSD Read Stream"); S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data) { XML_Status status; @@ -374,7 +373,7 @@ S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data) { break; } - { LLFastTimer _(FTM_SD_PARSE_READ_STREAM); + { count = get_till_eol(input, (char *)buffer, BUFFER_SIZE); if (!count) -- cgit v1.2.3 From 4331c112aba074562e9a8826fe6d271a94f790f0 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 14 Oct 2011 11:52:40 -0500 Subject: Backed out changeset b782a75c99e6 --- indra/llcommon/CMakeLists.txt | 3 - indra/llcommon/llapp.cpp | 4 + indra/llcommon/llapr.cpp | 445 +++++++++++++++++++++++++------ indra/llcommon/llapr.h | 107 ++++++-- indra/llcommon/llaprpool.cpp | 202 -------------- indra/llcommon/llaprpool.h | 256 ------------------ indra/llcommon/llcommon.cpp | 13 + indra/llcommon/llcommon.h | 2 + indra/llcommon/llerror.cpp | 3 - indra/llcommon/llerror.h | 1 + indra/llcommon/llfixedbuffer.cpp | 3 +- indra/llcommon/llscopedvolatileaprpool.h | 52 ---- indra/llcommon/llthread.cpp | 151 ++++++----- indra/llcommon/llthread.h | 124 ++------- indra/llcommon/llthreadsafequeue.cpp | 15 +- indra/llcommon/llthreadsafequeue.h | 16 +- indra/llcommon/llworkerthread.cpp | 8 +- indra/llcommon/llworkerthread.h | 3 +- 18 files changed, 615 insertions(+), 793 deletions(-) delete mode 100644 indra/llcommon/llaprpool.cpp delete mode 100644 indra/llcommon/llaprpool.h delete mode 100644 indra/llcommon/llscopedvolatileaprpool.h (limited to 'indra/llcommon') diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index d5b0a67533..9342a22d46 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -32,7 +32,6 @@ set(llcommon_SOURCE_FILES llallocator_heap_profile.cpp llapp.cpp llapr.cpp - llaprpool.cpp llassettype.cpp llavatarname.cpp llbase32.cpp @@ -81,7 +80,6 @@ set(llcommon_SOURCE_FILES llrand.cpp llrefcount.cpp llrun.cpp - llscopedvolatileaprpool.h llsd.cpp llsdserialize.cpp llsdserialize_xml.cpp @@ -123,7 +121,6 @@ set(llcommon_HEADER_FILES llavatarname.h llapp.h llapr.h - llaprpool.h llassettype.h llassoclist.h llavatarconstants.h diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index e5bd2bfa3d..39daefd1ad 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -136,6 +136,10 @@ void LLApp::commonCtor() mOptions.append(sd); } + // Make sure we clean up APR when we exit + // Don't need to do this if we're cleaning up APR in the destructor + //atexit(ll_cleanup_apr); + // Set the application to this instance. sApplication = this; diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index 1e4a51102e..d1c44c9403 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -29,8 +29,212 @@ #include "linden_common.h" #include "llapr.h" #include "apr_dso.h" -#include "llscopedvolatileaprpool.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 + +void ll_init_apr() +{ + if (!gAPRPoolp) + { + // Initialize APR and create the global pool + apr_initialize(); + 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) + { + LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool(FALSE) ; + } +} + + +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; + } + if (gAPRPoolp) + { + apr_pool_destroy(gAPRPoolp); + gAPRPoolp = NULL; + } + if (LLAPRFile::sAPRFilePoolp) + { + delete LLAPRFile::sAPRFilePoolp ; + LLAPRFile::sAPRFilePoolp = NULL ; + } + apr_terminate(); +} + +// +// +//LLAPRPool +// +LLAPRPool::LLAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) + : mParent(parent), + mReleasePoolFlag(releasePoolFlag), + mMaxSize(size), + mPool(NULL) +{ + createAPRPool() ; +} + +LLAPRPool::~LLAPRPool() +{ + releaseAPRPool() ; +} + +void LLAPRPool::createAPRPool() +{ + if(mPool) + { + return ; + } + + mStatus = apr_pool_create(&mPool, mParent); + ll_apr_warn_status(mStatus) ; + + if(mMaxSize > 0) //size is the number of blocks (which is usually 4K), NOT bytes. + { + apr_allocator_t *allocator = apr_pool_allocator_get(mPool); + if (allocator) + { + apr_allocator_max_free_set(allocator, mMaxSize) ; + } + } +} + +void LLAPRPool::releaseAPRPool() +{ + if(!mPool) + { + return ; + } + + if(!mParent || mReleasePoolFlag) + { + apr_pool_destroy(mPool) ; + mPool = NULL ; + } +} + +//virtual +apr_pool_t* LLAPRPool::getAPRPool() +{ + return mPool ; +} + +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) +{ + //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); + } +} + +LLVolatileAPRPool::~LLVolatileAPRPool() +{ + //delete mutex + if(mMutexp) + { + apr_thread_mutex_destroy(mMutexp); + apr_pool_destroy(mMutexPool); + } +} + +// +//define this virtual function to avoid any mistakenly calling LLAPRPool::getAPRPool(). +// +//virtual +apr_pool_t* LLVolatileAPRPool::getAPRPool() +{ + return LLVolatileAPRPool::getVolatileAPRPool() ; +} + +apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool() +{ + LLScopedLock lock(mMutexp) ; + + mNumTotalRef++ ; + mNumActiveRef++ ; + + if(!mPool) + { + createAPRPool() ; + } + + return mPool ; +} + +void LLVolatileAPRPool::clearVolatileAPRPool() +{ + LLScopedLock lock(mMutexp) ; + + if(mNumActiveRef > 0) + { + mNumActiveRef--; + if(mNumActiveRef < 1) + { + if(isFull()) + { + mNumTotalRef = 0 ; + + //destroy the apr_pool. + releaseAPRPool() ; + } + else + { + //This does not actually free the memory, + //it just allows the pool to re-use this memory for the next allocation. + apr_pool_clear(mPool) ; + } + } + } + else + { + llassert_always(mNumActiveRef > 0) ; + } + + //paranoia check if the pool is jammed. + //will remove the check before going to release. + llassert_always(mNumTotalRef < (FULL_VOLATILE_APR_POOL << 2)) ; +} + +BOOL LLVolatileAPRPool::isFull() +{ + return mNumTotalRef > FULL_VOLATILE_APR_POOL ; +} //--------------------------------------------------------------------- // // LLScopedLock @@ -109,17 +313,15 @@ void ll_apr_assert_status(apr_status_t status, apr_dso_handle_t *handle) // LLAPRFile::LLAPRFile() : mFile(NULL), - mVolatileFilePoolp(NULL), - mRegularFilePoolp(NULL) + mCurrentFilePoolp(NULL) { } -LLAPRFile::LLAPRFile(std::string const& filename, apr_int32_t flags, S32* sizep, access_t access_type) +LLAPRFile::LLAPRFile(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool) : mFile(NULL), - mVolatileFilePoolp(NULL), - mRegularFilePoolp(NULL) + mCurrentFilePoolp(NULL) { - open(filename, flags, access_type, sizep); + open(filename, flags, pool); } LLAPRFile::~LLAPRFile() @@ -136,58 +338,36 @@ apr_status_t LLAPRFile::close() mFile = NULL ; } - if (mVolatileFilePoolp) + if(mCurrentFilePoolp) { - mVolatileFilePoolp->clearVolatileAPRPool() ; - mVolatileFilePoolp = NULL ; - } - - if (mRegularFilePoolp) - { - delete mRegularFilePoolp; - mRegularFilePoolp = NULL; + mCurrentFilePoolp->clearVolatileAPRPool() ; + mCurrentFilePoolp = NULL ; } return ret ; } -apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, access_t access_type, S32* sizep) +apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool, S32* sizep) { - llassert_always(!mFile); - llassert_always(!mVolatileFilePoolp && !mRegularFilePoolp); + apr_status_t s ; - apr_status_t status; - { - apr_pool_t* apr_file_open_pool; // The use of apr_pool_t is OK here. - // This is a temporary variable for a pool that is passed directly to apr_file_open below. - if (access_type == short_lived) - { - // Use a "volatile" thread-local pool. - mVolatileFilePoolp = &LLThreadLocalData::tldata().mVolatileAPRPool; - // Access the pool and increment its reference count. - // The reference count of LLVolatileAPRPool objects will be decremented - // again in LLAPRFile::close by calling mVolatileFilePoolp->clearVolatileAPRPool(). - apr_file_open_pool = mVolatileFilePoolp->getVolatileAPRPool(); - } - else - { - mRegularFilePoolp = new LLAPRPool(LLThreadLocalData::tldata().mRootPool); - apr_file_open_pool = (*mRegularFilePoolp)(); - } - status = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, apr_file_open_pool); - } - if (status != APR_SUCCESS || !mFile) + //check if already open some file + llassert_always(!mFile) ; + llassert_always(!mCurrentFilePoolp) ; + + apr_pool_t* apr_pool = pool ? pool->getVolatileAPRPool() : NULL ; + s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, getAPRFilePool(apr_pool)); + + if (s != APR_SUCCESS || !mFile) { mFile = NULL ; - close() ; + if (sizep) { *sizep = 0; } - return status; } - - if (sizep) + else if (sizep) { S32 file_size = 0; apr_off_t offset = 0; @@ -201,7 +381,49 @@ apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, acc *sizep = file_size; } - return status; + if(!mCurrentFilePoolp) + { + mCurrentFilePoolp = pool ; + + if(!mFile) + { + close() ; + } + } + + return s ; +} + +//use gAPRPoolp. +apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool) +{ + apr_status_t s; + + //check if already open some file + llassert_always(!mFile) ; + llassert_always(!mCurrentFilePoolp) ; + llassert_always(use_global_pool) ; //be aware of using gAPRPoolp. + + s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, gAPRPoolp); + if (s != APR_SUCCESS || !mFile) + { + mFile = NULL ; + close() ; + return s; + } + + return s; +} + +apr_pool_t* LLAPRFile::getAPRFilePool(apr_pool_t* pool) +{ + if(!pool) + { + mCurrentFilePoolp = sAPRFilePoolp ; + return mCurrentFilePoolp->getVolatileAPRPool() ; + } + + return pool ; } // File I/O @@ -259,6 +481,45 @@ S32 LLAPRFile::seek(apr_seek_where_t where, S32 offset) //static components of LLAPRFile // +//static +apr_status_t LLAPRFile::close(apr_file_t* file_handle, LLVolatileAPRPool* pool) +{ + apr_status_t ret = APR_SUCCESS ; + if(file_handle) + { + ret = apr_file_close(file_handle); + file_handle = NULL ; + } + + if(pool) + { + pool->clearVolatileAPRPool() ; + } + + return ret ; +} + +//static +apr_file_t* LLAPRFile::open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags) +{ + apr_status_t s; + apr_file_t* file_handle ; + + pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; + + s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool->getVolatileAPRPool()); + if (s != APR_SUCCESS || !file_handle) + { + ll_apr_warn_status(s); + LL_WARNS("APR") << " Attempting to open filename: " << filename << LL_ENDL; + file_handle = NULL ; + close(file_handle, pool) ; + return NULL; + } + + return file_handle ; +} + //static S32 LLAPRFile::seek(apr_file_t* file_handle, apr_seek_where_t where, S32 offset) { @@ -292,15 +553,13 @@ S32 LLAPRFile::seek(apr_file_t* file_handle, apr_seek_where_t where, S32 offset) } //static -S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes) +S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool) { - apr_file_t* file_handle; - LLScopedVolatileAPRPool pool; - apr_status_t s = apr_file_open(&file_handle, filename.c_str(), APR_READ|APR_BINARY, APR_OS_DEFAULT, pool); - if (s != APR_SUCCESS || !file_handle) + //***************************************** + apr_file_t* file_handle = open(filename, pool, APR_READ|APR_BINARY); + //***************************************** + if (!file_handle) { - ll_apr_warn_status(s); - LL_WARNS("APR") << " while attempting to open file \"" << filename << '"' << LL_ENDL; return 0; } @@ -330,13 +589,14 @@ S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nb } } - apr_file_close(file_handle); - + //***************************************** + close(file_handle, pool) ; + //***************************************** return (S32)bytes_read; } //static -S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes) +S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool) { apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY; if (offset < 0) @@ -345,13 +605,11 @@ S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 n offset = 0; } - apr_file_t* file_handle; - LLScopedVolatileAPRPool pool; - apr_status_t s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool); - if (s != APR_SUCCESS || !file_handle) + //***************************************** + apr_file_t* file_handle = open(filename, pool, flags); + //***************************************** + if (!file_handle) { - ll_apr_warn_status(s); - LL_WARNS("APR") << " while attempting to open file \"" << filename << '"' << LL_ENDL; return 0; } @@ -381,18 +639,21 @@ S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 n } } - apr_file_close(file_handle); + //***************************************** + LLAPRFile::close(file_handle, pool); + //***************************************** return (S32)bytes_written; } //static -bool LLAPRFile::remove(const std::string& filename) +bool LLAPRFile::remove(const std::string& filename, LLVolatileAPRPool* pool) { apr_status_t s; - LLScopedVolatileAPRPool pool; - s = apr_file_remove(filename.c_str(), pool); + pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; + s = apr_file_remove(filename.c_str(), pool->getVolatileAPRPool()); + pool->clearVolatileAPRPool() ; if (s != APR_SUCCESS) { @@ -404,12 +665,13 @@ bool LLAPRFile::remove(const std::string& filename) } //static -bool LLAPRFile::rename(const std::string& filename, const std::string& newname) +bool LLAPRFile::rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool) { apr_status_t s; - LLScopedVolatileAPRPool pool; - s = apr_file_rename(filename.c_str(), newname.c_str(), pool); + pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; + s = apr_file_rename(filename.c_str(), newname.c_str(), pool->getVolatileAPRPool()); + pool->clearVolatileAPRPool() ; if (s != APR_SUCCESS) { @@ -421,44 +683,49 @@ bool LLAPRFile::rename(const std::string& filename, const std::string& newname) } //static -bool LLAPRFile::isExist(const std::string& filename, apr_int32_t flags) +bool LLAPRFile::isExist(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags) { - apr_file_t* file_handle; + apr_file_t* apr_file; apr_status_t s; - LLScopedVolatileAPRPool pool; - s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool); + pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; + s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, pool->getVolatileAPRPool()); - if (s != APR_SUCCESS || !file_handle) + if (s != APR_SUCCESS || !apr_file) { + pool->clearVolatileAPRPool() ; return false; } else { - apr_file_close(file_handle); + apr_file_close(apr_file) ; + pool->clearVolatileAPRPool() ; return true; } } //static -S32 LLAPRFile::size(const std::string& filename) +S32 LLAPRFile::size(const std::string& filename, LLVolatileAPRPool* pool) { - apr_file_t* file_handle; + apr_file_t* apr_file; apr_finfo_t info; apr_status_t s; - LLScopedVolatileAPRPool pool; - s = apr_file_open(&file_handle, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool); + pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; + s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool->getVolatileAPRPool()); - if (s != APR_SUCCESS || !file_handle) + if (s != APR_SUCCESS || !apr_file) { + pool->clearVolatileAPRPool() ; + return 0; } else { - apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, file_handle); + apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, apr_file); - apr_file_close(file_handle) ; + apr_file_close(apr_file) ; + pool->clearVolatileAPRPool() ; if (s == APR_SUCCESS) { @@ -472,29 +739,31 @@ S32 LLAPRFile::size(const std::string& filename) } //static -bool LLAPRFile::makeDir(const std::string& dirname) +bool LLAPRFile::makeDir(const std::string& dirname, LLVolatileAPRPool* pool) { apr_status_t s; - LLScopedVolatileAPRPool pool; - s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool); + pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; + s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool->getVolatileAPRPool()); + pool->clearVolatileAPRPool() ; if (s != APR_SUCCESS) { ll_apr_warn_status(s); - LL_WARNS("APR") << " while attempting to make directory: " << dirname << LL_ENDL; + LL_WARNS("APR") << " Attempting to make directory: " << dirname << LL_ENDL; return false; } return true; } //static -bool LLAPRFile::removeDir(const std::string& dirname) +bool LLAPRFile::removeDir(const std::string& dirname, LLVolatileAPRPool* pool) { apr_status_t s; - LLScopedVolatileAPRPool pool; - s = apr_file_remove(dirname.c_str(), pool); + pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; + s = apr_file_remove(dirname.c_str(), pool->getVolatileAPRPool()); + pool->clearVolatileAPRPool() ; if (s != APR_SUCCESS) { diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index 3f846f1314..af33ce666f 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -50,9 +50,71 @@ #include "apr_atomic.h" #include "llstring.h" +extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp; +extern apr_thread_mutex_t* gCallStacksLogMutexp; + struct apr_dso_handle_t; -class LLAPRPool; -class LLVolatileAPRPool; + +/** + * @brief initialize the common apr constructs -- apr itself, the + * global pool, and a mutex. + */ +void LL_COMMON_API ll_init_apr(); + +/** + * @brief Cleanup those common apr constructs. + */ +void LL_COMMON_API ll_cleanup_apr(); + +// +//LL apr_pool +//manage apr_pool_t, destroy allocated apr_pool in the destruction function. +// +class LL_COMMON_API LLAPRPool +{ +public: + LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE) ; + virtual ~LLAPRPool() ; + + virtual apr_pool_t* getAPRPool() ; + apr_status_t getStatus() {return mStatus ; } + +protected: + void releaseAPRPool() ; + void createAPRPool() ; + +protected: + apr_pool_t* mPool ; //pointing to an apr_pool + apr_pool_t* mParent ; //parent pool + apr_size_t mMaxSize ; //max size of mPool, mPool should return memory to system if allocated memory beyond this limit. However it seems not to work. + apr_status_t mStatus ; //status when creating the pool + BOOL mReleasePoolFlag ; //if set, mPool is destroyed when LLAPRPool is deleted. default value is true. +}; + +// +//volatile LL apr_pool +//which clears memory automatically. +//so it can not hold static data or data after memory is cleared +// +class LL_COMMON_API LLVolatileAPRPool : public LLAPRPool +{ +public: + LLVolatileAPRPool(BOOL is_local = TRUE, apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE); + virtual ~LLVolatileAPRPool(); + + /*virtual*/ apr_pool_t* getAPRPool() ; //define this virtual function to avoid any mistakenly calling LLAPRPool::getAPRPool(). + apr_pool_t* getVolatileAPRPool() ; + void clearVolatileAPRPool() ; + + BOOL isFull() ; + +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; +} ; /** * @class LLScopedLock @@ -143,20 +205,15 @@ class LL_COMMON_API LLAPRFile : boost::noncopyable // make this non copyable since a copy closes the file private: apr_file_t* mFile ; - LLVolatileAPRPool* mVolatileFilePoolp; // (Thread local) APR pool currently in use. - LLAPRPool* mRegularFilePoolp; // ...or a regular pool. + LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool. public: - enum access_t { - long_lived, // Use a global pool for long-lived file accesses. - short_lived // Use a volatile pool for short-lived file accesses. - }; - LLAPRFile() ; - LLAPRFile(std::string const& filename, apr_int32_t flags, S32* sizep = NULL, access_t access_type = short_lived); + LLAPRFile(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool = NULL); ~LLAPRFile() ; - - apr_status_t open(const std::string& filename, apr_int32_t flags, access_t access_type, S32* sizep = NULL); + + apr_status_t open(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool = NULL, S32* sizep = NULL); + apr_status_t open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool); //use gAPRPoolp. apr_status_t close() ; // Returns actual offset, -1 if seek fails @@ -169,24 +226,32 @@ public: apr_file_t* getFileHandle() {return mFile;} +private: + apr_pool_t* getAPRFilePool(apr_pool_t* pool) ; + // //******************************************************************************************************************************* //static components // +public: + static LLVolatileAPRPool *sAPRFilePoolp ; //a global apr_pool for APRFile, which is used only when local pool does not exist. + private: + static apr_file_t* open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags); + static apr_status_t close(apr_file_t* file, LLVolatileAPRPool* pool) ; static S32 seek(apr_file_t* file, apr_seek_where_t where, S32 offset); public: // returns false if failure: - static bool remove(const std::string& filename); - static bool rename(const std::string& filename, const std::string& newname); - static bool isExist(const std::string& filename, apr_int32_t flags = APR_READ); - static S32 size(const std::string& filename); - static bool makeDir(const std::string& dirname); - static bool removeDir(const std::string& dirname); + static bool remove(const std::string& filename, LLVolatileAPRPool* pool = NULL); + static bool rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool = NULL); + static bool isExist(const std::string& filename, LLVolatileAPRPool* pool = NULL, apr_int32_t flags = APR_READ); + static S32 size(const std::string& filename, LLVolatileAPRPool* pool = NULL); + static bool makeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL); + static bool removeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL); // Returns bytes read/written, 0 if read/write fails: - static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes); - static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes); // offset<0 means append + static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); + static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); // offset<0 means append //******************************************************************************************************************************* }; @@ -202,4 +267,6 @@ bool LL_COMMON_API ll_apr_warn_status(apr_status_t status, apr_dso_handle_t* han void LL_COMMON_API ll_apr_assert_status(apr_status_t status); void LL_COMMON_API ll_apr_assert_status(apr_status_t status, apr_dso_handle_t* handle); +extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool + #endif // LL_LLAPR_H diff --git a/indra/llcommon/llaprpool.cpp b/indra/llcommon/llaprpool.cpp deleted file mode 100644 index 6f21b61b65..0000000000 --- a/indra/llcommon/llaprpool.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/** - * @file llaprpool.cpp - * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2011, 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$ - * - * CHANGELOG - * and additional copyright holders. - * - * 04/04/2010 - * - Initial version, written by Aleric Inglewood @ SL - * - * 10/11/2010 - * - Added APR_HAS_THREADS #if's to allow creation and destruction - * of subpools by threads other than the parent pool owner. - */ - -#include "linden_common.h" - -#include "llerror.h" -#include "llaprpool.h" -#include "llthread.h" - -// Create a subpool from parent. -void LLAPRPool::create(LLAPRPool& parent) -{ - llassert(!mPool); // Must be non-initialized. - mParent = &parent; - if (!mParent) // Using the default parameter? - { - // By default use the root pool of the current thread. - mParent = &LLThreadLocalData::tldata().mRootPool; - } - llassert(mParent->mPool); // Parent must be initialized. -#if APR_HAS_THREADS - // As per the documentation of APR (ie http://apr.apache.org/docs/apr/1.4/apr__pools_8h.html): - // - // Note that most operations on pools are not thread-safe: a single pool should only be - // accessed by a single thread at any given time. The one exception to this rule is creating - // a subpool of a given pool: one or more threads can safely create subpools at the same - // time that another thread accesses the parent pool. - // - // In other words, it's safe for any thread to create a (sub)pool, independent of who - // owns the parent pool. - mOwner = apr_os_thread_current(); -#else - mOwner = mParent->mOwner; - llassert(apr_os_thread_equal(mOwner, apr_os_thread_current())); -#endif - apr_status_t const apr_pool_create_status = apr_pool_create(&mPool, mParent->mPool); - llassert_always(apr_pool_create_status == APR_SUCCESS); - llassert(mPool); // Initialized. - apr_pool_cleanup_register(mPool, this, &s_plain_cleanup, &apr_pool_cleanup_null); -} - -// Destroy the (sub)pool, if any. -void LLAPRPool::destroy(void) -{ - // Only do anything if we are not already (being) destroyed. - if (mPool) - { -#if !APR_HAS_THREADS - // If we are a root pool, then every thread may destruct us: in that case - // we have to assume that no other thread will use this pool concurrently, - // of course. Otherwise, if we are a subpool, only the thread that owns - // the parent may destruct us, since that is the pool that is still alive, - // possibly being used by others and being altered here. - llassert(!mParent || apr_os_thread_equal(mParent->mOwner, apr_os_thread_current())); -#endif - apr_pool_t* pool = mPool; // The use of apr_pool_t is OK here. - // Temporary store before destroying the pool. - mPool = NULL; // Mark that we are BEING destructed. - apr_pool_cleanup_kill(pool, this, &s_plain_cleanup); - apr_pool_destroy(pool); - } -} - -bool LLAPRPool::parent_is_being_destructed(void) -{ - return mParent && (!mParent->mPool || mParent->parent_is_being_destructed()); -} - -LLAPRInitialization::LLAPRInitialization(void) -{ - static bool apr_initialized = false; - - if (!apr_initialized) - { - apr_initialize(); - } - - apr_initialized = true; -} - -bool LLAPRRootPool::sCountInitialized = false; -apr_uint32_t volatile LLAPRRootPool::sCount; - -apr_thread_mutex_t* gLogMutexp; -apr_thread_mutex_t* gCallStacksLogMutexp; - -LLAPRRootPool::LLAPRRootPool(void) : LLAPRInitialization(), LLAPRPool(0) -{ - // sCountInitialized don't need locking because when we get here there is still only a single thread. - if (!sCountInitialized) - { - // Initialize the logging mutex - apr_thread_mutex_create(&gLogMutexp, APR_THREAD_MUTEX_UNNESTED, mPool); - apr_thread_mutex_create(&gCallStacksLogMutexp, APR_THREAD_MUTEX_UNNESTED, mPool); - - apr_status_t status = apr_atomic_init(mPool); - llassert_always(status == APR_SUCCESS); - apr_atomic_set32(&sCount, 1); // Set to 1 to account for the global root pool. - sCountInitialized = true; - - // Initialize thread-local APR pool support. - // Because this recursively calls LLAPRRootPool::LLAPRRootPool(void) - // it must be done last, so that sCount is already initialized. - LLThreadLocalData::init(); - } - apr_atomic_inc32(&sCount); -} - -LLAPRRootPool::~LLAPRRootPool() -{ - if (!apr_atomic_dec32(&sCount)) - { - // The last pool was destructed. Cleanup remainder of 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; - } - - // Must destroy ALL, and therefore this last LLAPRRootPool, before terminating APR. - static_cast(this)->destroy(); - - apr_terminate(); - } -} - -//static -// Return a global root pool that is independent of LLThreadLocalData. -// Normally you should NOT use this. Only use for early initialization -// (before main) and deinitialization (after main). -LLAPRRootPool& LLAPRRootPool::get(void) -{ - static LLAPRRootPool global_APRpool(0); - return global_APRpool; -} - -void LLVolatileAPRPool::clearVolatileAPRPool() -{ - llassert_always(mNumActiveRef > 0); - if (--mNumActiveRef == 0) - { - if (isOld()) - { - destroy(); - mNumTotalRef = 0 ; - } - else - { - // This does not actually free the memory, - // it just allows the pool to re-use this memory for the next allocation. - clear(); - } - } - - // Paranoia check if the pool is jammed. - llassert(mNumTotalRef < (FULL_VOLATILE_APR_POOL << 2)) ; -} diff --git a/indra/llcommon/llaprpool.h b/indra/llcommon/llaprpool.h deleted file mode 100644 index bf4102c584..0000000000 --- a/indra/llcommon/llaprpool.h +++ /dev/null @@ -1,256 +0,0 @@ -/** - * @file llaprpool.h - * @brief Implementation of LLAPRPool - * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2011, 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$ - * - * CHANGELOG - * and additional copyright holders. - * - * 04/04/2010 - * - Initial version, written by Aleric Inglewood @ SL - * - * 10/11/2010 - * - Added APR_HAS_THREADS #if's to allow creation and destruction - * of subpools by threads other than the parent pool owner. - * - * 05/02/2011 - * - Fixed compilation on windows: Suppress compile warning 4996 - * and include before including , - * by Merov Linden @ SL. - */ - -#ifndef LL_LLAPRPOOL_H -#define LL_LLAPRPOOL_H - -#ifdef LL_WINDOWS -#pragma warning(push) -#pragma warning(disable:4996) -#include -#include // Needed before including apr_portable.h -#pragma warning(pop) -#endif - -#include "apr_portable.h" -#include "apr_pools.h" -#include "llerror.h" - -extern void ll_init_apr(); - -/** - * @brief A wrapper around the APR memory pool API. - * - * Usage of this class should be restricted to passing it to libapr-1 function calls that need it. - * - */ -class LL_COMMON_API LLAPRPool -{ -protected: - //! Pointer to the underlaying pool. NULL if not initialized. - apr_pool_t* mPool; // The use of apr_pool_t is OK here. - // This is the wrapped pointer that it is all about! - //! Pointer to the parent pool, if any. Only valid when mPool is non-zero. - LLAPRPool* mParent; - //! The thread that owns this memory pool. Only valid when mPool is non-zero. - apr_os_thread_t mOwner; - -public: - /// Construct an uninitialized (destructed) pool. - LLAPRPool(void) : mPool(NULL) { } - - /// Construct a subpool from an existing pool. - /// This is not a copy-constructor, this class doesn't have one! - LLAPRPool(LLAPRPool& parent) : mPool(NULL) { create(parent); } - - /// Destruct the memory pool (free all of its subpools and allocated memory). - ~LLAPRPool() { destroy(); } - -protected: - /// Create a pool that is allocated from the Operating System. Only used by LLAPRRootPool. - LLAPRPool(int) : mPool(NULL), mParent(NULL), mOwner(apr_os_thread_current()) - { - apr_status_t const apr_pool_create_status = apr_pool_create(&mPool, NULL); - llassert_always(apr_pool_create_status == APR_SUCCESS); - llassert(mPool); - apr_pool_cleanup_register(mPool, this, &s_plain_cleanup, &apr_pool_cleanup_null); - } - -public: - /// Create a subpool from parent. May only be called for an uninitialized/destroyed pool. - /// The default parameter causes the root pool of the current thread to be used. - void create(LLAPRPool& parent = *static_cast(NULL)); - - /// Destroy the (sub)pool, if any. - void destroy(void); - - // Use some safebool idiom (http://www.artima.com/cppsource/safebool.html) rather than operator bool. - typedef LLAPRPool* const LLAPRPool::* const bool_type; - /// Return true if the pool is initialized. - operator bool_type() const { return mPool ? &LLAPRPool::mParent : 0; } - - /// Painful, but we have to either provide access to this, or wrap - /// every APR function call that needs an apr pool as argument. - /// NEVER destroy a pool that is returned by this function! - apr_pool_t* operator()(void) const // The use of apr_pool_t is OK here. - // This is the accessor for passing the pool to libapr-1 functions. - { - llassert(mPool); - llassert(apr_os_thread_equal(mOwner, apr_os_thread_current())); - return mPool; - } - - /// Free all memory without destructing the pool. - void clear(void) - { - llassert(mPool); - llassert(apr_os_thread_equal(mOwner, apr_os_thread_current())); - apr_pool_clear(mPool); - } - -// These methods would make this class 'complete' (as wrapper around the libapr -// pool functions), but we don't use memory pools in the viewer (only when -// we are forced to pass one to a libapr call), so don't define them in order -// not to encourage people to use them. -#if 0 - void* palloc(size_t size) - { - llassert(mPool); - llassert(apr_os_thread_equal(mOwner, apr_os_thread_current())); - return apr_palloc(mPool, size); - } - void* pcalloc(size_t size) - { - llassert(mPool); - llassert(apr_os_thread_equal(mOwner, apr_os_thread_current())); - return apr_pcalloc(mPool, size); - } -#endif - -private: - bool parent_is_being_destructed(void); - static apr_status_t s_plain_cleanup(void* userdata) { return static_cast(userdata)->plain_cleanup(); } - - apr_status_t plain_cleanup(void) - { - if (mPool && // We are not being destructed, - parent_is_being_destructed()) // but our parent is. - // This means the pool is being destructed recursively by libapr - // because one of its parents is being destructed. - { - mPool = NULL; // Stop destroy() from destructing the pool again. - } - return APR_SUCCESS; - } -}; - -class LLAPRInitialization -{ -public: - LLAPRInitialization(void); -}; - -/** - * @brief Root memory pool (allocates memory from the operating system). - * - * This class should only be used by LLThreadLocalData - * (and LLMutexRootPool when APR_HAS_THREADS isn't defined). - */ -class LL_COMMON_API LLAPRRootPool : public LLAPRInitialization, public LLAPRPool -{ -private: - /// Construct a root memory pool. Should only be used by LLThreadLocalData and LLMutexRootPool. - friend class LLThreadLocalData; -#if !APR_HAS_THREADS - friend class LLMutexRootPool; -#endif - /// Construct a root memory pool. - /// Should only be used by LLThreadLocalData. - LLAPRRootPool(void); - ~LLAPRRootPool(); - -private: - // Keep track of how many root pools exist and when the last one is destructed. - static bool sCountInitialized; - static apr_uint32_t volatile sCount; - -public: - // Return a global root pool that is independent of LLThreadLocalData. - // Normally you should not use this. Only use for early initialization - // (before main) and deinitialization (after main). - static LLAPRRootPool& get(void); - -#if APR_POOL_DEBUG - void grab_ownership(void) - { - // You need a patched libapr to use this. - // See http://web.archiveorange.com/archive/v/5XO9y2zoxUOMt6Gmi1OI - apr_pool_owner_set(mPool); - } -#endif - -private: - // Used for constructing the Special Global Root Pool (returned by LLAPRRootPool::get). - // It is the same as the default constructor but omits to increment sCount. As a result, - // we must be sure that at least one other LLAPRRootPool is created before termination - // of the application (which is the case: we create one LLAPRRootPool per thread). - LLAPRRootPool(int) : LLAPRInitialization(), LLAPRPool(0) { } -}; - -/** Volatile memory pool - * - * 'Volatile' APR memory pool which normally only clears memory, - * and does not destroy the pool (the same pool is reused) for - * greater efficiency. However, as a safe guard the apr pool - * is destructed every FULL_VOLATILE_APR_POOL uses to allow - * the system memory to be allocated more efficiently and not - * get scattered through RAM. - */ -class LL_COMMON_API LLVolatileAPRPool : protected LLAPRPool -{ -public: - LLVolatileAPRPool(void) : mNumActiveRef(0), mNumTotalRef(0) { } - - void clearVolatileAPRPool(void); - - bool isOld(void) const { return mNumTotalRef > FULL_VOLATILE_APR_POOL; } - bool isUnused() const { return mNumActiveRef == 0; } - -private: - friend class LLScopedVolatileAPRPool; - friend class LLAPRFile; - apr_pool_t* getVolatileAPRPool(void) // The use of apr_pool_t is OK here. - { - if (!mPool) create(); - ++mNumActiveRef; - ++mNumTotalRef; - return LLAPRPool::operator()(); - } - -private: - S32 mNumActiveRef; // Number of active uses of the pool. - S32 mNumTotalRef; // Number of total uses of the pool since last creation. - - // Maximum number of references to LLVolatileAPRPool until the pool is recreated. - static S32 const FULL_VOLATILE_APR_POOL = 1024; -}; - -#endif // LL_LLAPRPOOL_H diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp index b8a7394852..8be9e4f4de 100644 --- a/indra/llcommon/llcommon.cpp +++ b/indra/llcommon/llcommon.cpp @@ -30,10 +30,18 @@ #include "llmemory.h" #include "llthread.h" +//static +BOOL LLCommon::sAprInitialized = FALSE; + //static void LLCommon::initClass() { LLMemory::initClass(); + if (!sAprInitialized) + { + ll_init_apr(); + sAprInitialized = TRUE; + } LLTimer::initClass(); LLThreadSafeRefCount::initThreadSafeRefCount(); // LLWorkerThread::initClass(); @@ -47,5 +55,10 @@ void LLCommon::cleanupClass() // LLWorkerThread::cleanupClass(); LLThreadSafeRefCount::cleanupThreadSafeRefCount(); LLTimer::cleanupClass(); + if (sAprInitialized) + { + ll_cleanup_apr(); + sAprInitialized = FALSE; + } LLMemory::cleanupClass(); } diff --git a/indra/llcommon/llcommon.h b/indra/llcommon/llcommon.h index 171590f3d8..ca9cad5d05 100644 --- a/indra/llcommon/llcommon.h +++ b/indra/llcommon/llcommon.h @@ -35,6 +35,8 @@ class LL_COMMON_API LLCommon public: static void initClass(); static void cleanupClass(); +private: + static BOOL sAprInitialized; }; #endif diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 75048073ca..bb64152407 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -866,9 +866,6 @@ You get: */ -extern apr_thread_mutex_t* gLogMutexp; -extern apr_thread_mutex_t* gCallStacksLogMutexp; - namespace { bool checkLevelMap(const LevelMap& map, const std::string& key, LLError::ELevel& level) diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index 15d167c32e..4a42241c4f 100644 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -296,4 +296,5 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; Such computation is done iff the message will be logged. */ + #endif // LL_LLERROR_H diff --git a/indra/llcommon/llfixedbuffer.cpp b/indra/llcommon/llfixedbuffer.cpp index 4b5cdbe288..d394f179fb 100644 --- a/indra/llcommon/llfixedbuffer.cpp +++ b/indra/llcommon/llfixedbuffer.cpp @@ -30,7 +30,8 @@ LLFixedBuffer::LLFixedBuffer(const U32 max_lines) : LLLineBuffer(), - mMaxLines(max_lines) + mMaxLines(max_lines), + mMutex(NULL) { mTimer.reset(); } diff --git a/indra/llcommon/llscopedvolatileaprpool.h b/indra/llcommon/llscopedvolatileaprpool.h deleted file mode 100644 index dbaf4edcad..0000000000 --- a/indra/llcommon/llscopedvolatileaprpool.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * @file llscopedvolatileaprpool.h - * @brief Implementation of LLScopedVolatileAPRPool - * - * $LicenseInfo:firstyear=2010&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2011, 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_LLSCOPEDVOLATILEAPRPOOL_H -#define LL_LLSCOPEDVOLATILEAPRPOOL_H - -#include "llthread.h" - -/** Scoped volatile memory pool. - * - * As the LLVolatileAPRPool should never keep allocations very - * long, its most common use is for allocations with a lifetime - * equal to it's scope. - * - * This is a convenience class that makes just a little easier to type. - */ -class LL_COMMON_API LLScopedVolatileAPRPool -{ -private: - LLVolatileAPRPool& mPool; - apr_pool_t* mScopedAPRpool; // The use of apr_pool_t is OK here. -public: - LLScopedVolatileAPRPool() : mPool(LLThreadLocalData::tldata().mVolatileAPRPool), mScopedAPRpool(mPool.getVolatileAPRPool()) { } - ~LLScopedVolatileAPRPool() { mPool.clearVolatileAPRPool(); } - //! @attention Only use this to pass the underlaying pointer to a libapr-1 function that requires it. - operator apr_pool_t*() const { return mScopedAPRpool; } // The use of apr_pool_t is OK here. -}; - -#endif diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index 4917e3b935..49d05ef411 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -63,9 +63,6 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap { LLThread *threadp = (LLThread *)datap; - // Create a thread local data. - LLThreadLocalData::create(threadp); - // Run the user supplied function threadp->run(); @@ -78,20 +75,38 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap } -LLThread::LLThread(std::string const& name) : - mPaused(false), +LLThread::LLThread(const std::string& name, apr_pool_t *poolp) : + mPaused(FALSE), mName(name), mAPRThreadp(NULL), - mStatus(STOPPED), - mThreadLocalData(NULL) + mStatus(STOPPED) { - mRunCondition = new LLCondition; + // 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); + + mLocalAPRFilePoolp = NULL ; } LLThread::~LLThread() { shutdown(); + + if(mLocalAPRFilePoolp) + { + delete mLocalAPRFilePoolp ; + mLocalAPRFilePoolp = NULL ; + } } void LLThread::shutdown() @@ -128,7 +143,7 @@ void LLThread::shutdown() if (!isStopped()) { // This thread just wouldn't stop, even though we gave it time - llwarns << "LLThread::shutdown() exiting thread before clean exit!" << llendl; + llwarns << "LLThread::~LLThread() exiting thread before clean exit!" << llendl; // Put a stake in its heart. apr_thread_exit(mAPRThreadp, -1); return; @@ -138,8 +153,15 @@ void LLThread::shutdown() delete mRunCondition; mRunCondition = 0; + + if (mIsLocalPool && mAPRPoolp) + { + apr_pool_destroy(mAPRPoolp); + mAPRPoolp = 0; + } } + void LLThread::start() { llassert(isStopped()); @@ -148,7 +170,7 @@ void LLThread::start() mStatus = RUNNING; apr_status_t status = - apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, tldata().mRootPool()); + apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, mAPRPoolp); if(status == APR_SUCCESS) { @@ -173,7 +195,7 @@ void LLThread::pause() if (!mPaused) { // this will cause the thread to stop execution as soon as checkPause() is called - mPaused = true; // Does not need to be atomic since this is only set/unset from the main thread + mPaused = 1; // Does not need to be atomic since this is only set/unset from the main thread } } @@ -181,7 +203,7 @@ void LLThread::unpause() { if (mPaused) { - mPaused = false; + mPaused = 0; } wake(); // wake up the thread if necessary @@ -258,76 +280,85 @@ void LLThread::wakeLocked() } } -#ifdef SHOW_ASSERT -// This allows the use of llassert(is_main_thread()) to assure the current thread is the main thread. -static apr_os_thread_t main_thread_id; -LL_COMMON_API bool is_main_thread(void) { return apr_os_thread_equal(main_thread_id, apr_os_thread_current()); } -#endif - -// The thread private handle to access the LLThreadLocalData instance. -apr_threadkey_t* LLThreadLocalData::sThreadLocalDataKey; +//============================================================================ -//static -void LLThreadLocalData::init(void) +LLMutex::LLMutex(apr_pool_t *poolp) : + mAPRMutexp(NULL) { - // Only do this once. - if (sThreadLocalDataKey) + //if (poolp) + //{ + // mIsLocalPool = FALSE; + // mAPRPoolp = poolp; + //} + //else { - return; + mIsLocalPool = TRUE; + apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread } + apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mAPRPoolp); +} - apr_status_t status = apr_threadkey_private_create(&sThreadLocalDataKey, &LLThreadLocalData::destroy, LLAPRRootPool::get()()); - ll_apr_assert_status(status); // Or out of memory, or system-imposed limit on the - // total number of keys per process {PTHREAD_KEYS_MAX} - // has been exceeded. - - // Create the thread-local data for the main thread (this function is called by the main thread). - LLThreadLocalData::create(NULL); -#ifdef SHOW_ASSERT - // This function is called by the main thread. - main_thread_id = apr_os_thread_current(); +LLMutex::~LLMutex() +{ +#if MUTEX_DEBUG + llassert_always(!isLocked()); // better not be locked! #endif + apr_thread_mutex_destroy(mAPRMutexp); + mAPRMutexp = NULL; + if (mIsLocalPool) + { + apr_pool_destroy(mAPRPoolp); + } } -// This is called once for every thread when the thread is destructed. -//static -void LLThreadLocalData::destroy(void* thread_local_data) + +void LLMutex::lock() { - delete static_cast(thread_local_data); + apr_thread_mutex_lock(mAPRMutexp); +#if MUTEX_DEBUG + // Have to have the lock before we can access the debug info + U32 id = LLThread::currentID(); + if (mIsLocked[id] != FALSE) + llerrs << "Already locked in Thread: " << id << llendl; + mIsLocked[id] = TRUE; +#endif } -//static -void LLThreadLocalData::create(LLThread* threadp) +void LLMutex::unlock() { - LLThreadLocalData* new_tld = new LLThreadLocalData; - if (threadp) - { - threadp->mThreadLocalData = new_tld; - } - apr_status_t status = apr_threadkey_private_set(new_tld, sThreadLocalDataKey); - llassert_always(status == APR_SUCCESS); +#if MUTEX_DEBUG + // Access the debug info while we have the lock + U32 id = LLThread::currentID(); + if (mIsLocked[id] != TRUE) + llerrs << "Not locked in Thread: " << id << llendl; + mIsLocked[id] = FALSE; +#endif + apr_thread_mutex_unlock(mAPRMutexp); } -//static -LLThreadLocalData& LLThreadLocalData::tldata(void) +bool LLMutex::isLocked() { - if (!sThreadLocalDataKey) + apr_status_t status = apr_thread_mutex_trylock(mAPRMutexp); + if (APR_STATUS_IS_EBUSY(status)) { - LLThreadLocalData::init(); + return true; + } + else + { + apr_thread_mutex_unlock(mAPRMutexp); + return false; } - - void* data; - apr_status_t status = apr_threadkey_private_get(&data, sThreadLocalDataKey); - llassert_always(status == APR_SUCCESS); - return *static_cast(data); } //============================================================================ -LLCondition::LLCondition(LLAPRPool& parent) : LLMutex(parent) +LLCondition::LLCondition(apr_pool_t *poolp) : + LLMutex(poolp) { - apr_thread_cond_create(&mAPRCondp, mPool()); + // base class (LLMutex) has already ensured that mAPRPoolp is set up. + + apr_thread_cond_create(&mAPRCondp, mAPRPoolp); } @@ -365,7 +396,7 @@ void LLThreadSafeRefCount::initThreadSafeRefCount() { if (!sMutex) { - sMutex = new LLMutex; + sMutex = new LLMutex(0); } } diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index 757832b8ca..f1c6cd75af 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -29,34 +29,12 @@ #include "llapp.h" #include "llapr.h" -#include "llmemory.h" #include "apr_thread_cond.h" -#include "llaprpool.h" - -#ifdef SHOW_ASSERT -extern LL_COMMON_API bool is_main_thread(void); -#endif class LLThread; class LLMutex; class LLCondition; -class LL_COMMON_API LLThreadLocalData -{ -private: - static apr_threadkey_t* sThreadLocalDataKey; - -public: - // Thread-local memory pools. - LLAPRRootPool mRootPool; - LLVolatileAPRPool mVolatileAPRPool; - - static void init(void); - static void destroy(void* thread_local_data); - static void create(LLThread* pthread); - static LLThreadLocalData& tldata(void); -}; - class LL_COMMON_API LLThread { public: @@ -67,7 +45,7 @@ public: QUITTING= 2 // Someone wants this thread to quit } EThreadStatus; - LLThread(std::string const& name); + LLThread(const std::string& name, apr_pool_t *poolp = NULL); virtual ~LLThread(); // Warning! You almost NEVER want to destroy a thread unless it's in the STOPPED state. virtual void shutdown(); // stops the thread @@ -82,7 +60,7 @@ public: // Called from MAIN THREAD. void pause(); void unpause(); - bool isPaused() { return isStopped() || mPaused; } + bool isPaused() { return isStopped() || mPaused == TRUE; } // Cause the thread to wake up and check its condition void wake(); @@ -96,11 +74,11 @@ public: // this kicks off the apr thread void start(void); - // Return thread-local data for the current thread. - static LLThreadLocalData& tldata(void) { return LLThreadLocalData::tldata(); } + apr_pool_t *getAPRPool() { return mAPRPoolp; } + LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; } private: - bool mPaused; + BOOL mPaused; // static function passed to APR thread creation routine static void *APR_THREAD_FUNC staticRun(apr_thread_t *apr_threadp, void *datap); @@ -110,10 +88,14 @@ protected: LLCondition* mRunCondition; apr_thread_t *mAPRThreadp; + apr_pool_t *mAPRPoolp; + BOOL mIsLocalPool; EThreadStatus mStatus; - friend void LLThreadLocalData::create(LLThread* threadp); - LLThreadLocalData* mThreadLocalData; + //a local apr_pool for APRFile operations in this thread. If it exists, LLAPRFile::sAPRFilePoolp should not be used. + //Note: this pool is used by APRFile ONLY, do NOT use it for any other purposes. + // otherwise it will cause severe memory leaking!!! --bao + LLVolatileAPRPool *mLocalAPRFilePoolp ; void setQuitting(); @@ -143,80 +125,30 @@ protected: #define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO) -#ifdef MUTEX_DEBUG -// We really shouldn't be using recursive locks. Make sure of that in debug mode. -#define MUTEX_FLAG APR_THREAD_MUTEX_UNNESTED -#else -// Use the fastest platform-optimal lock behavior (can be recursive or non-recursive). -#define MUTEX_FLAG APR_THREAD_MUTEX_DEFAULT -#endif - -class LL_COMMON_API LLMutexBase -{ -public: - void lock() { apr_thread_mutex_lock(mAPRMutexp); } - void unlock() { apr_thread_mutex_unlock(mAPRMutexp); } - // Returns true if lock was obtained successfully. - bool trylock() { return !APR_STATUS_IS_EBUSY(apr_thread_mutex_trylock(mAPRMutexp)); } - - // non-blocking, but does do a lock/unlock so not free - bool isLocked() { bool is_not_locked = trylock(); if (is_not_locked) unlock(); return !is_not_locked; } - -protected: - // mAPRMutexp is initialized and uninitialized in the derived class. - apr_thread_mutex_t* mAPRMutexp; -}; - -class LL_COMMON_API LLMutex : public LLMutexBase +class LL_COMMON_API LLMutex { public: - LLMutex(LLAPRPool& parent = LLThread::tldata().mRootPool) : mPool(parent) - { - apr_thread_mutex_create(&mAPRMutexp, MUTEX_FLAG, mPool()); - } - ~LLMutex() - { - llassert(!isLocked()); // better not be locked! - apr_thread_mutex_destroy(mAPRMutexp); - mAPRMutexp = NULL; - } - + LLMutex(apr_pool_t *apr_poolp); // NULL pool constructs a new pool for the mutex + virtual ~LLMutex(); + + void lock(); // blocks + void unlock(); + bool isLocked(); // non-blocking, but does do a lock/unlock so not free + protected: - LLAPRPool mPool; -}; - -#if APR_HAS_THREADS -// No need to use a root pool in this case. -typedef LLMutex LLMutexRootPool; -#else // APR_HAS_THREADS -class LL_COMMON_API LLMutexRootPool : public LLMutexBase -{ -public: - LLMutexRootPool(void) - { - apr_thread_mutex_create(&mAPRMutexp, MUTEX_FLAG, mRootPool()); - } - ~LLMutexRootPool() - { -#if APR_POOL_DEBUG - // It is allowed to destruct root pools from a different thread. - mRootPool.grab_ownership(); + apr_thread_mutex_t *mAPRMutexp; + apr_pool_t *mAPRPoolp; + BOOL mIsLocalPool; +#if MUTEX_DEBUG + std::map mIsLocked; #endif - llassert(!isLocked()); - apr_thread_mutex_destroy(mAPRMutexp); - mAPRMutexp = NULL; - } - -protected: - LLAPRRootPool mRootPool; }; -#endif // APR_HAS_THREADS // Actually a condition/mutex pair (since each condition needs to be associated with a mutex). class LL_COMMON_API LLCondition : public LLMutex { public: - LLCondition(LLAPRPool& parent = LLThread::tldata().mRootPool); + LLCondition(apr_pool_t *apr_poolp); // Defaults to global pool, could use the thread pool as well. ~LLCondition(); void wait(); // blocks @@ -227,10 +159,10 @@ protected: apr_thread_cond_t *mAPRCondp; }; -class LL_COMMON_API LLMutexLock +class LLMutexLock { public: - LLMutexLock(LLMutexBase* mutex) + LLMutexLock(LLMutex* mutex) { mMutex = mutex; mMutex->lock(); @@ -240,7 +172,7 @@ public: mMutex->unlock(); } private: - LLMutexBase* mMutex; + LLMutex* mMutex; }; //============================================================================ diff --git a/indra/llcommon/llthreadsafequeue.cpp b/indra/llcommon/llthreadsafequeue.cpp index 05d24944f3..8a73e632a9 100644 --- a/indra/llcommon/llthreadsafequeue.cpp +++ b/indra/llcommon/llthreadsafequeue.cpp @@ -34,11 +34,19 @@ //----------------------------------------------------------------------------- -LLThreadSafeQueueImplementation::LLThreadSafeQueueImplementation(unsigned int capacity): +LLThreadSafeQueueImplementation::LLThreadSafeQueueImplementation(apr_pool_t * pool, unsigned int capacity): + mOwnsPool(pool == 0), + mPool(pool), mQueue(0) { - mPool.create(); - apr_status_t status = apr_queue_create(&mQueue, capacity, mPool()); + if(mOwnsPool) { + apr_status_t status = apr_pool_create(&mPool, 0); + if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate pool"); + } else { + ; // No op. + } + + apr_status_t status = apr_queue_create(&mQueue, capacity, mPool); if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate queue"); } @@ -51,6 +59,7 @@ LLThreadSafeQueueImplementation::~LLThreadSafeQueueImplementation() " elements;" << "memory will be leaked" << LL_ENDL; apr_queue_term(mQueue); } + if(mOwnsPool && (mPool != 0)) apr_pool_destroy(mPool); } diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h index 43d0b396f2..58cac38769 100644 --- a/indra/llcommon/llthreadsafequeue.h +++ b/indra/llcommon/llthreadsafequeue.h @@ -30,9 +30,9 @@ #include #include -#include "llaprpool.h" +struct apr_pool_t; // From apr_pools.h class LLThreadSafeQueueImplementation; // See below. @@ -75,7 +75,7 @@ struct apr_queue_t; // From apr_queue.h class LL_COMMON_API LLThreadSafeQueueImplementation { public: - LLThreadSafeQueueImplementation(unsigned int capacity); + LLThreadSafeQueueImplementation(apr_pool_t * pool, unsigned int capacity); ~LLThreadSafeQueueImplementation(); void pushFront(void * element); bool tryPushFront(void * element); @@ -84,7 +84,8 @@ public: size_t size(); private: - LLAPRPool mPool; // The pool used for mQueue. + bool mOwnsPool; + apr_pool_t * mPool; apr_queue_t * mQueue; }; @@ -98,8 +99,9 @@ class LLThreadSafeQueue public: typedef ElementT value_type; - // Constructor. - LLThreadSafeQueue(unsigned int capacity = 1024); + // If the pool is set to NULL one will be allocated and managed by this + // queue. + LLThreadSafeQueue(apr_pool_t * pool = 0, unsigned int capacity = 1024); // Add an element to the front of queue (will block if the queue has // reached capacity). @@ -137,8 +139,8 @@ private: template -LLThreadSafeQueue::LLThreadSafeQueue(unsigned int capacity) : - mImplementation(capacity) +LLThreadSafeQueue::LLThreadSafeQueue(apr_pool_t * pool, unsigned int capacity): + mImplementation(pool, capacity) { ; // No op. } diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp index 6b308bb917..3ac50832fd 100644 --- a/indra/llcommon/llworkerthread.cpp +++ b/indra/llcommon/llworkerthread.cpp @@ -37,7 +37,12 @@ LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded) : LLQueuedThread(name, threaded) { - mDeleteMutex = new LLMutex; + mDeleteMutex = new LLMutex(NULL); + + if(!mLocalAPRFilePoolp) + { + mLocalAPRFilePoolp = new LLVolatileAPRPool() ; + } } LLWorkerThread::~LLWorkerThread() @@ -199,6 +204,7 @@ LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& na mWorkerClassName(name), mRequestHandle(LLWorkerThread::nullHandle()), mRequestPriority(LLWorkerThread::PRIORITY_NORMAL), + mMutex(NULL), mWorkFlags(0) { if (!mWorkerThread) diff --git a/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h index bef5ef53fe..9bff18303e 100644 --- a/indra/llcommon/llworkerthread.h +++ b/indra/llcommon/llworkerthread.h @@ -94,6 +94,7 @@ public: private: void deleteWorker(LLWorkerClass* workerclass); // schedule for deletion + }; //============================================================================ @@ -193,7 +194,7 @@ protected: U32 mRequestPriority; // last priority set private: - LLMutexRootPool mMutex; // Use LLMutexRootPool since this object is created and destructed by multiple threads. + LLMutex mMutex; LLAtomicU32 mWorkFlags; }; -- cgit v1.2.3 From 4924f0c99b021869967f4587df703084d2bdc8ed Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 14 Oct 2011 12:38:48 -0500 Subject: b782a75c99e6 backout cleanup --- indra/llcommon/llmemory.cpp | 2 +- indra/llcommon/llthread.cpp | 100 +++++++++++++++++++++++--------------------- indra/llcommon/llthread.h | 14 ++++++- 3 files changed, 66 insertions(+), 50 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 3b27a1639a..3c5c20d0bf 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -1325,7 +1325,7 @@ LLPrivateMemoryPool::LLPrivateMemoryPool(S32 type, U32 max_pool_size) : { if(type == STATIC_THREADED || type == VOLATILE_THREADED) { - mMutexp = new LLMutex ; + mMutexp = new LLMutex(NULL) ; } for(S32 i = 0 ; i < SUPER_ALLOCATION ; i++) diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index ed4f9eb376..4063cc730b 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -36,12 +36,6 @@ #include #endif -#if !LL_DARWIN -U32 ll_thread_local local_thread_ID = 0; -#endif - -U32 LLThread::sIDIter = 0; - //---------------------------------------------------------------------------- // Usage: // void run_func(LLThread* thread) @@ -62,6 +56,12 @@ U32 LLThread::sIDIter = 0; // //---------------------------------------------------------------------------- +#if !LL_DARWIN +U32 ll_thread_local sThreadID = 0; +#endif + +U32 LLThread::sIDIter = 0; + LL_COMMON_API void assert_main_thread() { static U32 s_thread_id = LLThread::currentID(); @@ -79,7 +79,7 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap LLThread *threadp = (LLThread *)datap; #if !LL_DARWIN - local_thread_ID = threadp->mID; + sThreadID = threadp->mID; #endif // Run the user supplied function @@ -100,6 +100,8 @@ LLThread::LLThread(const std::string& name, apr_pool_t *poolp) : mAPRThreadp(NULL), mStatus(STOPPED) { + mID = ++sIDIter; + // Thread creation probably CAN be paranoid about APR being initialized, if necessary if (poolp) { @@ -162,7 +164,7 @@ void LLThread::shutdown() if (!isStopped()) { // This thread just wouldn't stop, even though we gave it time - //llwarns << "LLThread::shutdown() exiting thread before clean exit!" << llendl; + //llwarns << "LLThread::~LLThread() exiting thread before clean exit!" << llendl; // Put a stake in its heart. apr_thread_exit(mAPRThreadp, -1); return; @@ -302,7 +304,7 @@ void LLThread::wakeLocked() //============================================================================ LLMutex::LLMutex(apr_pool_t *poolp) : - mAPRMutexp(NULL) + mAPRMutexp(NULL), mCount(0), mLockingThread(NO_THREAD) { //if (poolp) //{ @@ -321,7 +323,8 @@ LLMutex::LLMutex(apr_pool_t *poolp) : LLMutex::~LLMutex() { #if MUTEX_DEBUG - llassert_always(!isLocked()); // better not be locked! + //bad assertion, the subclass LLSignal might be "locked", and that's OK + //llassert_always(!isLocked()); // better not be locked! #endif apr_thread_mutex_destroy(mAPRMutexp); mAPRMutexp = NULL; @@ -334,7 +337,18 @@ LLMutex::~LLMutex() void LLMutex::lock() { +#if LL_DARWIN + if (mLockingThread == LLThread::currentID()) +#else + if (mLockingThread == sThreadID) +#endif + { //redundant lock + mCount++; + return; + } + apr_thread_mutex_lock(mAPRMutexp); + #if MUTEX_DEBUG // Have to have the lock before we can access the debug info U32 id = LLThread::currentID(); @@ -342,10 +356,22 @@ void LLMutex::lock() llerrs << "Already locked in Thread: " << id << llendl; mIsLocked[id] = TRUE; #endif + +#if LL_DARWIN + mLockingThread = LLThread::currentID(); +#else + mLockingThread = sThreadID; +#endif } void LLMutex::unlock() { + if (mCount > 0) + { //not the root unlock + mCount--; + return; + } + #if MUTEX_DEBUG // Access the debug info while we have the lock U32 id = LLThread::currentID(); @@ -353,6 +379,8 @@ void LLMutex::unlock() llerrs << "Not locked in Thread: " << id << llendl; mIsLocked[id] = FALSE; #endif + + mLockingThread = NO_THREAD; apr_thread_mutex_unlock(mAPRMutexp); } @@ -370,6 +398,11 @@ bool LLMutex::isLocked() } } +U32 LLMutex::lockingThread() const +{ + return mLockingThread; +} + //============================================================================ LLCondition::LLCondition(apr_pool_t *poolp) : @@ -390,6 +423,15 @@ LLCondition::~LLCondition() 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); } @@ -404,44 +446,6 @@ void LLCondition::broadcast() } //============================================================================ -LLMutexBase::LLMutexBase() : - mLockingThread(NO_THREAD), - mCount(0) -{ -} - -void LLMutexBase::lock() -{ -#if LL_DARWIN - if (mLockingThread == LLThread::currentID()) -#else - if (mLockingThread == local_thread_ID) -#endif - { //redundant lock - mCount++; - return; - } - - apr_thread_mutex_lock(mAPRMutexp); - -#if LL_DARWIN - mLockingThread = LLThread::currentID(); -#else - mLockingThread = local_thread_ID; -#endif -} - -void LLMutexBase::unlock() -{ - if (mCount > 0) - { //not the root unlock - mCount--; - return; - } - mLockingThread = NO_THREAD; - - apr_thread_mutex_unlock(mAPRMutexp); -} //---------------------------------------------------------------------------- diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index ad4a6523a1..40291a2569 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -86,6 +86,8 @@ public: apr_pool_t *getAPRPool() { return mAPRPoolp; } LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; } + U32 getID() const { return mID; } + private: BOOL mPaused; @@ -101,7 +103,7 @@ protected: BOOL mIsLocalPool; EThreadStatus mStatus; U32 mID; - + //a local apr_pool for APRFile operations in this thread. If it exists, LLAPRFile::sAPRFilePoolp should not be used. //Note: this pool is used by APRFile ONLY, do NOT use it for any other purposes. // otherwise it will cause severe memory leaking!!! --bao @@ -138,17 +140,27 @@ protected: class LL_COMMON_API LLMutex { public: + typedef enum + { + NO_THREAD = 0xFFFFFFFF + } e_locking_thread; + LLMutex(apr_pool_t *apr_poolp); // NULL pool constructs a new pool for the mutex virtual ~LLMutex(); void lock(); // blocks void unlock(); bool isLocked(); // non-blocking, but does do a lock/unlock so not free + U32 lockingThread() const; //get ID of locking thread protected: apr_thread_mutex_t *mAPRMutexp; + mutable U32 mCount; + mutable U32 mLockingThread; + apr_pool_t *mAPRPoolp; BOOL mIsLocalPool; + #if MUTEX_DEBUG std::map mIsLocked; #endif -- cgit v1.2.3 From 902b33068fa4809915982712f369ecd8cea3c20d Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Tue, 18 Oct 2011 19:27:40 -0400 Subject: increment viewer version to 3.2.0 --- indra/llcommon/llversionviewer.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h index e4ad7f4f54..1dc22519d7 100644 --- a/indra/llcommon/llversionviewer.h +++ b/indra/llcommon/llversionviewer.h @@ -28,8 +28,8 @@ #define LL_LLVERSIONVIEWER_H const S32 LL_VERSION_MAJOR = 3; -const S32 LL_VERSION_MINOR = 1; -const S32 LL_VERSION_PATCH = 1; +const S32 LL_VERSION_MINOR = 2; +const S32 LL_VERSION_PATCH = 0; const S32 LL_VERSION_BUILD = 0; const char * const LL_CHANNEL = "Second Life Developer"; -- cgit v1.2.3 From dd61baa3401a09bd8ff1e894514c15390946cdb3 Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Tue, 18 Oct 2011 19:28:24 -0400 Subject: increment viewer version to 3.2.1 --- indra/llcommon/llversionviewer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h index 1dc22519d7..aa37a03ef8 100644 --- a/indra/llcommon/llversionviewer.h +++ b/indra/llcommon/llversionviewer.h @@ -29,7 +29,7 @@ const S32 LL_VERSION_MAJOR = 3; const S32 LL_VERSION_MINOR = 2; -const S32 LL_VERSION_PATCH = 0; +const S32 LL_VERSION_PATCH = 1; const S32 LL_VERSION_BUILD = 0; const char * const LL_CHANNEL = "Second Life Developer"; -- cgit v1.2.3