summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/llapr.cpp502
-rw-r--r--indra/llcommon/llapr.h124
-rw-r--r--indra/llcommon/llcrc.cpp4
-rw-r--r--indra/llcommon/llerror.cpp123
-rw-r--r--indra/llcommon/llerror.h36
-rw-r--r--indra/llcommon/llfasttimer.h12
-rw-r--r--indra/llcommon/llfixedbuffer.cpp7
-rw-r--r--indra/llcommon/llfixedbuffer.h10
-rw-r--r--indra/llcommon/llthread.cpp8
-rw-r--r--indra/llcommon/llthread.h8
-rw-r--r--indra/llcommon/llworkerthread.cpp18
-rw-r--r--indra/llcommon/llworkerthread.h6
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
{