diff options
author | Brad Kittenbrink <brad@lindenlab.com> | 2009-02-18 21:10:16 +0000 |
---|---|---|
committer | Brad Kittenbrink <brad@lindenlab.com> | 2009-02-18 21:10:16 +0000 |
commit | abdc99f21b542c4fea67030ddbd7166c9d1c6c63 (patch) | |
tree | 3e984e405adfdec189ca8a047daca5250737ffbf /indra/llcommon | |
parent | 34412f0530cf6a411b4de906a8e9da59cbcb3a85 (diff) |
Merge of QAR-1267 to trunk. This was a combo merge of QAR-1175 (maint-render-9) and QAR-1236 (dll-msvcrt-2)
svn merge -r 109838:112264 svn+ssh://svn.lindenlab.com/svn/linden/branches/maint-render/maint-render-9-merge-r109833
Diffstat (limited to 'indra/llcommon')
-rw-r--r-- | indra/llcommon/llapr.cpp | 502 | ||||
-rw-r--r-- | indra/llcommon/llapr.h | 124 | ||||
-rw-r--r-- | indra/llcommon/llcrc.cpp | 4 | ||||
-rw-r--r-- | indra/llcommon/llerror.cpp | 123 | ||||
-rw-r--r-- | indra/llcommon/llerror.h | 36 | ||||
-rw-r--r-- | indra/llcommon/llfasttimer.h | 12 | ||||
-rw-r--r-- | indra/llcommon/llfixedbuffer.cpp | 7 | ||||
-rw-r--r-- | indra/llcommon/llfixedbuffer.h | 10 | ||||
-rw-r--r-- | indra/llcommon/llthread.cpp | 8 | ||||
-rw-r--r-- | indra/llcommon/llthread.h | 8 | ||||
-rw-r--r-- | indra/llcommon/llworkerthread.cpp | 18 | ||||
-rw-r--r-- | indra/llcommon/llworkerthread.h | 6 |
12 files changed, 704 insertions, 154 deletions
diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index 74d821c721..82530b1489 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -36,8 +36,10 @@ #include "llapr.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; +const S32 FULL_VOLATILE_APR_POOL = 1024 ; //number of references to LLVolatileAPRPool void ll_init_apr() { @@ -46,10 +48,15 @@ void ll_init_apr() // 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); } + + if(!LLAPRFile::sAPRFilePoolp) + { + LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool() ; + } } @@ -70,31 +77,127 @@ void ll_cleanup_apr() 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) +LLAPRPool::LLAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) { - mStatus = apr_pool_create(&mPool, parent); + mParent = parent ; + mReleasePoolFlag = releasePoolFlag ; + mMaxSize = size ; + mPool = NULL ; + + createAPRPool() ; +} + +LLAPRPool::~LLAPRPool() +{ + releaseAPRPool() ; +} - if(size > 0) //size is the number of blocks (which is usually 4K), NOT bytes. +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, size) ; + apr_allocator_max_free_set(allocator, mMaxSize) ; } } } -LLAPRPool::~LLAPRPool() +void LLAPRPool::releaseAPRPool() +{ + if(!mPool) + { + return ; + } + + if(!mParent || mReleasePoolFlag) + { + apr_pool_destroy(mPool) ; + mPool = NULL ; + } +} + +apr_pool_t* LLAPRPool::getAPRPool() { - apr_pool_destroy(mPool) ; + if(!mPool) + { + createAPRPool() ; + } + + return mPool ; +} +LLVolatileAPRPool::LLVolatileAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) + : LLAPRPool(parent, size, releasePoolFlag) +{ + mNumActiveRef = 0 ; + mNumTotalRef = 0 ; } +apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool() +{ + mNumTotalRef++ ; + mNumActiveRef++ ; + return getAPRPool() ; +} + +void LLVolatileAPRPool::clearVolatileAPRPool() +{ + 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 // @@ -133,9 +236,8 @@ void LLScopedLock::unlock() } } -// -// Misc functions -// +//--------------------------------------------------------------------- + bool ll_apr_warn_status(apr_status_t status) { if(APR_SUCCESS == status) return false; @@ -151,55 +253,110 @@ void ll_apr_assert_status(apr_status_t status) llassert(ll_apr_warn_status(status) == false); } -// File I/O -apr_file_t* ll_apr_file_open(const std::string& filename, apr_int32_t flags, S32* sizep, apr_pool_t* pool) +//--------------------------------------------------------------------- +// +// LLAPRFile functions +// +LLAPRFile::LLAPRFile() +{ + mFile = NULL ; + mCurrentFilePoolp = NULL ; +} +LLAPRFile::~LLAPRFile() +{ + close() ; +} + +apr_status_t LLAPRFile::close() +{ + apr_status_t ret = APR_SUCCESS ; + if(mFile) + { + ret = apr_file_close(mFile); + mFile = NULL ; + } + + if(mCurrentFilePoolp) + { + mCurrentFilePoolp->clearVolatileAPRPool() ; + mCurrentFilePoolp = NULL ; + } + + return ret ; +} + +apr_status_t LLAPRFile::open(LLVolatileAPRPool* pool, const std::string& filename, apr_int32_t flags, S32* sizep) +{ + apr_status_t s ; + s = open(filename, flags, pool ? pool->getVolatileAPRPool() : NULL, sizep) ; + + if(!mCurrentFilePoolp) + { + mCurrentFilePoolp = pool ; + + if(!mFile) + { + close() ; + } + } + + return s ; +} +apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, apr_pool_t* pool, S32* sizep) { - apr_file_t* apr_file; apr_status_t s; - if (pool == NULL) pool = gAPRPoolp; - s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, pool); - if (s != APR_SUCCESS) + + //check if already open some file + llassert_always(!mFile) ; + llassert_always(!mCurrentFilePoolp) ; + + s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, getAPRFilePool(pool)); + if (s != APR_SUCCESS || !mFile) { + mFile = NULL ; + close() ; if (sizep) { *sizep = 0; } - return NULL; + return s; } if (sizep) { S32 file_size = 0; apr_off_t offset = 0; - if (apr_file_seek(apr_file, APR_END, &offset) == APR_SUCCESS) + if (apr_file_seek(mFile, APR_END, &offset) == APR_SUCCESS) { llassert_always(offset <= 0x7fffffff); file_size = (S32)offset; offset = 0; - apr_file_seek(apr_file, APR_SET, &offset); + apr_file_seek(mFile, APR_SET, &offset); } *sizep = file_size; } - return apr_file; + return s; } -apr_file_t* ll_apr_file_open(const std::string& filename, apr_int32_t flags, S32* sizep) -{ - return ll_apr_file_open(filename, flags, sizep, NULL); -} -apr_file_t* ll_apr_file_open(const std::string& filename, apr_int32_t flags, apr_pool_t* pool) -{ - return ll_apr_file_open(filename, flags, NULL, pool); -} -apr_file_t* ll_apr_file_open(const std::string& filename, apr_int32_t flags) -{ - return ll_apr_file_open(filename, flags, NULL, NULL); + +apr_pool_t* LLAPRFile::getAPRFilePool(apr_pool_t* pool) +{ + if(!pool) + { + mCurrentFilePoolp = sAPRFilePoolp ; + return mCurrentFilePoolp->getVolatileAPRPool() ; + } + + return pool ; } -S32 ll_apr_file_read(apr_file_t* apr_file, void *buf, S32 nbytes) +// File I/O +S32 LLAPRFile::read(void *buf, S32 nbytes) { + llassert_always(mFile) ; + apr_size_t sz = nbytes; - apr_status_t s = apr_file_read(apr_file, buf, &sz); + apr_status_t s = apr_file_read(mFile, buf, &sz); if (s != APR_SUCCESS) { return 0; @@ -211,165 +368,273 @@ S32 ll_apr_file_read(apr_file_t* apr_file, void *buf, S32 nbytes) } } -S32 ll_apr_file_read_ex(const std::string& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes) +S32 LLAPRFile::write(const void *buf, S32 nbytes) { - if (pool == NULL) pool = gAPRPoolp; - apr_file_t* filep = ll_apr_file_open(filename, APR_READ|APR_BINARY, pool); - if (!filep) + llassert_always(mFile) ; + + apr_size_t sz = nbytes; + apr_status_t s = apr_file_write(mFile, buf, &sz); + if (s != APR_SUCCESS) { return 0; } - S32 off; - if (offset < 0) - off = ll_apr_file_seek(filep, APR_END, 0); else - off = ll_apr_file_seek(filep, APR_SET, offset); - S32 bytes_read; - if (off < 0) { - bytes_read = 0; + llassert_always(sz <= 0x7fffffff); + return (S32)sz; } - else +} + +S32 LLAPRFile::seek(apr_seek_where_t where, S32 offset) +{ + return LLAPRFile::seek(mFile, where, 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) { - bytes_read = ll_apr_file_read(filep, buf, nbytes ); + ret = apr_file_close(file_handle); + file_handle = NULL ; } - apr_file_close(filep); - return bytes_read; + if(pool) + { + pool->clearVolatileAPRPool() ; + } + + return ret ; } -S32 ll_apr_file_write(apr_file_t* apr_file, const void *buf, S32 nbytes) +//static +apr_file_t* LLAPRFile::open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags) { - apr_size_t sz = nbytes; - apr_status_t s = apr_file_write(apr_file, buf, &sz); + 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) + { + 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) +{ + if(!file_handle) + { + return -1 ; + } + + apr_status_t s; + apr_off_t apr_offset; + if (offset >= 0) + { + apr_offset = (apr_off_t)offset; + s = apr_file_seek(file_handle, where, &apr_offset); + } + else + { + apr_offset = 0; + s = apr_file_seek(file_handle, APR_END, &apr_offset); + } if (s != APR_SUCCESS) { + return -1; + } + else + { + llassert_always(apr_offset <= 0x7fffffff); + return (S32)apr_offset; + } +} + +//static +S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool) +{ + //***************************************** + apr_file_t* file_handle = open(filename, pool, APR_READ|APR_BINARY); + //***************************************** + if (!file_handle) + { return 0; } + + S32 off; + if (offset < 0) + off = LLAPRFile::seek(file_handle, APR_END, 0); else + off = LLAPRFile::seek(file_handle, APR_SET, offset); + + apr_size_t bytes_read; + if (off < 0) { - llassert_always(sz <= 0x7fffffff); - return (S32)sz; + bytes_read = 0; } + else + { + bytes_read = nbytes ; + apr_status_t s = apr_file_read(file_handle, buf, &bytes_read); + if (s != APR_SUCCESS) + { + bytes_read = 0; + } + else + { + llassert_always(bytes_read <= 0x7fffffff); + } + } + + //***************************************** + close(file_handle, pool) ; + //***************************************** + return (S32)bytes_read; } -S32 ll_apr_file_write_ex(const std::string& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes) +//static +S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool) { - if (pool == NULL) pool = gAPRPoolp; apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY; if (offset < 0) { flags |= APR_APPEND; offset = 0; } - apr_file_t* filep = ll_apr_file_open(filename, flags, pool); - if (!filep) + + //***************************************** + apr_file_t* file_handle = open(filename, pool, flags); + //***************************************** + if (!file_handle) { return 0; } + if (offset > 0) { - offset = ll_apr_file_seek(filep, APR_SET, offset); + offset = LLAPRFile::seek(file_handle, APR_SET, offset); } - S32 bytes_written; + + apr_size_t bytes_written; if (offset < 0) { bytes_written = 0; } else { - bytes_written = ll_apr_file_write(filep, buf, nbytes ); + bytes_written = nbytes ; + apr_status_t s = apr_file_write(file_handle, buf, &bytes_written); + if (s != APR_SUCCESS) + { + bytes_written = 0; + } + else + { + llassert_always(bytes_written <= 0x7fffffff); + } } - apr_file_close(filep); - return bytes_written; -} + //***************************************** + LLAPRFile::close(file_handle, pool); + //***************************************** -S32 ll_apr_file_seek(apr_file_t* apr_file, apr_seek_where_t where, S32 offset) -{ - apr_status_t s; - apr_off_t apr_offset; - if (offset >= 0) - { - apr_offset = (apr_off_t)offset; - s = apr_file_seek(apr_file, where, &apr_offset); - } - else - { - apr_offset = 0; - s = apr_file_seek(apr_file, APR_END, &apr_offset); - } - if (s != APR_SUCCESS) - { - return -1; - } - else - { - llassert_always(apr_offset <= 0x7fffffff); - return (S32)apr_offset; - } + return (S32)bytes_written; } -bool ll_apr_file_remove(const std::string& filename, apr_pool_t* pool) +//static +bool LLAPRFile::remove(const std::string& filename, LLVolatileAPRPool* pool) { apr_status_t s; - if (pool == NULL) pool = gAPRPoolp; - 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) { - LL_DEBUGS("APR") << "ll_apr_file_remove failed on file: " << filename << LL_ENDL; + LL_DEBUGS("APR") << "LLAPRFile::remove failed on file: " << filename << LL_ENDL; ll_apr_warn_status(s); return false; } return true; } -bool ll_apr_file_rename(const std::string& filename, const std::string& newname, apr_pool_t* pool) +//static +bool LLAPRFile::rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool) { apr_status_t s; - if (pool == NULL) pool = gAPRPoolp; - 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) { - LL_DEBUGS("APR") << "ll_apr_file_rename failed on file: " << filename << LL_ENDL; + LL_DEBUGS("APR") << "LLAPRFile::rename failed on file: " << filename << LL_ENDL; ll_apr_warn_status(s); return false; } return true; } -bool ll_apr_file_exists(const std::string& filename, apr_pool_t* pool) +//static +bool LLAPRFile::isExist(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags) { apr_file_t* apr_file; apr_status_t s; - if (pool == NULL) pool = gAPRPoolp; - s = apr_file_open(&apr_file, filename.c_str(), APR_READ, 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 || !apr_file) { + pool->clearVolatileAPRPool() ; return false; } else { - apr_file_close(apr_file); + apr_file_close(apr_file) ; + pool->clearVolatileAPRPool() ; return true; } } -S32 ll_apr_file_size(const std::string& filename, apr_pool_t* pool) +//static +S32 LLAPRFile::size(const std::string& filename, LLVolatileAPRPool* pool) { apr_file_t* apr_file; apr_finfo_t info; apr_status_t s; - if (pool == NULL) pool = gAPRPoolp; - s = apr_file_open(&apr_file, 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 || !apr_file) - { + { + pool->clearVolatileAPRPool() ; + return 0; } else { - apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, apr_file); - apr_file_close(apr_file); + apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, apr_file); + + apr_file_close(apr_file) ; + pool->clearVolatileAPRPool() ; + if (s == APR_SUCCESS) { return (S32)info.size; @@ -381,31 +646,42 @@ S32 ll_apr_file_size(const std::string& filename, apr_pool_t* pool) } } -bool ll_apr_dir_make(const std::string& dirname, apr_pool_t* pool) +//static +bool LLAPRFile::makeDir(const std::string& dirname, LLVolatileAPRPool* pool) { apr_status_t s; - if (pool == NULL) pool = gAPRPoolp; - 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_DEBUGS("APR") << "ll_apr_dir_make failed on file: " << dirname << LL_ENDL; + LL_DEBUGS("APR") << "LLAPRFile::makeDir failed on file: " << dirname << LL_ENDL; ll_apr_warn_status(s); return false; } return true; } -bool ll_apr_dir_remove(const std::string& dirname, apr_pool_t* pool) +//static +bool LLAPRFile::removeDir(const std::string& dirname, LLVolatileAPRPool* pool) { apr_status_t s; - if (pool == NULL) pool = gAPRPoolp; - 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) { - LL_DEBUGS("APR") << "ll_apr_dir_remove failed on file: " << dirname << LL_ENDL; + LL_DEBUGS("APR") << "LLAPRFile::removeDir failed on file: " << dirname << LL_ENDL; ll_apr_warn_status(s); return false; } return true; } - +// +//end of static components of LLAPRFile +//******************************************************************************************************************************* +// diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index b8723562d7..44ad2dd50f 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -61,18 +61,51 @@ void ll_init_apr(); */ void ll_cleanup_apr(); +// +//LL apr_pool +//manage apr_pool_t, destroy allocated apr_pool in the destruction function. +// class LLAPRPool { public: - LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0) ; + LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE) ; ~LLAPRPool() ; - apr_pool_t* getAPRPool() {return mPool ; } + 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 LLVolatileAPRPool : public LLAPRPool +{ +public: + LLVolatileAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE); + ~LLVolatileAPRPool(){} + + apr_pool_t* getVolatileAPRPool() ; + + void clearVolatileAPRPool() ; + + BOOL isFull() ; + BOOL isEmpty() {return !mNumActiveRef ;} private: - apr_pool_t* mPool ; - apr_status_t mStatus ; + 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. } ; /** @@ -145,24 +178,71 @@ typedef LLAtomic32<S32> LLAtomicS32; #define LL_APR_WB (APR_CREATE|APR_TRUNCATE|APR_WRITE|APR_BINARY) // "wb" #define LL_APR_RPB (APR_READ|APR_WRITE|APR_BINARY) // "r+b" #define LL_APR_WPB (APR_CREATE|APR_TRUNCATE|APR_READ|APR_WRITE|APR_BINARY) // "w+b" -apr_file_t* ll_apr_file_open(const std::string& filename, apr_int32_t flags, S32* sizep, apr_pool_t* pool); -apr_file_t* ll_apr_file_open(const std::string& filename, apr_int32_t flags, S32* sizep); -apr_file_t* ll_apr_file_open(const std::string& filename, apr_int32_t flags, apr_pool_t* pool); -apr_file_t* ll_apr_file_open(const std::string& filename, apr_int32_t flags); -// Returns actual offset, -1 if seek fails -S32 ll_apr_file_seek(apr_file_t* apr_file, apr_seek_where_t where, S32 offset); -// Returns bytes read/written, 0 if read/write fails: -S32 ll_apr_file_read(apr_file_t* apr_file, void* buf, S32 nbytes); -S32 ll_apr_file_read_ex(const std::string& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes); -S32 ll_apr_file_write(apr_file_t* apr_file, const void* buf, S32 nbytes); -S32 ll_apr_file_write_ex(const std::string& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes); -// returns false if failure: -bool ll_apr_file_remove(const std::string& filename, apr_pool_t* pool = NULL); -bool ll_apr_file_rename(const std::string& filename, const std::string& newname, apr_pool_t* pool = NULL); -bool ll_apr_file_exists(const std::string& filename, apr_pool_t* pool = NULL); -S32 ll_apr_file_size(const std::string& filename, apr_pool_t* pool = NULL); -bool ll_apr_dir_make(const std::string& dirname, apr_pool_t* pool = NULL); -bool ll_apr_dir_remove(const std::string& dirname, apr_pool_t* pool = NULL); + +// +//apr_file manager +//which: 1)only keeps one file open; +// 2)closes the open file in the destruction function +// 3)informs the apr_pool to clean the memory when the file is closed. +//Note: please close an open file at the earliest convenience. +// especially do not put some time-costly operations between open() and close(). +// otherwise it might lock the APRFilePool. +//there are two different apr_pools the APRFile can use: +// 1, a temperary pool passed to an APRFile function, which is used within this function and only once. +// 2, a global pool. +// +class LLAPRFile +{ +private: + apr_file_t* mFile ; + LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool. + +public: + LLAPRFile() ; + ~LLAPRFile() ; + + apr_status_t open(LLVolatileAPRPool* pool, const std::string& filename, apr_int32_t flags, S32* sizep = NULL); + apr_status_t open(const std::string& filename, apr_int32_t flags, apr_pool_t* pool = NULL, S32* sizep = NULL); + apr_status_t close() ; + + // Returns actual offset, -1 if seek fails + S32 seek(apr_seek_where_t where, S32 offset); + apr_status_t eof() { return apr_file_eof(mFile);} + + // Returns bytes read/written, 0 if read/write fails: + S32 read(void* buf, S32 nbytes); + S32 write(const void* buf, S32 nbytes); + + 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, 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, LLVolatileAPRPool* pool = NULL); + static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); +//******************************************************************************************************************************* +}; /** * @brief Function which approprately logs error or remains quiet on diff --git a/indra/llcommon/llcrc.cpp b/indra/llcommon/llcrc.cpp index ad4211f9e8..7f183dc9ae 100644 --- a/indra/llcommon/llcrc.cpp +++ b/indra/llcommon/llcrc.cpp @@ -197,6 +197,10 @@ void LLCRC::update(const std::string& filename) update(data, nread); delete[] data; } + else + { + fclose(fp); + } } } diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 2943d7b288..5e520afab9 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -990,6 +990,38 @@ namespace LLError return new std::ostringstream; } + + void Log::flush(std::ostringstream* out, char* message) + { + LogLock lock; + if (!lock.ok()) + { + return; + } + + if(strlen(out->str().c_str()) < 128) + { + strcpy(message, out->str().c_str()); + } + else + { + strncpy(message, out->str().c_str(), 127); + message[127] = '\0' ; + } + + Globals& g = Globals::get(); + if (out == &g.messageStream) + { + g.messageStream.clear(); + g.messageStream.str(""); + g.messageStreamInUse = false; + } + else + { + delete out; + } + return ; + } void Log::flush(std::ostringstream* out, const CallSite& site) { @@ -1205,3 +1237,94 @@ namespace LLError } } +namespace LLError +{ + char** LLCallStacks::sBuffer = NULL ; + S32 LLCallStacks::sIndex = 0 ; + + //static + void LLCallStacks::push(const char* function, const int line) + { + if(!sBuffer) + { + sBuffer = new char*[512] ; + sBuffer[0] = new char[512 * 128] ; + for(S32 i = 1 ; i < 512 ; i++) + { + sBuffer[i] = sBuffer[i-1] + 128 ; + } + sIndex = 0 ; + } + + if(sIndex > 511) + { + clear() ; + } + + strcpy(sBuffer[sIndex], function) ; + sprintf(sBuffer[sIndex] + strlen(function), " line: %d ", line) ; + sIndex++ ; + + return ; + } + + //static + std::ostringstream* LLCallStacks::insert(const char* function, const int line) + { + std::ostringstream* _out = LLError::Log::out(); + *_out << function << " line " << line << " " ; + + return _out ; + } + + //static + void LLCallStacks::end(std::ostringstream* _out) + { + if(!sBuffer) + { + sBuffer = new char*[512] ; + sBuffer[0] = new char[512 * 128] ; + for(S32 i = 1 ; i < 512 ; i++) + { + sBuffer[i] = sBuffer[i-1] + 128 ; + } + sIndex = 0 ; + } + + if(sIndex > 511) + { + clear() ; + } + + LLError::Log::flush(_out, sBuffer[sIndex++]) ; + } + + //static + void LLCallStacks::print() + { + if(sIndex > 0) + { + llinfos << " ************* PRINT OUT LL CALL STACKS ************* " << llendl ; + while(sIndex > 0) + { + sIndex-- ; + llinfos << sBuffer[sIndex] << llendl ; + } + llinfos << " *************** END OF LL CALL STACKS *************** " << llendl ; + } + + if(sBuffer) + { + delete[] sBuffer[0] ; + delete[] sBuffer ; + sBuffer = NULL ; + } + } + + //static + void LLCallStacks::clear() + { + sIndex = 0 ; + } +} + diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index e39d19741b..6794be4904 100644 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -38,6 +38,7 @@ #include <typeinfo> #include "llerrorlegacy.h" +#include "stdtypes.h" /* Error Logging Facility @@ -135,6 +136,7 @@ namespace LLError public: static bool shouldLog(CallSite&); static std::ostringstream* out(); + static void flush(std::ostringstream* out, char* message) ; static void flush(std::ostringstream*, const CallSite&); }; @@ -179,9 +181,41 @@ namespace LLError class NoClassInfo { }; // used to indicate no class info known for logging -} + //LLCallStacks keeps track of call stacks and output the call stacks to log file + //when LLAppViewer::handleViewerCrash() is triggered. + // + //Note: to be simple, efficient and necessary to keep track of correct call stacks, + //LLCallStacks is designed not to be thread-safe. + //so try not to use it in multiple parallel threads at same time. + //Used in a single thread at a time is fine. + class LLCallStacks + { + private: + static char** sBuffer ; + static S32 sIndex ; + + public: + static void push(const char* function, const int line) ; + static std::ostringstream* insert(const char* function, const int line) ; + static void print() ; + static void clear() ; + static void end(std::ostringstream* _out) ; + }; +} +//this is cheaper than llcallstacks if no need to output other variables to call stacks. +#define llpushcallstacks LLError::LLCallStacks::push(__FUNCTION__, __LINE__) +#define llcallstacks \ + {\ + std::ostringstream* _out = LLError::LLCallStacks::insert(__FUNCTION__, __LINE__) ; \ + (*_out) +#define llcallstacksendl \ + LLError::End(); \ + LLError::LLCallStacks::end(_out) ; \ + } +#define llclearcallstacks LLError::LLCallStacks::clear() +#define llprintcallstacks LLError::LLCallStacks::print() /* Class type information for logging diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index 666aac70fc..94b51119e4 100644 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -71,6 +71,14 @@ public: FTM_UPDATE_AVATAR, // common render components + FTM_SHADOW_GEOMETRY, + FTM_SHADOW_RENDER, + FTM_SHADOW_TERRAIN, + FTM_SHADOW_AVATAR, + FTM_SHADOW_SIMPLE, + FTM_SHADOW_ALPHA, + FTM_SHADOW_TREE, + FTM_RENDER_GEOMETRY, FTM_RENDER_TERRAIN, FTM_RENDER_SIMPLE, @@ -186,11 +194,13 @@ public: enum { FTM_MAX_DEPTH = 64 }; public: + static LLFastTimer::EFastTimerType sCurType; + LLFastTimer(EFastTimerType type) { #if FAST_TIMER_ON mType = type; - + sCurType = type; // These don't get counted, because they use CPU clockticks //gTimerBins[gCurTimerBin]++; //LLTimer::sNumTimerCalls++; diff --git a/indra/llcommon/llfixedbuffer.cpp b/indra/llcommon/llfixedbuffer.cpp index d4cb604c5b..e9d6029378 100644 --- a/indra/llcommon/llfixedbuffer.cpp +++ b/indra/llcommon/llfixedbuffer.cpp @@ -33,6 +33,7 @@ #include "llfixedbuffer.h" LLFixedBuffer::LLFixedBuffer(const U32 max_lines) + : mMutex(NULL) { mMaxLines = max_lines; mTimer.reset(); @@ -47,9 +48,11 @@ LLFixedBuffer::~LLFixedBuffer() void LLFixedBuffer::clear() { + mMutex.lock() ; mLines.clear(); mAddTimes.clear(); mLineLengths.clear(); + mMutex.unlock() ; mTimer.reset(); } @@ -70,9 +73,11 @@ void LLFixedBuffer::addLine(const LLWString& line) removeExtraLines(); + mMutex.lock() ; mLines.push_back(line); mLineLengths.push_back((S32)line.length()); mAddTimes.push_back(mTimer.getElapsedTimeF32()); + mMutex.unlock() ; } @@ -86,10 +91,12 @@ void LLFixedBuffer::setMaxLines(S32 max_lines) void LLFixedBuffer::removeExtraLines() { + mMutex.lock() ; while ((S32)mLines.size() > llmax((S32)0, (S32)(mMaxLines - 1))) { mLines.pop_front(); mAddTimes.pop_front(); mLineLengths.pop_front(); } + mMutex.unlock() ; } diff --git a/indra/llcommon/llfixedbuffer.h b/indra/llcommon/llfixedbuffer.h index 5d84cd96cb..992a024df1 100644 --- a/indra/llcommon/llfixedbuffer.h +++ b/indra/llcommon/llfixedbuffer.h @@ -37,6 +37,7 @@ #include <deque> #include <string> #include "llstring.h" +#include "llthread.h" // Fixed size buffer for console output and other things. @@ -53,14 +54,19 @@ public: std::deque<S32> mLineLengths; void clear(); // Clear the buffer, and reset it. - virtual void addLine(const std::string& utf8line); - virtual void addLine(const LLWString& line); + + //do not make these two "virtual" + void addLine(const std::string& utf8line); + void addLine(const LLWString& line); // Get lines currently in the buffer, up to max_size chars, max_length lines char *getLines(U32 max_size = 0, U32 max_length = 0); void setMaxLines(S32 max_lines); protected: virtual void removeExtraLines(); + +protected: + LLMutex mMutex ; }; const U32 FIXED_BUF_MAX_LINE_LEN = 255; // Not including termnating 0 diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index 01647c671b..920d8c0977 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -102,12 +102,20 @@ LLThread::LLThread(const std::string& name, apr_pool_t *poolp) : 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() diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index d48d1ba7fa..c8c9fd4eec 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -83,7 +83,8 @@ public: void start(void); apr_pool_t *getAPRPool() { return mAPRPoolp; } - + LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; } + private: BOOL mPaused; @@ -99,6 +100,11 @@ protected: BOOL mIsLocalPool; EThreadStatus mStatus; + //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(); // virtual function overridden by subclass -- this will be called when the thread runs diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp index cdc7c02348..5dda600755 100644 --- a/indra/llcommon/llworkerthread.cpp +++ b/indra/llcommon/llworkerthread.cpp @@ -37,16 +37,18 @@ #include "llframecallbackmanager.h" #endif -BOOL LLWorkerClass::sDeleteLock = FALSE ; //============================================================================ // Run on MAIN thread LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded) : - LLQueuedThread(name, threaded), - mWorkerAPRPoolp(NULL) + LLQueuedThread(name, threaded) { - apr_pool_create(&mWorkerAPRPoolp, NULL); - mDeleteMutex = new LLMutex(getAPRPool()); + mDeleteMutex = new LLMutex(NULL); + + if(!mLocalAPRFilePoolp) + { + mLocalAPRFilePoolp = new LLVolatileAPRPool() ; + } } LLWorkerThread::~LLWorkerThread() @@ -96,7 +98,6 @@ S32 LLWorkerThread::update(U32 max_time_ms) { (*iter)->abortWork(false); } - LLWorkerClass::sDeleteLock = TRUE ; for (std::vector<LLWorkerClass*>::iterator iter = delete_list.begin(); iter != delete_list.end(); ++iter) { @@ -110,8 +111,7 @@ S32 LLWorkerThread::update(U32 max_time_ms) } delete *iter; } - LLWorkerClass::sDeleteLock = FALSE ; - // delete and aborted entries mean there's still work to do + // delete and aborted entries mean there's still work to do res += delete_list.size() + abort_list.size(); return res; } @@ -188,7 +188,7 @@ LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& na : mWorkerThread(workerthread), mWorkerClassName(name), mRequestHandle(LLWorkerThread::nullHandle()), - mMutex(workerthread->getWorkerAPRPool()), + mMutex(NULL), mWorkFlags(0) { if (!mWorkerThread) diff --git a/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h index 745310840b..19407f4463 100644 --- a/indra/llcommon/llworkerthread.h +++ b/indra/llcommon/llworkerthread.h @@ -38,6 +38,7 @@ #include <set> #include "llqueuedthread.h" +#include "llapr.h" #define USE_FRAME_CALLBACK_MANAGER 0 @@ -82,14 +83,11 @@ private: typedef std::list<LLWorkerClass*> delete_list_t; delete_list_t mDeleteList; LLMutex* mDeleteMutex; - apr_pool_t* mWorkerAPRPoolp; public: LLWorkerThread(const std::string& name, bool threaded = true); ~LLWorkerThread(); - apr_pool_t* getWorkerAPRPool() { return mWorkerAPRPoolp; } - /*virtual*/ S32 update(U32 max_time_ms); handle_t addWorkRequest(LLWorkerClass* workerclass, S32 param, U32 priority = PRIORITY_NORMAL); @@ -121,8 +119,6 @@ class LLWorkerClass friend class LLWorkerThread::WorkRequest; public: - static BOOL sDeleteLock ; -public: typedef LLWorkerThread::handle_t handle_t; enum FLAGS { |