From f4ff1430f0d6ae7dd5a6be0bd665678b30a63aca Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Fri, 3 Dec 2010 22:16:16 -0700 Subject: first iteration of memory pool code --- indra/llcommon/llmemory.cpp | 955 ++++++++++++++++++++- indra/llcommon/llmemory.h | 174 +++- indra/llcommon/llsys.cpp | 8 +- indra/llcommon/llsys.h | 2 +- indra/llrender/llvertexbuffer.cpp | 9 +- indra/llxml/llcontrol.h | 3 +- indra/newview/app_settings/settings.xml | 22 + indra/newview/llappviewer.cpp | 128 ++- indra/newview/llappviewer.h | 10 +- indra/newview/lldynamictexture.cpp | 6 +- indra/newview/llfloatermemleak.cpp | 5 + indra/newview/llviewerdisplay.cpp | 7 +- indra/newview/llviewertexture.cpp | 12 +- indra/newview/llviewertexture.h | 2 +- indra/newview/llviewerwindow.cpp | 13 + indra/newview/pipeline.cpp | 22 +- indra/newview/pipeline.h | 5 +- .../newview/skins/default/xui/en/notifications.xml | 16 +- 18 files changed, 1342 insertions(+), 57 deletions(-) (limited to 'indra') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index a502d1a7eb..ca06589611 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -26,8 +26,9 @@ #include "linden_common.h" +#include "llthread.h" #if defined(LL_WINDOWS) -# include +//# include # include #elif defined(LL_DARWIN) # include @@ -38,11 +39,19 @@ #endif #include "llmemory.h" +#include "llsys.h" + //---------------------------------------------------------------------------- //static char* LLMemory::reserveMem = 0; +U32 LLMemory::sAvailPhysicalMemInKB = U32_MAX ; +U32 LLMemory::sMaxPhysicalMemInKB = 0; +U32 LLMemory::sAllocatedMemInKB = 0; +U32 LLMemory::sAllocatedPageSizeInKB = 0 ; +U32 LLMemory::sMaxHeapSizeInKB = U32_MAX ; +BOOL LLMemory::sEnableMemoryFailurePrevention = FALSE; //static void LLMemory::initClass() @@ -67,6 +76,131 @@ void LLMemory::freeReserve() reserveMem = NULL; } +//static +void LLMemory::initMaxHeapSizeGB(F32 max_heap_size_gb, BOOL prevent_heap_failure) +{ + sMaxHeapSizeInKB = (U32)(max_heap_size_gb * 1024 * 1024) ; + sEnableMemoryFailurePrevention = prevent_heap_failure ; +} + +//static +void LLMemory::updateMemoryInfo() +{ +#if LL_WINDOWS + HANDLE self = GetCurrentProcess(); + PROCESS_MEMORY_COUNTERS counters; + + if (!GetProcessMemoryInfo(self, &counters, sizeof(counters))) + { + llwarns << "GetProcessMemoryInfo failed" << llendl; + return ; + } + + sAllocatedMemInKB = (U32)(counters.WorkingSetSize / 1024) ; + sAllocatedPageSizeInKB = (U32)(counters.PagefileUsage / 1024) ; + sMaxPhysicalMemInKB = llmin(LLMemoryInfo::getAvailableMemoryKB() + sAllocatedMemInKB, sMaxHeapSizeInKB); + + if(sMaxPhysicalMemInKB > sAllocatedMemInKB) + { + sAvailPhysicalMemInKB = sMaxPhysicalMemInKB - sAllocatedMemInKB ; + } + else + { + sAvailPhysicalMemInKB = 0 ; + } +#else + //not valid for other systems for now. + sAllocatedMemInKB = (U32)(LLMemory::getCurrentRSS() / 1024) ; + sMaxPhysicalMemInKB = U32_MAX ; + sAvailPhysicalMemInKB = U32_MAX ; +#endif + + return ; +} + +// +//this function is to test if there is enough space with the size in the virtual address space. +//it does not do any real allocation +//if success, it returns the address where the memory chunk can fit in; +//otherwise it returns NULL. +// +//static +void* LLMemory::tryToAlloc(void* address, U32 size) +{ +#if LL_WINDOWS + address = VirtualAlloc(address, size, MEM_RESERVE | MEM_TOP_DOWN, PAGE_NOACCESS) ; + if(address) + { + if(!VirtualFree(address, 0, MEM_RELEASE)) + { + llerrs << "error happens when free some memory reservation." << llendl ; + } + } +#else +#endif + + return address ; +} + +//static +void LLMemory::logMemoryInfo(BOOL update) +{ + if(update) + { + updateMemoryInfo() ; + } + + llinfos << "Current allocated physical memory(KB): " << sAllocatedMemInKB << llendl ; + llinfos << "Current allocated page size (KB): " << sAllocatedPageSizeInKB << llendl ; + llinfos << "Current availabe physical memory(KB): " << sAvailPhysicalMemInKB << llendl ; + llinfos << "Current max usable memory(KB): " << sMaxPhysicalMemInKB << llendl ; +} + +//return 0: everything is normal; +//return 1: the memory pool is low, but not in danger; +//return -1: the memory pool is in danger, is about to crash. +//static +S32 LLMemory::isMemoryPoolLow() +{ + static const U32 LOW_MEMEOY_POOL_THRESHOLD_KB = 64 * 1024 ; //64 MB for emergency use + + if(!sEnableMemoryFailurePrevention) + { + return 0 ; //no memory failure prevention. + } + + if(sAvailPhysicalMemInKB < (LOW_MEMEOY_POOL_THRESHOLD_KB >> 2)) //out of physical memory + { + return -1 ; + } + + if(sAllocatedPageSizeInKB + (LOW_MEMEOY_POOL_THRESHOLD_KB >> 2) > sMaxHeapSizeInKB) //out of virtual address space. + { + return -1 ; + } + + return (S32)(sAvailPhysicalMemInKB < LOW_MEMEOY_POOL_THRESHOLD_KB || + sAllocatedPageSizeInKB + LOW_MEMEOY_POOL_THRESHOLD_KB > sMaxHeapSizeInKB) ; +} + +//static +U32 LLMemory::getAvailableMemKB() +{ + return sAvailPhysicalMemInKB ; +} + +//static +U32 LLMemory::getMaxMemKB() +{ + return sMaxPhysicalMemInKB ; +} + +//static +U32 LLMemory::getAllocatedMemKB() +{ + return sAllocatedMemInKB ; +} + void* ll_allocate (size_t size) { if (size == 0) @@ -221,3 +355,822 @@ U64 LLMemory::getCurrentRSS() } #endif + +//------------------------------------------------------------- +//class LLPrivateMemoryPool::LLMemoryBlock +//------------------------------------------------------------- +// +//each memory block could fit for two page sizes: 0.75 * mSlotSize, which starts from the beginning of the memory chunk and grow towards the end of the +//the block; another is mSlotSize, which starts from the end of the block and grows towards the beginning of the block. +// +LLPrivateMemoryPool::LLMemoryBlock::LLMemoryBlock() +{ + //empty +} + +LLPrivateMemoryPool::LLMemoryBlock::~LLMemoryBlock() +{ + //empty +} + +void LLPrivateMemoryPool::LLMemoryBlock::init(char* buffer, U32 buffer_size, U32 slot_size) +{ + mBuffer = buffer ; + mBufferSize = buffer_size ; + mSlotSize = slot_size ; + mTotalSlots = buffer_size / mSlotSize ; + llassert_always(mTotalSlots < 256) ; //max number is 256 + mAllocatedSlots = 0 ; + + //mark free bits + S32 usage_bit_len = (mTotalSlots + 31) / 32 ; + mDummySize = usage_bit_len - 1 ; + if(mDummySize > 0) //extra space to store mUsageBits + { + mTotalSlots -= (mDummySize * sizeof(mUsageBits) + mSlotSize - 1) / mSlotSize ; + usage_bit_len = (mTotalSlots + 31) / 32 ; + mDummySize = usage_bit_len - 1 ; + + if(mDummySize > 0) + { + mUsageBits = 0 ; + for(S32 i = 0 ; i < mDummySize ; i++) + { + *((U32*)mBuffer + i) = 0 ; + } + if(mTotalSlots & 31) + { + *((U32*)mBuffer + mDummySize - 1) = (0xffffffff << (mTotalSlots & 31)) ; + } + } + } + + if(mDummySize < 1) + { + mUsageBits = 0 ; + if(mTotalSlots & 31) + { + mUsageBits = (0xffffffff << (mTotalSlots & 31)) ; + } + } + + mSelf = NULL ; + mNext = NULL ; +} + +void LLPrivateMemoryPool::LLMemoryBlock::setBuffer(char* buffer, U32 buffer_size) +{ + mBuffer = buffer ; + mBufferSize = buffer_size ; + mTotalSlots = 0 ; //set the block is free. +} + +char* LLPrivateMemoryPool::LLMemoryBlock::allocate() +{ + llassert_always(mAllocatedSlots < mTotalSlots) ; + + //find a free slot + U32* bits = NULL ; + U32 k = 0 ; + if(mUsageBits != 0xffffffff) + { + bits = &mUsageBits ; + } + else if(mDummySize > 0)//go to extra space + { + for(S32 i = 0 ; i < mDummySize; i++) + { + if(*((U32*)mBuffer + i) != 0xffffffff) + { + bits = (U32*)mBuffer + i ; + k = i + 1 ; + break ; + } + } + } + S32 idx = 0 ; + U32 tmp = *bits ; + for(; tmp & 1 ; tmp >>= 1, idx++) ; + + //set the slot reserved + if(!idx) + { + *bits |= 1 ; + } + else + { + *bits |= (1 << idx) ; + } + + mAllocatedSlots++ ; + + return mBuffer + mDummySize * sizeof(U32) + (k * 32 + idx) * mSlotSize ; +} + +void LLPrivateMemoryPool::LLMemoryBlock::free(void* addr) +{ + U32 idx = ((char*) addr - mBuffer - mDummySize * sizeof(U32)) / mSlotSize ; + + U32* bits = &mUsageBits ; + if(idx > 32) + { + bits = (U32*)mBuffer + (idx - 32) / 32 ; + } + if(idx & 31) + { + *bits &= ~(1 << (idx & 31)) ; + } + else + { + *bits &= ~1 ; + } + + mAllocatedSlots-- ; +} + +//------------------------------------------------------------------- +//class LLMemoryChunk +//-------------------------------------------------------------------- +LLPrivateMemoryPool::LLMemoryChunk::LLMemoryChunk() +{ + //empty +} + +LLPrivateMemoryPool::LLMemoryChunk::~LLMemoryChunk() +{ + //empty +} + +void LLPrivateMemoryPool::LLMemoryChunk::init(char* buffer, U32 buffer_size, U32 min_slot_size, U32 max_slot_size, U32 min_block_size, U32 max_block_size) +{ + mBuffer = buffer ; + mBufferSize = buffer_size ; + + mMetaBuffer = mBuffer + sizeof(LLMemoryChunk) ; + + mMinBlockSize = min_block_size; + mMaxBlockSize = max_block_size; + mMinSlotSize = min_slot_size; + mBlockLevels = max_block_size / min_block_size ; + mPartitionLevels = mMaxBlockSize / mMinBlockSize + 1 ; + + S32 max_num_blocks = (buffer_size - sizeof(LLMemoryChunk) - mBlockLevels * sizeof(LLMemoryBlock*) - mPartitionLevels * sizeof(LLMemoryBlock*)) / + (mMinBlockSize + sizeof(LLMemoryBlock)) ; + //meta data space + mBlocks = (LLMemoryBlock*)mMetaBuffer ; + mAvailBlockList = (LLMemoryBlock**)((char*)mBlocks + sizeof(LLMemoryBlock) * max_num_blocks) ; + mFreeSpaceList = (LLMemoryBlock**)((char*)mAvailBlockList + sizeof(LLMemoryBlock*) * mBlockLevels) ; + + //data buffer + mDataBuffer = (char*)mFreeSpaceList + sizeof(LLMemoryBlock*) * mPartitionLevels ; + + //init + for(U32 i = 0 ; i < mBlockLevels; i++) + { + mAvailBlockList[i] = NULL ; + } + for(U32 i = 0 ; i < mPartitionLevels ; i++) + { + mFreeSpaceList[i] = NULL ; + } + + mBlocks[0].setBuffer(mDataBuffer, buffer_size - (mDataBuffer - mBuffer)) ; + addToFreeSpace(&mBlocks[0]) ; + + mKey = (U32)mBuffer ; + mNext = NULL ; + mPrev = NULL ; +} + +//static +U32 LLPrivateMemoryPool::LLMemoryChunk::getMaxOverhead(U32 data_buffer_size, U32 min_page_size) +{ + return 2048 + + sizeof(LLMemoryBlock) * (data_buffer_size / min_page_size) ; +} + +char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) +{ + char* p = NULL ; + U32 blk_idx = size / mMinSlotSize ; + if(mMinSlotSize * blk_idx < size) + { + blk_idx++ ; + } + + //check if there is free block available + if(mAvailBlockList[blk_idx]) + { + LLMemoryBlock* blk = mAvailBlockList[blk_idx] ; + p = blk->allocate() ; + + if(blk->isFull()) + { + //removeFromFreelist + popAvailBlockList(blk_idx) ; + } + } + + //ask for a new block + if(!p) + { + LLMemoryBlock* blk = addBlock(blk_idx) ; + if(blk) + { + p = blk->allocate() ; + + if(blk->isFull()) + { + //removeFromFreelist + popAvailBlockList(blk_idx) ; + } + } + } + + //ask for space from higher level blocks + if(!p) + { + for(S32 i = blk_idx + 1 ; i < mBlockLevels; i++) + { + if(mAvailBlockList[i]) + { + LLMemoryBlock* blk = mAvailBlockList[i] ; + p = blk->allocate() ; + + if(blk->isFull()) + { + //removeFromFreelist + popAvailBlockList(i) ; + } + break ; + } + } + } + + return p ; +} + +void LLPrivateMemoryPool::LLMemoryChunk::free(void* addr) +{ + LLMemoryBlock* blk = (LLMemoryBlock*)(mMetaBuffer + (((char*)addr - mDataBuffer) / mMinBlockSize) * sizeof(LLMemoryBlock)) ; + blk = blk->mSelf ; + + bool was_full = blk->isFull() ; + blk->free(addr) ; + + if(blk->empty()) + { + removeBlock(blk) ; + } + else if(was_full) + { + addToAvailBlockList(blk) ; + } +} + +LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::addBlock(U32 blk_idx) +{ + U32 slot_size = mMinSlotSize * (blk_idx + 1) ; + U32 preferred_block_size = llmax(mMinBlockSize, slot_size * 32) ; + preferred_block_size = llmin(preferred_block_size, mMaxBlockSize) ; + + U32 idx = preferred_block_size / mMinBlockSize ; + preferred_block_size = idx * mMinBlockSize ; //round to integer times of mMinBlockSize. + + LLMemoryBlock* blk = NULL ; + + if(mFreeSpaceList[idx])//if there is free slot for blk_idx + { + blk = createNewBlock(&mFreeSpaceList[idx], preferred_block_size, slot_size, blk_idx) ; + } + else if(mFreeSpaceList[mPartitionLevels - 1]) //search free pool + { + blk = createNewBlock(&mFreeSpaceList[mPartitionLevels - 1], preferred_block_size, slot_size, blk_idx) ; + } + else //search for other non-preferred but enough space slot. + { + for(U32 i = idx - 1 ; i >= 0 ; i--) //search the small slots first + { + if(mFreeSpaceList[i]) + { + //create a NEW BLOCK THERE. + if(mFreeSpaceList[i]->getBufferSize() >= slot_size) //at least there is space for one slot. + { + blk = createNewBlock(&mFreeSpaceList[i], preferred_block_size, slot_size, blk_idx) ; + } + break ; + } + } + + if(!blk) + { + for(U16 i = idx + 1 ; i < mPartitionLevels - 1; i++) //search the large slots + { + if(mFreeSpaceList[i]) + { + //create a NEW BLOCK THERE. + blk = createNewBlock(&mFreeSpaceList[i], preferred_block_size, slot_size, blk_idx) ; + break ; + } + } + } + } + + return blk ; +} + +LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::createNewBlock(LLMemoryBlock** cur_idxp, U32 buffer_size, U32 slot_size, U32 blk_idx) +{ + LLMemoryBlock* blk = *cur_idxp ; + + buffer_size = llmin(buffer_size, blk->getBufferSize()) ; + U32 new_free_blk_size = blk->getBufferSize() - buffer_size ; + if(new_free_blk_size < mMinBlockSize) //can not partition the memory into size smaller than mMinBlockSize + { + buffer_size += new_free_blk_size ; + new_free_blk_size = 0 ; + } + blk->init(blk->getBuffer(), buffer_size, slot_size) ; + + if(new_free_blk_size > 0) //cur_idx still has free space + { + LLMemoryBlock* next_blk = blk + (buffer_size / mMinBlockSize) ; + next_blk->setBuffer(blk->getBuffer() + buffer_size, new_free_blk_size) ; + + if(new_free_blk_size > mMaxBlockSize) //stays in the free pool + { + next_blk->mPrev = NULL ; + next_blk->mNext = blk->mNext ; + if(next_blk->mNext) + { + next_blk->mNext->mPrev = next_blk ; + } + *cur_idxp = next_blk ; + } + else + { + *cur_idxp = blk->mNext ; //move to the next slot + (*cur_idxp)->mPrev = NULL ; + + addToFreeSpace(next_blk) ; + } + } + else //move to the next block + { + *cur_idxp = blk->mNext ; + (*cur_idxp)->mPrev = NULL ; + } + + //insert to the available block list... + blk->mNext = NULL ; + blk->mPrev = NULL ; + blk->mSelf = blk ; + mAvailBlockList[blk_idx] = blk ; + + //mark the address map + U32 end = (buffer_size / mMinBlockSize) ; + for(U32 i = 1 ; i < end ; i++) + { + (blk + i)->mSelf = blk ; + } + + return blk ; +} + +void LLPrivateMemoryPool::LLMemoryChunk::removeBlock(LLMemoryBlock* blk) +{ + //remove from the available block list + if(blk->mPrev) + { + blk->mPrev->mNext = blk->mNext ; + } + if(blk->mNext) + { + blk->mNext->mPrev = blk->mPrev ; + } + + //mark it free + blk->setBuffer(blk->getBuffer(), blk->getBufferSize()) ; + + //merge blk with neighbors if possible + if(blk->getBuffer() > mDataBuffer) //has the left neighbor + { + if((blk - 1)->mSelf->isFree()) + { + removeFromFreeSpace((blk - 1)->mSelf); + (blk - 1)->mSelf->setBuffer((blk-1)->mSelf->getBuffer(), (blk-1)->mSelf->getBufferSize() + blk->getBufferSize()) ; + blk = (blk - 1)->mSelf ; + } + } + if(blk->getBuffer() + blk->getBufferSize() < mBuffer + mBufferSize) //has the right neighbor + { + U32 d = blk->getBufferSize() / mMinBlockSize ; + if((blk + d)->isFree()) + { + removeFromFreeSpace(blk + d) ; + blk->setBuffer(blk->getBuffer(), blk->getBufferSize() + (blk + d)->getBufferSize()) ; + } + } + + addToFreeSpace(blk) ; + + return ; +} + +//the top block in the list is full, pop it out of the list +void LLPrivateMemoryPool::LLMemoryChunk::popAvailBlockList(U32 blk_idx) +{ + if(mAvailBlockList[blk_idx]) + { + LLMemoryBlock* next = mAvailBlockList[blk_idx]->mNext ; + next->mPrev = NULL ; + mAvailBlockList[blk_idx]->mNext = NULL ; + mAvailBlockList[blk_idx] = next ; + } +} + +void LLPrivateMemoryPool::LLMemoryChunk::addToFreeSpace(LLMemoryBlock* blk) +{ + U16 free_idx = blk->getBufferSize() / mMinBlockSize ; + (blk + free_idx)->mSelf = blk ; //mark the end pointing back to the head. + free_idx = llmin(free_idx, (U16)(mPartitionLevels - 1)) ; + + blk->mNext = mFreeSpaceList[free_idx] ; + if(mFreeSpaceList[free_idx]) + { + mFreeSpaceList[free_idx]->mPrev = blk ; + } + mFreeSpaceList[free_idx] = blk ; + blk->mPrev = NULL ; + blk->mSelf = blk ; + + return ; +} + +void LLPrivateMemoryPool::LLMemoryChunk::removeFromFreeSpace(LLMemoryBlock* blk) +{ + U16 free_idx = blk->getBufferSize() / mMinBlockSize ; + free_idx = llmin(free_idx, (U16)(mPartitionLevels - 1)) ; + + if(mFreeSpaceList[free_idx] == blk) + { + mFreeSpaceList[free_idx] = blk->mNext ; + } + if(blk->mPrev) + { + blk->mPrev->mNext = blk->mNext ; + } + if(blk->mNext) + { + blk->mNext->mPrev = blk->mPrev ; + } + + return ; +} + +void LLPrivateMemoryPool::LLMemoryChunk::addToAvailBlockList(LLMemoryBlock* blk) +{ + U32 blk_idx = blk->getSlotSize() / mMinSlotSize ; + + blk->mNext = mAvailBlockList[blk_idx] ; + if(blk->mNext) + { + blk->mNext->mPrev = blk ; + } + blk->mPrev = NULL ; + + return ; +} + +//------------------------------------------------------------------- +//class LLPrivateMemoryPool +//-------------------------------------------------------------------- +LLPrivateMemoryPool::LLPrivateMemoryPool(U32 max_size, bool threaded) : + mMutexp(NULL), + mMaxPoolSize(max_size), + mReservedPoolSize(0) +{ + if(threaded) + { + mMutexp = new LLMutex(NULL) ; + } + + for(S32 i = 0 ; i < SUPER_ALLOCATION ; i++) + { + mChunkList[i] = NULL ; + } + + mChunkVectorCapacity = 128 ; + mChunks.resize(mChunkVectorCapacity) ; //at most 128 chunks + mNumOfChunks = 0 ; +} + +LLPrivateMemoryPool::~LLPrivateMemoryPool() +{ + destroyPool(); + delete mMutexp ; +} + +char* LLPrivateMemoryPool::allocate(U32 size) +{ + const static U32 MAX_BLOCK_SIZE = 4 * 1024 * 1024 ; //4MB + + //if the asked size larger than MAX_BLOCK_SIZE, fetch from heap directly, the pool does not manage it + if(size >= MAX_BLOCK_SIZE) + { + return new char[size] ; + } + + char* p = NULL ; + + //find the appropriate chunk + S32 chunk_idx = getChunkIndex(size) ; + + lock() ; + + LLMemoryChunk* chunk = mChunkList[chunk_idx]; + while(chunk) + { + if(p = chunk->allocate(size)) + { + break ; + } + chunk = chunk->mNext ; + } + + //fetch new memory chunk + if(!p) + { + chunk = addChunk(chunk_idx) ; + p = chunk->allocate(size) ; + } + + unlock() ; + + return p ; +} + +void LLPrivateMemoryPool::free(void* addr) +{ + lock() ; + + LLMemoryChunk* chunk = mChunks[findChunk((char*)addr)] ; + if(!chunk) + { + delete[] (char*)addr ; //release from heap + } + else + { + chunk->free(addr) ; + + if(chunk->empty()) + { + removeChunk(chunk) ; + } + } + + unlock() ; +} + +void LLPrivateMemoryPool::dump() +{ +} + +void LLPrivateMemoryPool::lock() +{ + if(mMutexp) + { + mMutexp->lock() ; + } +} + +void LLPrivateMemoryPool::unlock() +{ + if(mMutexp) + { + mMutexp->unlock() ; + } +} + +S32 LLPrivateMemoryPool::getChunkIndex(U32 size) +{ + if(size < 2048) + { + return 0 ; + } + else if(size < (512 << 10)) + { + return 1 ; + } + else + { + return 2 ; + } +} + +//destroy the entire pool +void LLPrivateMemoryPool::destroyPool() +{ + for(U16 i = 0 ; i < mNumOfChunks ; i++) + { + delete[] mChunks[i]->getBuffer() ; + } + mNumOfChunks = 0 ; + for(S32 i = 0 ; i < SUPER_ALLOCATION ; i++) + { + mChunkList[i] = NULL ; + } +} + +LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::addChunk(S32 chunk_index) +{ + static const U32 MIN_BLOCK_SIZES[SUPER_ALLOCATION] = {2 << 10, 32 << 10, 64 << 10} ; + static const U32 MAX_BLOCK_SIZES[SUPER_ALLOCATION] = {64 << 10, 1 << 20, 4 << 20} ; + static const U32 MIN_SLOT_SIZES[SUPER_ALLOCATION] = {8, 2 << 10, 512 << 10}; + static const U32 MAX_SLOT_SIZES[SUPER_ALLOCATION] = {(2 << 10) - 8, (512 - 2) << 10, 4 << 20}; + + U32 preferred_size ; + U32 overhead ; + if(chunk_index < LARGE_ALLOCATION) + { + preferred_size = (4 << 20) ; //4MB + overhead = LLMemoryChunk::getMaxOverhead(preferred_size, MIN_BLOCK_SIZES[chunk_index]) ; + } + else + { + preferred_size = (16 << 20) ; //16MB + overhead = LLMemoryChunk::getMaxOverhead(preferred_size, MIN_BLOCK_SIZES[chunk_index]) ; + } + char* buffer = new(std::nothrow) char[preferred_size + overhead] ; + if(!buffer) + { + return NULL ; + } + + LLMemoryChunk* chunk = new (buffer) LLMemoryChunk() ; + chunk->init(buffer, preferred_size + overhead, MIN_SLOT_SIZES[chunk_index], + MAX_SLOT_SIZES[chunk_index], MIN_BLOCK_SIZES[chunk_index], MAX_BLOCK_SIZES[chunk_index]) ; + + //add to the head of the linked list + chunk->mNext = mChunkList[chunk_index] ; + if(mChunkList[chunk_index]) + { + mChunkList[chunk_index]->mPrev = chunk ; + } + chunk->mPrev = NULL ; + mChunkList[chunk_index] = chunk ; + + //insert into the array + llassert_always(mNumOfChunks + 1 < mChunkVectorCapacity) ; + if(!mNumOfChunks) + { + mChunks[0] = chunk ; + } + else + { + U16 k ; + if(mChunks[0]->getBuffer() > chunk->getBuffer()) + { + k = 0 ; + } + else + { + k = findChunk(chunk->getBuffer()) + 1 ; + } + for(U16 i = mNumOfChunks ; i > k ; i++) + { + mChunks[i] = mChunks[i-1] ; + } + mChunks[k] = chunk ; + } + mNumOfChunks++; + + return chunk ; +} + +void LLPrivateMemoryPool::removeChunk(LLMemoryChunk* chunk) +{ + //remove from the linked list + if(chunk->mPrev) + { + chunk->mPrev->mNext = chunk->mNext ; + } + if(chunk->mNext) + { + chunk->mNext->mPrev = chunk->mPrev ; + } + + //remove from the array + U16 k = findChunk(chunk->getBuffer()) ; + mNumOfChunks--; + for(U16 i = k ; i < mNumOfChunks ; i++) + { + mChunks[i] = mChunks[i+1] ; + } + + //release memory + delete[] chunk->getBuffer() ; +} + +U16 LLPrivateMemoryPool::findChunk(const char* addr) +{ + llassert_always(mNumOfChunks > 0) ; + + U16 s = 0, e = mNumOfChunks; + U16 k = (s + e) / 2 ; + while(s < e) + { + if(mChunks[k]->mKey > (U32)addr) + { + e = k ; + } + else if(k < mNumOfChunks - 1 && mChunks[k+1]->mKey < (U32)addr) + { + s = k ; + } + else + { + break ; + } + + k = (s + e) / 2 ; + } + + return k ; +} + +//-------------------------------------------------------------------- +//class LLPrivateMemoryPoolTester +LLPrivateMemoryPoolTester* LLPrivateMemoryPoolTester::sInstance = NULL ; +LLPrivateMemoryPool* LLPrivateMemoryPoolTester::sPool = NULL ; +LLPrivateMemoryPoolTester::LLPrivateMemoryPoolTester() +{ +} + +LLPrivateMemoryPoolTester::~LLPrivateMemoryPoolTester() +{ +} + +//static +LLPrivateMemoryPoolTester* LLPrivateMemoryPoolTester::getInstance() +{ + if(!sInstance) + { + sInstance = new LLPrivateMemoryPoolTester() ; + } + return sInstance ; +} + +//static +void LLPrivateMemoryPoolTester::destroy() +{ + if(sInstance) + { + delete sInstance ; + sInstance = NULL ; + } + + if(sPool) + { + delete sPool ; + sPool = NULL ; + } +} + +void LLPrivateMemoryPoolTester::run() +{ + const U32 max_pool_size = 16 << 20 ; + const bool threaded = false ; + if(!sPool) + { + sPool = new LLPrivateMemoryPool(max_pool_size, threaded) ; + } + + //run the test + correctnessTest() ; + reliabilityTest() ; + performanceTest() ; + fragmentationtest() ; +} + +void LLPrivateMemoryPoolTester::correctnessTest() +{ + //try many different sized allocation, fill the memory fully to see if allocation is right. + +} + +void LLPrivateMemoryPoolTester::reliabilityTest() +void LLPrivateMemoryPoolTester::performanceTest() +void LLPrivateMemoryPoolTester::fragmentationtest() + +void* LLPrivateMemoryPoolTester::operator new(size_t size) +{ + return (void*)sPool->allocate(size) ; +} + +void LLPrivateMemoryPoolTester::operator delete(void* addr) +{ + sPool->free(addr) ; +} + +//-------------------------------------------------------------------- diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 9bf4248bb7..d9e93d0e96 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -26,8 +26,6 @@ #ifndef LLMEMORY_H #define LLMEMORY_H - - extern S32 gTotalDAlloc; extern S32 gTotalDAUse; extern S32 gDACount; @@ -44,8 +42,180 @@ public: // Return the resident set size of the current process, in bytes. // Return value is zero if not known. static U64 getCurrentRSS(); + + static void* tryToAlloc(void* address, U32 size); + static void initMaxHeapSizeGB(F32 max_heap_size_gb, BOOL prevent_heap_failure); + static void updateMemoryInfo() ; + static void logMemoryInfo(BOOL update = FALSE); + static S32 isMemoryPoolLow(); + + static U32 getAvailableMemKB() ; + static U32 getMaxMemKB() ; + static U32 getAllocatedMemKB() ; private: static char* reserveMem; + static U32 sAvailPhysicalMemInKB ; + static U32 sMaxPhysicalMemInKB ; + static U32 sAllocatedMemInKB; + static U32 sAllocatedPageSizeInKB ; + + static U32 sMaxHeapSizeInKB; + static BOOL sEnableMemoryFailurePrevention; +}; + +class LL_COMMON_API LLPrivateMemoryPool +{ +public: + class LL_COMMON_API LLMemoryBlock //each block is devided into slots uniformly + { + public: + LLMemoryBlock() ; + ~LLMemoryBlock() ; + + void init(char* buffer, U32 buffer_size, U32 slot_size) ; + void setBuffer(char* buffer, U32 buffer_size) ; + + char* allocate() ; + void free(void* addr) ; + + bool empty() {return !mAllocatedSlots;} + bool isFull() {return mAllocatedSlots == mTotalSlots;} + bool isFree() {return !mTotalSlots;} + + U32 getSlotSize()const {return mSlotSize;} + U32 getTotalSlots()const {return mTotalSlots;} + U32 getBufferSize()const {return mBufferSize;} + char* getBuffer() const {return mBuffer;} + + private: + char* mBuffer; + U32 mSlotSize ; //when the block is not initialized, it is the buffer size. + U32 mBufferSize ; + U32 mUsageBits ; + U8 mTotalSlots ; + U8 mAllocatedSlots ; + U8 mDummySize ; //size of extra U32 reserved for mUsageBits. + + public: + LLMemoryBlock* mPrev ; + LLMemoryBlock* mNext ; + LLMemoryBlock* mSelf ; + }; + + class LL_COMMON_API LLMemoryChunk //is divided into memory blocks. + { + public: + LLMemoryChunk() ; + ~LLMemoryChunk() ; + + void init(char* buffer, U32 buffer_size, U32 min_slot_size, U32 max_slot_size, U32 min_block_size, U32 max_block_size) ; + void setBuffer(char* buffer, U32 buffer_size) ; + + bool empty() ; + + char* allocate(U32 size) ; + void free(void* addr) ; + + const char* getBuffer() const {return mBuffer;} + U32 getBufferSize() const {return mBufferSize;} + + static U32 getMaxOverhead(U32 data_buffer_size, U32 min_page_size) ; + + private: + LLMemoryBlock* addBlock(U32 blk_idx) ; + void popAvailBlockList(U32 blk_idx) ; + void addToFreeSpace(LLMemoryBlock* blk) ; + void removeFromFreeSpace(LLMemoryBlock* blk) ; + void removeBlock(LLMemoryBlock* blk) ; + void addToAvailBlockList(LLMemoryBlock* blk) ; + LLMemoryBlock* createNewBlock(LLMemoryBlock** cur_idxp, U32 buffer_size, U32 slot_size, U32 blk_idx) ; + + private: + LLMemoryBlock** mAvailBlockList ;//256 by mMinSlotSize + LLMemoryBlock** mFreeSpaceList; + LLMemoryBlock* mBlocks ; //index of blocks by address. + + char* mBuffer ; + U32 mBufferSize ; + char* mDataBuffer ; + char* mMetaBuffer ; + U32 mMinBlockSize ; + U32 mMaxBlockSize; + U32 mMinSlotSize ; + U16 mBlockLevels; + U16 mPartitionLevels; + + public: + //form a linked list + LLMemoryChunk* mNext ; + LLMemoryChunk* mPrev ; + + U32 mKey ; //= mBuffer + } ; + +public: + LLPrivateMemoryPool(U32 max_size, bool threaded) ; + ~LLPrivateMemoryPool() ; + + char *allocate(U32 size) ; + void free(void* addr) ; + void dump() ; + +private: + void lock() ; + void unlock() ; + S32 getChunkIndex(U32 size) ; + LLMemoryChunk* addChunk(S32 chunk_index) ; + void removeChunk(LLMemoryChunk* chunk) ; + U16 findChunk(const char* addr) ; + void destroyPool() ; + +private: + LLMutex* mMutexp ; + U32 mMaxPoolSize; + U32 mReservedPoolSize ; + + enum + { + SMALL_ALLOCATION = 0, //from 8 bytes to 2KB(exclusive), page size 2KB, max chunk size is 4MB. + MEDIUM_ALLOCATION, //from 2KB to 512KB(exclusive), page size 32KB, max chunk size 4MB + LARGE_ALLOCATION, //from 512KB to 4MB(inclusive), page size 64KB, max chunk size 16MB + SUPER_ALLOCATION //allocation larger than 4MB. + }; + + LLMemoryChunk* mChunkList[SUPER_ALLOCATION] ; //all memory chunks reserved by this pool, sorted by address + std::vector mChunks ; + U16 mNumOfChunks ; + U16 mChunkVectorCapacity ; +}; + +// +//the below singleton is used to test the private memory pool. +// +class LLPrivateMemoryPoolTester +{ +private: + LLPrivateMemoryPoolTester() ; + ~LLPrivateMemoryPoolTester() ; + +public: + static LLPrivateMemoryPoolTester* getInstance() ; + static void destroy() ; + + void run() ; + +private: + void correctnessTest() ; + void reliabilityTest() ; + void performanceTest() ; + void fragmentationtest() ; + + void* operator new(size_t); + void operator delete(void*); + +private: + static LLPrivateMemoryPoolTester* sInstance; + static LLPrivateMemoryPool* sPool ; }; // LLRefCount moved to llrefcount.h diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 10cdc7087b..7968e53c13 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -636,22 +636,20 @@ U32 LLMemoryInfo::getPhysicalMemoryClamped() const } //static -void LLMemoryInfo::getAvailableMemoryKB(U32& avail_physical_mem_kb, U32& avail_virtual_mem_kb) +U32 LLMemoryInfo::getAvailableMemoryKB() { #if LL_WINDOWS MEMORYSTATUSEX state; state.dwLength = sizeof(state); GlobalMemoryStatusEx(&state); - avail_physical_mem_kb = (U32)(state.ullAvailPhys/1024) ; - avail_virtual_mem_kb = (U32)(state.ullAvailVirtual/1024) ; + return (U32)(state.ullAvailPhys/1024) ; #else //do not know how to collect available memory info for other systems. //leave it blank here for now. - avail_physical_mem_kb = -1 ; - avail_virtual_mem_kb = -1 ; + return -1; #endif } diff --git a/indra/llcommon/llsys.h b/indra/llcommon/llsys.h index 41a4f25000..580eee4e8d 100644 --- a/indra/llcommon/llsys.h +++ b/indra/llcommon/llsys.h @@ -116,7 +116,7 @@ public: U32 getPhysicalMemoryClamped() const; ///< Memory size in clamped bytes //get the available memory infomation in KiloBytes. - static void getAvailableMemoryKB(U32& avail_physical_mem_kb, U32& avail_virtual_mem_kb); + static U32 getAvailableMemoryKB(); }; diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 02160b09c4..19269c2a31 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -33,6 +33,7 @@ #include "llglheaders.h" #include "llmemtype.h" #include "llrender.h" +#include "llmemory.h" //============================================================================ @@ -857,11 +858,8 @@ U8* LLVertexBuffer::mapBuffer(S32 access) log_glerror(); //check the availability of memory - U32 avail_phy_mem, avail_vir_mem; - LLMemoryInfo::getAvailableMemoryKB(avail_phy_mem, avail_vir_mem) ; - llinfos << "Available physical mwmory(KB): " << avail_phy_mem << llendl ; - llinfos << "Available virtual memory(KB): " << avail_vir_mem << llendl; - + LLMemory::logMemoryInfo(TRUE) ; + //-------------------- //print out more debug info before crash llinfos << "vertex buffer size: (num verts : num indices) = " << getNumVerts() << " : " << getNumIndices() << llendl ; @@ -884,6 +882,7 @@ U8* LLVertexBuffer::mapBuffer(S32 access) if (!mMappedIndexData) { log_glerror(); + LLMemory::logMemoryInfo(TRUE) ; GLint buff; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h index 93975579cc..70749b8ee9 100644 --- a/indra/llxml/llcontrol.h +++ b/indra/llxml/llcontrol.h @@ -385,7 +385,8 @@ class LLCachedControl { public: LLCachedControl(LLControlGroup& group, - const std::string& name, + const std::string& name, + const T& default_value, const std::string& comment = "Declared In Code") { diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 535bc95287..905c683f69 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -5153,6 +5153,17 @@ Value 48.0 + MaxHeapSize + + Comment + Maximum heap size (GB) + Persist + 1 + Type + F32 + Value + 1.6 + MaxSelectDistance Comment @@ -5329,6 +5340,17 @@ Value 1 + MemeoyFailurePreventionEnabled + + Comment + If set, the viewer will quit to avoid crash when memory failure happens + Persist + 0 + Type + Boolean + Value + 1 + MemoryLogFrequency Comment diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 3a98749c0f..84e36ac3c7 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -604,7 +604,7 @@ LLAppViewer::~LLAppViewer() } bool LLAppViewer::init() -{ +{ // // Start of the application // @@ -632,6 +632,9 @@ bool LLAppViewer::init() if (!initConfiguration()) return false; + //set the max heap size. + initMaxHeapSize() ; + // write Google Breakpad minidump files to our log directory std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); logdir += gDirUtilp->getDirDelimiter(); @@ -949,6 +952,96 @@ bool LLAppViewer::init() return true; } +void LLAppViewer::initMaxHeapSize() +{ + //set the max heap size. + //here is some info regarding to the max heap size: + //------------------------------------------------------------------------------------------ + // OS | setting | SL address bits | max manageable memory space | max heap size + // Win 32 | default | 32-bit | 2GB | < 1.7GB + // Win 32 | /3G | 32-bit | 3GB | < 1.7GB or 2.7GB + //Linux 32 | default | 32-bit | 3GB | < 2.7GB + //Linux 32 |HUGEMEM | 32-bit | 4GB | < 3.7GB + //64-bit OS |default | 32-bit | 4GB | < 3.7GB + //64-bit OS |default | 64-bit | N/A (> 4GB) | N/A (> 4GB) + //------------------------------------------------------------------------------------------ + //currently SL is built under 32-bit setting, we set its max heap size no more than 1.6 GB. + + //F32 max_heap_size_gb = llmin(1.6f, (F32)gSavedSettings.getF32("MaxHeapSize")) ; + F32 max_heap_size_gb = gSavedSettings.getF32("MaxHeapSize") ; + BOOL enable_mem_failure_prevention = (BOOL)gSavedSettings.getBOOL("MemeoyFailurePreventionEnabled") ; + + LLMemory::initMaxHeapSizeGB(max_heap_size_gb, enable_mem_failure_prevention) ; +} + +void LLAppViewer::checkMemory() +{ + const static F32 MEMORY_CHECK_INTERVAL = 1.0f ; //second + const static F32 MAX_QUIT_WAIT_TIME = 30.0f ; //seconds + const static U32 MAX_SIZE_CHECKED_MEMORY_BLOCK = 64 * 1024 * 1024 ; //64 MB + //static F32 force_quit_timer = MAX_QUIT_WAIT_TIME + MEMORY_CHECK_INTERVAL ; + static void* last_reserved_address = NULL ; + + if(MEMORY_CHECK_INTERVAL > mMemCheckTimer.getElapsedTimeF32()) + { + return ; + } + mMemCheckTimer.reset() ; + + if(gGLManager.mDebugGPU) + { + //update the availability of memory + LLMemory::updateMemoryInfo() ; + } + + //check the virtual address space fragmentation + if(!last_reserved_address) + { + last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK) ; + } + else + { + last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK) ; + if(!last_reserved_address) //failed, try once more + { + last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK) ; + } + } + + S32 is_low = !last_reserved_address || LLMemory::isMemoryPoolLow() ; + + //if(is_low < 0) //to force quit + //{ + // if(force_quit_timer > MAX_QUIT_WAIT_TIME) //just hit the limit for the first time + // { + // //send out the notification to tell the viewer is about to quit in 30 seconds. + // LLNotification::Params params("ForceQuitDueToLowMemory"); + // LLNotifications::instance().add(params); + + // force_quit_timer = MAX_QUIT_WAIT_TIME - MEMORY_CHECK_INTERVAL ; + // } + // else + // { + // force_quit_timer -= MEMORY_CHECK_INTERVAL ; + // if(force_quit_timer < 0.f) + // { + // forceQuit() ; //quit + // } + // } + //} + //else + //{ + // force_quit_timer = MAX_QUIT_WAIT_TIME + MEMORY_CHECK_INTERVAL ; + //} + + LLPipeline::throttleNewMemoryAllocation(!is_low ? FALSE : TRUE) ; + + if(is_low) + { + LLMemory::logMemoryInfo() ; + } +} + static LLFastTimer::DeclareTimer FTM_MESSAGES("System Messages"); static LLFastTimer::DeclareTimer FTM_SLEEP("Sleep"); static LLFastTimer::DeclareTimer FTM_TEXTURE_CACHE("Texture Cache"); @@ -983,8 +1076,7 @@ bool LLAppViewer::mainLoop() LLVoiceChannel::initClass(); LLVoiceClient::getInstance()->init(gServicePump); LLTimer frameTimer,idleTimer; - LLTimer debugTime; - LLFrameTimer memCheckTimer; + LLTimer debugTime; LLViewerJoystick* joystick(LLViewerJoystick::getInstance()); joystick->setNeedsReset(true); @@ -993,9 +1085,7 @@ bool LLAppViewer::mainLoop() // with each frame, no need to instantiate a new LLSD event object each // time. Obviously, if that changes, just instantiate the LLSD at the // point of posting. - LLSD newFrame; - - const F32 memory_check_interval = 1.0f ; //second + LLSD newFrame; // Handle messages while (!LLApp::isExiting()) @@ -1006,18 +1096,8 @@ bool LLAppViewer::mainLoop() llclearcallstacks; //check memory availability information - { - if(memory_check_interval < memCheckTimer.getElapsedTimeF32()) - { - memCheckTimer.reset() ; - - //update the availability of memory - LLMemoryInfo::getAvailableMemoryKB(mAvailPhysicalMemInKB, mAvailVirtualMemInKB) ; - } - llcallstacks << "Available physical mem(KB): " << mAvailPhysicalMemInKB << llcallstacksendl ; - llcallstacks << "Available virtual mem(KB): " << mAvailVirtualMemInKB << llcallstacksendl ; - } - + checkMemory() ; + try { pingMainloopTimeout("Main:MiscNativeWindowEvents"); @@ -1181,7 +1261,7 @@ bool LLAppViewer::mainLoop() idleTimer.reset(); bool is_slow = (frameTimer.getElapsedTimeF64() > FRAME_SLOW_THRESHOLD) ; S32 total_work_pending = 0; - S32 total_io_pending = 0; + S32 total_io_pending = 0; while(!is_slow)//do not unpause threads if the frame rates are very low. { S32 work_pending = 0; @@ -1248,15 +1328,7 @@ bool LLAppViewer::mainLoop() } catch(std::bad_alloc) { - { - llinfos << "Availabe physical memory(KB) at the beginning of the frame: " << mAvailPhysicalMemInKB << llendl ; - llinfos << "Availabe virtual memory(KB) at the beginning of the frame: " << mAvailVirtualMemInKB << llendl ; - - LLMemoryInfo::getAvailableMemoryKB(mAvailPhysicalMemInKB, mAvailVirtualMemInKB) ; - - llinfos << "Current availabe physical memory(KB): " << mAvailPhysicalMemInKB << llendl ; - llinfos << "Current availabe virtual memory(KB): " << mAvailVirtualMemInKB << llendl ; - } + LLMemory::logMemoryInfo(TRUE) ; //stop memory leaking simulation LLFloaterMemLeak* mem_leak_instance = diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index a70a727c5d..7761a10f1c 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -166,8 +166,8 @@ public: // mute/unmute the system's master audio virtual void setMasterSystemAudioMute(bool mute); - virtual bool getMasterSystemAudioMute(); - + virtual bool getMasterSystemAudioMute(); + protected: virtual bool initWindow(); // Initialize the viewer's window. virtual bool initLogging(); // Initialize log files, logging system, return false on failure. @@ -184,11 +184,12 @@ protected: private: + void initMaxHeapSize(); bool initThreads(); // Initialize viewer threads, return false on failure. bool initConfiguration(); // Initialize settings from the command line/config file. bool initCache(); // Initialize local client cache. - + void checkMemory() ; // We have switched locations of both Mac and Windows cache, make sure // files migrate and old cache is cleared out. @@ -258,8 +259,7 @@ private: std::set mPlugins; - U32 mAvailPhysicalMemInKB ; - U32 mAvailVirtualMemInKB ; + LLFrameTimer mMemCheckTimer; public: //some information for updater typedef struct diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp index a3d2941114..58eef45935 100644 --- a/indra/newview/lldynamictexture.cpp +++ b/indra/newview/lldynamictexture.cpp @@ -40,6 +40,7 @@ #include "llvertexbuffer.h" #include "llviewerdisplay.h" #include "llrender.h" +#include "pipeline.h" // static LLViewerDynamicTexture::instance_list_t LLViewerDynamicTexture::sInstances[ LLViewerDynamicTexture::ORDER_COUNT ]; @@ -205,7 +206,7 @@ void LLViewerDynamicTexture::postRender(BOOL success) BOOL LLViewerDynamicTexture::updateAllInstances() { sNumRenders = 0; - if (gGLManager.mIsDisabled) + if (gGLManager.mIsDisabled || LLPipeline::sMemAllocationThrottled) { return TRUE; } @@ -221,9 +222,8 @@ BOOL LLViewerDynamicTexture::updateAllInstances() if (dynamicTexture->needsRender()) { if(gGLManager.mDebugGPU) - { + { llinfos << "class type: " << (S32)dynamicTexture->getType() << llendl; - LLGLState::dumpStates() ; } glClear(GL_DEPTH_BUFFER_BIT); diff --git a/indra/newview/llfloatermemleak.cpp b/indra/newview/llfloatermemleak.cpp index 58931d112e..9edfe1e354 100644 --- a/indra/newview/llfloatermemleak.cpp +++ b/indra/newview/llfloatermemleak.cpp @@ -90,6 +90,11 @@ LLFloaterMemLeak::~LLFloaterMemLeak() void LLFloaterMemLeak::release() { + if(mLeakedMem.empty()) + { + return ; + } + for(S32 i = 0 ; i < (S32)mLeakedMem.size() ; i++) { delete[] mLeakedMem[i] ; diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 7c8b52d0b6..e7153f7ffc 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -202,6 +202,7 @@ void display_stats() gMemoryAllocated = LLMemory::getCurrentRSS(); U32 memory = (U32)(gMemoryAllocated / (1024*1024)); llinfos << llformat("MEMORY: %d MB", memory) << llendl; + LLMemory::logMemoryInfo() ; gRecentMemoryTime.reset(); } } @@ -672,7 +673,11 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) glh::matrix4f mod = glh_get_current_modelview(); glViewport(0,0,512,512); LLVOAvatar::updateFreezeCounter() ; - LLVOAvatar::updateImpostors(); + + if(!LLPipeline::sMemAllocationThrottled) + { + LLVOAvatar::updateImpostors(); + } glh_set_current_projection(proj); glh_set_current_modelview(mod); diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index f96b93da4d..260023a802 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -3068,9 +3068,16 @@ void LLViewerLODTexture::processTextureStats() { mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, (S8)mDesiredSavedRawDiscardLevel) ; } + else if(LLPipeline::sMemAllocationThrottled)//release memory of large textures by decrease their resolutions. + { + if(scaleDown()) + { + mDesiredDiscardLevel = mCachedRawDiscardLevel ; + } + } } -void LLViewerLODTexture::scaleDown() +bool LLViewerLODTexture::scaleDown() { if(hasGLTexture() && mCachedRawDiscardLevel > getDiscardLevel()) { @@ -3080,7 +3087,10 @@ void LLViewerLODTexture::scaleDown() { LLViewerTextureManager::sTesterp->setStablizingTime() ; } + + return true ; } + return false ; } //---------------------------------------------------------------------------------------------- //end of LLViewerLODTexture diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index b779396293..ffcbba3efd 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -595,7 +595,7 @@ public: private: void init(bool firstinit) ; - void scaleDown() ; + bool scaleDown() ; private: F32 mDiscardVirtualSize; // Virtual size used to calculate desired discard diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 64698ed006..943b5b5886 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -3874,6 +3874,19 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei { return FALSE; } + //check if there is enough memory for the snapshot image + if(LLPipeline::sMemAllocationThrottled) + { + return FALSE ; //snapshot taking is disabled due to memory restriction. + } + if(image_width * image_height > (1 << 22)) //if snapshot image is larger than 2K by 2K + { + if(!LLMemory::tryToAlloc(NULL, image_width * image_height * 3)) + { + llwarns << "No enough memory to take the snapshot with size (w : h): " << image_width << " : " << image_height << llendl ; + return FALSE ; //there is no enough memory for taking this snapshot. + } + } // PRE SNAPSHOT gDisplaySwapBuffers = FALSE; diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index b4a5777f10..7c69af17f2 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -98,6 +98,7 @@ #include "llspatialpartition.h" #include "llmutelist.h" #include "lltoolpie.h" +#include "llnotifications.h" #ifdef _DEBUG @@ -281,6 +282,7 @@ BOOL LLPipeline::sRenderAttachedLights = TRUE; BOOL LLPipeline::sRenderAttachedParticles = TRUE; BOOL LLPipeline::sRenderDeferred = FALSE; BOOL LLPipeline::sAllowRebuildPriorityGroup = FALSE ; +BOOL LLPipeline::sMemAllocationThrottled = FALSE; S32 LLPipeline::sVisibleLightCount = 0; F32 LLPipeline::sMinRenderSize = 0.f; @@ -513,6 +515,24 @@ void LLPipeline::destroyGL() static LLFastTimer::DeclareTimer FTM_RESIZE_SCREEN_TEXTURE("Resize Screen Texture"); +//static +void LLPipeline::throttleNewMemoryAllocation(BOOL disable) +{ + if(sMemAllocationThrottled != disable) + { + sMemAllocationThrottled = disable ; + + if(sMemAllocationThrottled) + { + //send out notification + LLNotification::Params params("LowMemory"); + LLNotifications::instance().add(params); + + //release some memory. + } + } +} + void LLPipeline::resizeScreenTexture() { LLFastTimer ft(FTM_RESIZE_SCREEN_TEXTURE); @@ -8792,7 +8812,7 @@ void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL textu void LLPipeline::generateImpostor(LLVOAvatar* avatar) { - LLMemType mt_gi(LLMemType::MTYPE_PIPELINE_GENERATE_IMPOSTOR); + LLMemType mt_gi(LLMemType::MTYPE_PIPELINE_GENERATE_IMPOSTOR); LLGLState::checkStates(); LLGLState::checkTextureChannels(); LLGLState::checkClientArrays(); diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index b80765dac6..f4a7dfd38d 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -334,6 +334,8 @@ public: static void updateRenderDeferred(); + static void throttleNewMemoryAllocation(BOOL disable); + private: void unloadShaders(); void addToQuickLookup( LLDrawPool* new_poolp ); @@ -477,8 +479,9 @@ public: static BOOL sRenderAttachedParticles; static BOOL sRenderDeferred; static BOOL sAllowRebuildPriorityGroup; + static BOOL sMemAllocationThrottled; static S32 sVisibleLightCount; - static F32 sMinRenderSize; + static F32 sMinRenderSize; //screen texture U32 mScreenWidth; diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index dfbb408d96..5183788c98 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -6450,6 +6450,20 @@ Mute everyone? Here's your current balance of L$. Click Buy L$ to purchase more Linden Dollars. + + Your memory pool is low. Some functions of SL are disabled to avoid crash. Please close other applications. Restart SL if this persists. + + + + SL will quit in 30 seconds due to out of memory. + + - + \ No newline at end of file -- cgit v1.2.3 From 43f4429363e63484f35663c10ca993d0d812e855 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Wed, 8 Dec 2010 20:50:39 -0700 Subject: test code and some code change --- indra/llcommon/llmemory.cpp | 251 +++++++++++++++++++++++++++++++++++------- indra/llcommon/llmemory.h | 62 ++++++++++- indra/newview/llappviewer.cpp | 4 + 3 files changed, 273 insertions(+), 44 deletions(-) (limited to 'indra') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index ca06589611..a659e84309 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -40,7 +40,7 @@ #include "llmemory.h" #include "llsys.h" - +#include "llframetimer.h" //---------------------------------------------------------------------------- @@ -505,6 +505,7 @@ void LLPrivateMemoryPool::LLMemoryChunk::init(char* buffer, U32 buffer_size, U32 { mBuffer = buffer ; mBufferSize = buffer_size ; + mAlloatedSize = 0 ; mMetaBuffer = mBuffer + sizeof(LLMemoryChunk) ; @@ -552,18 +553,16 @@ U32 LLPrivateMemoryPool::LLMemoryChunk::getMaxOverhead(U32 data_buffer_size, U32 char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) { char* p = NULL ; - U32 blk_idx = size / mMinSlotSize ; - if(mMinSlotSize * blk_idx < size) - { - blk_idx++ ; - } + U32 blk_idx = getBlockLevel(size); + + LLMemoryBlock* blk = NULL ; //check if there is free block available if(mAvailBlockList[blk_idx]) { - LLMemoryBlock* blk = mAvailBlockList[blk_idx] ; + blk = mAvailBlockList[blk_idx] ; p = blk->allocate() ; - + if(blk->isFull()) { //removeFromFreelist @@ -574,7 +573,7 @@ char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) //ask for a new block if(!p) { - LLMemoryBlock* blk = addBlock(blk_idx) ; + blk = addBlock(blk_idx) ; if(blk) { p = blk->allocate() ; @@ -594,7 +593,7 @@ char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) { if(mAvailBlockList[i]) { - LLMemoryBlock* blk = mAvailBlockList[i] ; + blk = mAvailBlockList[i] ; p = blk->allocate() ; if(blk->isFull()) @@ -607,16 +606,23 @@ char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) } } + if(p && blk) + { + mAlloatedSize += blk->getSlotSize() ; + } return p ; } void LLPrivateMemoryPool::LLMemoryChunk::free(void* addr) { - LLMemoryBlock* blk = (LLMemoryBlock*)(mMetaBuffer + (((char*)addr - mDataBuffer) / mMinBlockSize) * sizeof(LLMemoryBlock)) ; + U32 blk_idx = ((U32)addr - (U32)mDataBuffer) / mMinBlockSize ; + if(blk_idx > 0) blk_idx-- ; + LLMemoryBlock* blk = (LLMemoryBlock*)(mMetaBuffer + blk_idx * sizeof(LLMemoryBlock)) ; blk = blk->mSelf ; bool was_full = blk->isFull() ; blk->free(addr) ; + mAlloatedSize -= blk->getSlotSize() ; if(blk->empty()) { @@ -628,13 +634,18 @@ void LLPrivateMemoryPool::LLMemoryChunk::free(void* addr) } } +bool LLPrivateMemoryPool::LLMemoryChunk::empty() +{ + return !mAlloatedSize ; +} + LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::addBlock(U32 blk_idx) { U32 slot_size = mMinSlotSize * (blk_idx + 1) ; U32 preferred_block_size = llmax(mMinBlockSize, slot_size * 32) ; preferred_block_size = llmin(preferred_block_size, mMaxBlockSize) ; - U32 idx = preferred_block_size / mMinBlockSize ; + U32 idx = preferred_block_size / mMinBlockSize - 1; preferred_block_size = idx * mMinBlockSize ; //round to integer times of mMinBlockSize. LLMemoryBlock* blk = NULL ; @@ -710,7 +721,10 @@ LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::createNe else { *cur_idxp = blk->mNext ; //move to the next slot - (*cur_idxp)->mPrev = NULL ; + if(*cur_idxp) + { + (*cur_idxp)->mPrev = NULL ; + } addToFreeSpace(next_blk) ; } @@ -718,7 +732,10 @@ LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::createNe else //move to the next block { *cur_idxp = blk->mNext ; - (*cur_idxp)->mPrev = NULL ; + if(*cur_idxp) + { + (*cur_idxp)->mPrev = NULL ; + } } //insert to the available block list... @@ -791,7 +808,9 @@ void LLPrivateMemoryPool::LLMemoryChunk::popAvailBlockList(U32 blk_idx) void LLPrivateMemoryPool::LLMemoryChunk::addToFreeSpace(LLMemoryBlock* blk) { - U16 free_idx = blk->getBufferSize() / mMinBlockSize ; + U16 free_idx = blk->getBufferSize() / mMinBlockSize; + if(free_idx > 0) free_idx--; + (blk + free_idx)->mSelf = blk ; //mark the end pointing back to the head. free_idx = llmin(free_idx, (U16)(mPartitionLevels - 1)) ; @@ -809,7 +828,8 @@ void LLPrivateMemoryPool::LLMemoryChunk::addToFreeSpace(LLMemoryBlock* blk) void LLPrivateMemoryPool::LLMemoryChunk::removeFromFreeSpace(LLMemoryBlock* blk) { - U16 free_idx = blk->getBufferSize() / mMinBlockSize ; + U16 free_idx = blk->getBufferSize() / mMinBlockSize; + if(free_idx > 0) free_idx-- ; free_idx = llmin(free_idx, (U16)(mPartitionLevels - 1)) ; if(mFreeSpaceList[free_idx] == blk) @@ -830,7 +850,7 @@ void LLPrivateMemoryPool::LLMemoryChunk::removeFromFreeSpace(LLMemoryBlock* blk) void LLPrivateMemoryPool::LLMemoryChunk::addToAvailBlockList(LLMemoryBlock* blk) { - U32 blk_idx = blk->getSlotSize() / mMinSlotSize ; + U32 blk_idx = getBlockLevel(blk->getSlotSize()); blk->mNext = mAvailBlockList[blk_idx] ; if(blk->mNext) @@ -842,6 +862,16 @@ void LLPrivateMemoryPool::LLMemoryChunk::addToAvailBlockList(LLMemoryBlock* blk) return ; } +U32 LLPrivateMemoryPool::LLMemoryChunk::getBlockLevel(U32 size) +{ + return (size + mMinSlotSize - 1) / mMinSlotSize - 1 ; +} + +U32 LLPrivateMemoryPool::LLMemoryChunk::getPageLevel(U32 size) +{ + return (size + mMinBlockSize - 1) / mMinBlockSize - 1 ; +} + //------------------------------------------------------------------- //class LLPrivateMemoryPool //-------------------------------------------------------------------- @@ -875,6 +905,11 @@ char* LLPrivateMemoryPool::allocate(U32 size) { const static U32 MAX_BLOCK_SIZE = 4 * 1024 * 1024 ; //4MB + if(!size) + { + return NULL ; + } + //if the asked size larger than MAX_BLOCK_SIZE, fetch from heap directly, the pool does not manage it if(size >= MAX_BLOCK_SIZE) { @@ -902,7 +937,10 @@ char* LLPrivateMemoryPool::allocate(U32 size) if(!p) { chunk = addChunk(chunk_idx) ; - p = chunk->allocate(size) ; + if(chunk) + { + p = chunk->allocate(size) ; + } } unlock() ; @@ -912,6 +950,11 @@ char* LLPrivateMemoryPool::allocate(U32 size) void LLPrivateMemoryPool::free(void* addr) { + if(!addr) + { + return ; + } + lock() ; LLMemoryChunk* chunk = mChunks[findChunk((char*)addr)] ; @@ -1116,7 +1159,7 @@ LLPrivateMemoryPoolTester* LLPrivateMemoryPoolTester::getInstance() { if(!sInstance) { - sInstance = new LLPrivateMemoryPoolTester() ; + sInstance = ::new LLPrivateMemoryPoolTester() ; } return sInstance ; } @@ -1126,51 +1169,181 @@ void LLPrivateMemoryPoolTester::destroy() { if(sInstance) { - delete sInstance ; + ::delete sInstance ; sInstance = NULL ; } if(sPool) { - delete sPool ; + ::delete sPool ; sPool = NULL ; } } -void LLPrivateMemoryPoolTester::run() +void LLPrivateMemoryPoolTester::run(bool threaded) { const U32 max_pool_size = 16 << 20 ; - const bool threaded = false ; - if(!sPool) + + if(sPool) { - sPool = new LLPrivateMemoryPool(max_pool_size, threaded) ; + ::delete sPool ; } + sPool = ::new LLPrivateMemoryPool(max_pool_size, threaded) ; //run the test correctnessTest() ; - reliabilityTest() ; performanceTest() ; fragmentationtest() ; + + //release pool. + ::delete sPool ; + sPool = NULL ; +} + +void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 times, + bool random_deletion, bool output_statistics) +{ + U32 levels = (max_size - min_size) / stride + 1 ; + char*** p ; + U32 i, j ; + + //allocate space for p ; + if(!(p = ::new char**[times]) || !(*p = ::new char*[times * levels])) + { + llerrs << "memory initialization for p failed" << llendl ; + } + + //init + for(i = 0 ; i < times; i++) + { + p[i] = *p + i * levels ; + for(j = 0 ; j < levels; j++) + { + p[i][j] = NULL ; + } + } + + //allocation + U32 size ; + for(i = 0 ; i < times ; i++) + { + for(j = 0 ; j < levels; j++) + { + size = min_size + j * stride ; + p[i][j] = sPool->allocate(size) ; + p[i][j][size - 1] = '\0' ; //access the last element to verify the success of the allocation. + + //randomly release memory + if(random_deletion) + { + S32 k = rand() % levels ; + sPool->free(p[i][k]) ; + p[i][k] = NULL ; + } + } + } + + //output pool allocation statistics + if(output_statistics) + { + } + + //release all memory allocations + for(i = 0 ; i < times; i++) + { + for(j = 0 ; j < levels; j++) + { + sPool->free(p[i][j]) ; + p[i][j] = NULL ; + } + } + + ::delete[] *p ; + ::delete[] p ; } void LLPrivateMemoryPoolTester::correctnessTest() { - //try many different sized allocation, fill the memory fully to see if allocation is right. + //try many different sized allocation, and all kinds of edge cases, access the allocated memory + //to see if allocation is right. + + //edge case + char* p = sPool->allocate(0) ; + sPool->free(p) ; + + //small sized + // [8 bytes, 2KB), each asks for 256 allocations and deallocations + test(8, 2040, 8, 256, true, true) ; + + //medium sized + //[2KB, 512KB), each asks for 16 allocations and deallocations + test(2048, 512 * 1024 - 2048, 2048, 16, true, true) ; + //large sized + //[512KB, 4MB], each asks for 8 allocations and deallocations + test(512 * 1024, 4 * 1024 * 1024, 64 * 1024, 8, true, true) ; } -void LLPrivateMemoryPoolTester::reliabilityTest() void LLPrivateMemoryPoolTester::performanceTest() +{ + U32 test_size[3] = {768, 3* 1024, 3* 1024 * 1024}; + + S32 i ; + LLFrameTimer timer ; + + //do 1024 various-sized allocations / deallocations, compare the performance with the normal ones. + + //small sized + { + timer.reset() ; + char* p[1024] = {NULL} ; + for(i = 0 ; i < 1024; i++) + { + p[i] = sPool->allocate(test_size[0]) ; + if(!p[i]) + { + llerrs << "allocation failed" << llendl ; + } + } + + for(i = 0 ; i < 1024; i++) + { + sPool->free(p[i]) ; + p[i] = NULL ; + } + llinfos << "time spent on 1024 small allocations: %f " << timer.getElapsedTimeF32() << llendl ; + + timer.reset() ; + + //using the standard allocator/de-allocator: + for(i = 0 ; i < 1024; i++) + { + p[i] = ::new char[test_size[0]] ; + if(!p[i]) + { + llerrs << "allocation failed" << llendl ; + } + } + + for(i = 0 ; i < 1024; i++) + { + ::delete[] p[i] ; + p[i] = NULL ; + } + llinfos << "time spent on 1024 small allocations: %f using standard allocator/de-allocator." << timer.getElapsedTimeF32() << llendl ; + + timer.reset() ; + } + //medium sized + + //large sized +} + void LLPrivateMemoryPoolTester::fragmentationtest() +{ + //for internal fragmentation statistics: + //every time when asking for a new chunk during correctness test, and performance test, + //print out the chunk usage statistices. +} -void* LLPrivateMemoryPoolTester::operator new(size_t size) -{ - return (void*)sPool->allocate(size) ; -} - -void LLPrivateMemoryPoolTester::operator delete(void* addr) -{ - sPool->free(addr) ; -} - -//-------------------------------------------------------------------- +//-------------------------------------------------------------------- diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index d9e93d0e96..128e7aefe6 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -63,6 +63,14 @@ private: static BOOL sEnableMemoryFailurePrevention; }; +// +//class LLPrivateMemoryPool defines a private memory pool for an application to use, so the application does not +//need to access the heap directly fro each memory allocation. Throught this, the allocation speed is faster, +//and reduces virtaul address space gragmentation problem. +//Note: this class is thread-safe by passing true to the constructor function. However, you do not need to do this unless +//you are sure the memory allocation and de-allocation will happen in different threads. To make the pool thread safe +//increases allocation and deallocation cost. +// class LL_COMMON_API LLPrivateMemoryPool { public: @@ -122,6 +130,8 @@ public: static U32 getMaxOverhead(U32 data_buffer_size, U32 min_page_size) ; private: + U32 getBlockLevel(U32 size) ; + U32 getPageLevel(U32 size) ; LLMemoryBlock* addBlock(U32 blk_idx) ; void popAvailBlockList(U32 blk_idx) ; void addToFreeSpace(LLMemoryBlock* blk) ; @@ -142,6 +152,7 @@ public: U32 mMinBlockSize ; U32 mMaxBlockSize; U32 mMinSlotSize ; + U32 mAlloatedSize ; U16 mBlockLevels; U16 mPartitionLevels; @@ -192,7 +203,7 @@ private: // //the below singleton is used to test the private memory pool. // -class LLPrivateMemoryPoolTester +class LL_COMMON_API LLPrivateMemoryPoolTester { private: LLPrivateMemoryPoolTester() ; @@ -202,22 +213,63 @@ public: static LLPrivateMemoryPoolTester* getInstance() ; static void destroy() ; - void run() ; + void run(bool threaded) ; private: void correctnessTest() ; - void reliabilityTest() ; void performanceTest() ; void fragmentationtest() ; - void* operator new(size_t); - void operator delete(void*); + void test(U32 min_size, U32 max_size, U32 stride, U32 times, bool random_deletion, bool output_statistics) ; + +public: + void* operator new(size_t size) + { + return (void*)sPool->allocate(size) ; + } + void operator delete(void* addr) + { + sPool->free(addr) ; + } + void* operator new[](size_t size) + { + return (void*)sPool->allocate(size) ; + } + void operator delete[](void* addr) + { + sPool->free(addr) ; + } private: static LLPrivateMemoryPoolTester* sInstance; static LLPrivateMemoryPool* sPool ; + static LLPrivateMemoryPool* sThreadedPool ; }; +#if 0 +//static +void* LLPrivateMemoryPoolTester::operator new(size_t size) +{ + return (void*)sPool->allocate(size) ; +} + +//static +void LLPrivateMemoryPoolTester::operator delete(void* addr) +{ + sPool->free(addr) ; +} +//static +void* LLPrivateMemoryPoolTester::operator new[](size_t size) +{ + return (void*)sPool->allocate(size) ; +} + +//static +void LLPrivateMemoryPoolTester::operator delete[](void* addr) +{ + sPool->free(addr) ; +} +#endif // LLRefCount moved to llrefcount.h // LLPointer moved to llpointer.h diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 84e36ac3c7..fd7e1eda7f 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1087,6 +1087,10 @@ bool LLAppViewer::mainLoop() // point of posting. LLSD newFrame; + LLPrivateMemoryPoolTester::getInstance()->run(false) ; + LLPrivateMemoryPoolTester::getInstance()->run(true) ; + LLPrivateMemoryPoolTester::destroy() ; + // Handle messages while (!LLApp::isExiting()) { -- cgit v1.2.3 From 5654abd50d834c3a7d0efb5dde393ff34f09be17 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Tue, 4 Jan 2011 13:14:36 -0700 Subject: a wroking version with a lot of debugging code (to be removed). --- indra/llcommon/llmemory.cpp | 770 ++++++++++++++++++++++++++++++++++---------- indra/llcommon/llmemory.h | 50 ++- 2 files changed, 636 insertions(+), 184 deletions(-) (limited to 'indra') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index a659e84309..00ef09d7a2 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -356,6 +356,22 @@ U64 LLMemory::getCurrentRSS() #endif +//------------------------------------------------------------- +//minimum block sizes (page size) for small allocation, medium allocation, large allocation +const U32 MIN_BLOCK_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {2 << 10, 4 << 10, 16 << 10} ; // + +//maximum block sizes for small allocation, medium allocation, large allocation +const U32 MAX_BLOCK_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {64 << 10, 1 << 20, 4 << 20} ; + +//minimum slot sizes for small allocation, medium allocation, large allocation +const U32 MIN_SLOT_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {8, 2 << 10, 512 << 10}; + +//maximum slot sizes for small allocation, medium allocation, large allocation +const U32 MAX_SLOT_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {(2 << 10) - 8, (512 - 2) << 10, 4 << 20}; + +//size of a block with multiple slots can not exceed CUT_OFF_SIZE +const U32 CUT_OFF_SIZE = (64 << 10) ; //64 KB + //------------------------------------------------------------- //class LLPrivateMemoryPool::LLMemoryBlock //------------------------------------------------------------- @@ -375,6 +391,8 @@ LLPrivateMemoryPool::LLMemoryBlock::~LLMemoryBlock() void LLPrivateMemoryPool::LLMemoryBlock::init(char* buffer, U32 buffer_size, U32 slot_size) { + llassert_always(buffer_size >= slot_size) ; + mBuffer = buffer ; mBufferSize = buffer_size ; mSlotSize = slot_size ; @@ -414,14 +432,20 @@ void LLPrivateMemoryPool::LLMemoryBlock::init(char* buffer, U32 buffer_size, U32 } } - mSelf = NULL ; + mSelf = this ; mNext = NULL ; + mPrev = NULL ; + + llassert_always(mTotalSlots > 0) ; } void LLPrivateMemoryPool::LLMemoryBlock::setBuffer(char* buffer, U32 buffer_size) { + llassert_always(buffer_size <= (16 << 20)) ; + mBuffer = buffer ; mBufferSize = buffer_size ; + mSelf = NULL ; mTotalSlots = 0 ; //set the block is free. } @@ -455,27 +479,47 @@ char* LLPrivateMemoryPool::LLMemoryBlock::allocate() //set the slot reserved if(!idx) { + llassert_always(!(*bits & 1)); *bits |= 1 ; } else { + llassert_always(!(*bits & (1 << idx))) ; *bits |= (1 << idx) ; } mAllocatedSlots++ ; + + //return mBuffer + mDummySize * sizeof(U32) + (k * 32 + idx) * mSlotSize ; - return mBuffer + mDummySize * sizeof(U32) + (k * 32 + idx) * mSlotSize ; + char* p = mBuffer + mDummySize * sizeof(U32) + (k * 32 + idx) * mSlotSize ; + llassert_always(mBuffer != p || !mDummySize) ; + llassert_always(*(U32*)p == 0 && *((U32*)p + 1) == 0) ; + + return p ; } +U32 col = 0, row = 0 ; void LLPrivateMemoryPool::LLMemoryBlock::free(void* addr) { - U32 idx = ((char*) addr - mBuffer - mDummySize * sizeof(U32)) / mSlotSize ; + llassert_always((U32)addr >= (U32)mBuffer + mDummySize * sizeof(U32) && + (U32)addr < (U32)mBuffer + mBufferSize) ; + + U32 idx = ((U32)addr - (U32)mBuffer - mDummySize * sizeof(U32)) / mSlotSize ; + + llassert_always(idx < mTotalSlots) ; + llassert_always(addr == mBuffer + mDummySize * sizeof(U32) + idx * mSlotSize) ; + llassert_always(*(U32*)addr == col && *((U32*)addr + 1) == row) ; + + *(U32*)addr = 0 ; + *((U32*)addr + 1) = 0 ; U32* bits = &mUsageBits ; - if(idx > 32) + if(idx >= 32) { bits = (U32*)mBuffer + (idx - 32) / 32 ; } + if(idx & 31) { *bits &= ~(1 << (idx & 31)) ; @@ -488,6 +532,15 @@ void LLPrivateMemoryPool::LLMemoryBlock::free(void* addr) mAllocatedSlots-- ; } +//for debug use +void LLPrivateMemoryPool::LLMemoryBlock::resetBitMap() +{ + for(S32 i = 0 ; i < mDummySize ; i++) + { + *((U32*)mBuffer + i) = 0 ; + } + mUsageBits = 0 ; +} //------------------------------------------------------------------- //class LLMemoryChunk //-------------------------------------------------------------------- @@ -510,10 +563,10 @@ void LLPrivateMemoryPool::LLMemoryChunk::init(char* buffer, U32 buffer_size, U32 mMetaBuffer = mBuffer + sizeof(LLMemoryChunk) ; mMinBlockSize = min_block_size; - mMaxBlockSize = max_block_size; mMinSlotSize = min_slot_size; - mBlockLevels = max_block_size / min_block_size ; - mPartitionLevels = mMaxBlockSize / mMinBlockSize + 1 ; + mMaxSlotSize = max_slot_size ; + mBlockLevels = mMaxSlotSize / mMinSlotSize ; + mPartitionLevels = max_block_size / mMinBlockSize + 1 ; S32 max_num_blocks = (buffer_size - sizeof(LLMemoryChunk) - mBlockLevels * sizeof(LLMemoryBlock*) - mPartitionLevels * sizeof(LLMemoryBlock*)) / (mMinBlockSize + sizeof(LLMemoryBlock)) ; @@ -535,10 +588,20 @@ void LLPrivateMemoryPool::LLMemoryChunk::init(char* buffer, U32 buffer_size, U32 mFreeSpaceList[i] = NULL ; } + mBlocks[0].mPrev = NULL ; + mBlocks[0].mNext = NULL ; mBlocks[0].setBuffer(mDataBuffer, buffer_size - (mDataBuffer - mBuffer)) ; + + //debug + U32 end = (mBlocks[0].getBufferSize() / mMinBlockSize) ; + for(U32 i = 1 ; i < end ; i++) + { + mBlocks[i].mSelf = NULL ; + } + addToFreeSpace(&mBlocks[0]) ; - mKey = (U32)mBuffer ; + mHashNext = NULL ; mNext = NULL ; mPrev = NULL ; } @@ -546,8 +609,14 @@ void LLPrivateMemoryPool::LLMemoryChunk::init(char* buffer, U32 buffer_size, U32 //static U32 LLPrivateMemoryPool::LLMemoryChunk::getMaxOverhead(U32 data_buffer_size, U32 min_page_size) { - return 2048 + - sizeof(LLMemoryBlock) * (data_buffer_size / min_page_size) ; + if(data_buffer_size / min_page_size < 64) //large allocations + { + return 4096 ; //4KB + } + else + { + return 0 ; //do not reserve extra overhead if for small allocations + } } char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) @@ -565,7 +634,6 @@ char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) if(blk->isFull()) { - //removeFromFreelist popAvailBlockList(blk_idx) ; } } @@ -580,7 +648,6 @@ char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) if(blk->isFull()) { - //removeFromFreelist popAvailBlockList(blk_idx) ; } } @@ -598,7 +665,6 @@ char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) if(blk->isFull()) { - //removeFromFreelist popAvailBlockList(i) ; } break ; @@ -606,8 +672,18 @@ char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) } } + llassert_always(!p || blk) ; + if(p && blk) { + if(blk->getTotalSlots() == 1) + { + llassert_always(blk->getBuffer() == (char*)p) ; + } + U32 blk_idx = getPageIndex((U32)p) ; + LLMemoryBlock* b = (LLMemoryBlock*)(mMetaBuffer + blk_idx * sizeof(LLMemoryBlock)) ; + llassert_always(blk == b || b->mSelf == blk) ; + mAlloatedSize += blk->getSlotSize() ; } return p ; @@ -615,23 +691,34 @@ char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) void LLPrivateMemoryPool::LLMemoryChunk::free(void* addr) { - U32 blk_idx = ((U32)addr - (U32)mDataBuffer) / mMinBlockSize ; - if(blk_idx > 0) blk_idx-- ; + U32 blk_idx = getPageIndex((U32)addr) ; LLMemoryBlock* blk = (LLMemoryBlock*)(mMetaBuffer + blk_idx * sizeof(LLMemoryBlock)) ; + llassert_always(blk->mSelf) ; blk = blk->mSelf ; + llassert_always(addr >= blk->getBuffer() && addr < blk->getBuffer() + blk->getBufferSize()) ; + if(blk->getTotalSlots() == 1) + { + llassert_always(blk->getBuffer() == (char*)addr) ; + } + bool was_full = blk->isFull() ; blk->free(addr) ; mAlloatedSize -= blk->getSlotSize() ; if(blk->empty()) { + blk->resetBitMap() ; //debug use removeBlock(blk) ; + + dump(); } else if(was_full) { addToAvailBlockList(blk) ; - } + + dump(); + } } bool LLPrivateMemoryPool::LLMemoryChunk::empty() @@ -639,35 +726,170 @@ bool LLPrivateMemoryPool::LLMemoryChunk::empty() return !mAlloatedSize ; } +bool LLPrivateMemoryPool::LLMemoryChunk::containsAddress(const char* addr) const +{ + return (U32)mBuffer <= (U32)addr && (U32)mBuffer + mBufferSize > (U32)addr ; +} + +void LLPrivateMemoryPool::LLMemoryChunk::dump() +{ + //sanity check + std::vector< LLMemoryBlock* > blk_list ; + for(std::set::iterator iter = mActiveBlockList.begin() ; iter != mActiveBlockList.end(); ++iter) + { + blk_list.push_back(*iter) ; + } + //for(S32 i = 0 ; i < mBlockLevels ; i++) + //{ + // LLMemoryBlock* blk = mAvailBlockList[i] ; + // while(blk) + // { + // blk_list.push_back(blk) ; + // blk = blk->mNext ; + // } + //} + for(S32 i = 0 ; i < mPartitionLevels ; i++) + { + LLMemoryBlock* blk = mFreeSpaceList[i] ; + while(blk) + { + blk_list.push_back(blk) ; + blk = blk->mNext ; + } + } + + std::sort(blk_list.begin(), blk_list.end(), LLMemoryBlock::CompareAddress()); + + U32 total_size = blk_list[0]->getBufferSize() ; + for(U32 i = 1 ; i < blk_list.size(); i++) + { + total_size += blk_list[i]->getBufferSize() ; + if((U32)blk_list[i]->getBuffer() < (U32)blk_list[i-1]->getBuffer() + blk_list[i-1]->getBufferSize()) + { + llerrs << "buffer corrupted." << llendl ; + } + } + + llassert_always(total_size + mMinBlockSize >= mBufferSize - ((U32)mDataBuffer - (U32)mBuffer)) ; + + U32 blk_num = (mBufferSize - (mDataBuffer - mBuffer)) / mMinBlockSize ; + for(U32 i = 0 ; i < blk_num ; ) + { + LLMemoryBlock* blk = &mBlocks[i] ; + if(blk->mSelf) + { + U32 end = blk->getBufferSize() / mMinBlockSize ; + for(U32 j = 0 ; j < end ; j++) + { + llassert_always(blk->mSelf == blk || !blk->mSelf) ; + } + i += end ; + } + else + { + llerrs << "gap happens" << llendl ; + } + } +#if 0 + llinfos << "---------------------------" << llendl ; + llinfos << "Chunk buffer: " << (U32)getBuffer() << " size: " << getBufferSize() << llendl ; + + llinfos << "available blocks ... " << llendl ; + for(S32 i = 0 ; i < mBlockLevels ; i++) + { + LLMemoryBlock* blk = mAvailBlockList[i] ; + while(blk) + { + llinfos << "blk buffer " << (U32)blk->getBuffer() << " size: " << blk->getBufferSize() << llendl ; + blk = blk->mNext ; + } + } + + llinfos << "free blocks ... " << llendl ; + for(S32 i = 0 ; i < mPartitionLevels ; i++) + { + LLMemoryBlock* blk = mFreeSpaceList[i] ; + while(blk) + { + llinfos << "blk buffer " << (U32)blk->getBuffer() << " size: " << blk->getBufferSize() << llendl ; + blk = blk->mNext ; + } + } +#endif +} + +U32 LLPrivateMemoryPool::LLMemoryChunk::calcBlockSize(U32 slot_size) +{ + // + //Note: we try to make a block to have 32 slots if the size is not over 32 pages + //32 is the number of bits of an integer in a 32-bit system + // + + U32 block_size; + U32 cut_off_size = llmin(CUT_OFF_SIZE, (U32)(mMinBlockSize << 5)) ; + + if((slot_size << 5) <= mMinBlockSize)//for small allocations, return one page + { + block_size = mMinBlockSize ; + } + else if(slot_size >= cut_off_size)//for large allocations, return one-slot block + { + block_size = (slot_size / mMinBlockSize) * mMinBlockSize ; + if(block_size < slot_size) + { + block_size += mMinBlockSize ; + } + } + else //medium allocations + { + if((slot_size << 5) >= cut_off_size) + { + block_size = cut_off_size ; + } + else + { + block_size = ((slot_size << 5) / mMinBlockSize) * mMinBlockSize ; + } + } + + llassert_always(block_size >= slot_size) ; + + return block_size ; +} + LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::addBlock(U32 blk_idx) { U32 slot_size = mMinSlotSize * (blk_idx + 1) ; - U32 preferred_block_size = llmax(mMinBlockSize, slot_size * 32) ; - preferred_block_size = llmin(preferred_block_size, mMaxBlockSize) ; - - U32 idx = preferred_block_size / mMinBlockSize - 1; - preferred_block_size = idx * mMinBlockSize ; //round to integer times of mMinBlockSize. + U32 preferred_block_size = calcBlockSize(slot_size) ; + + U16 idx = getPageLevel(preferred_block_size); + llassert_always(idx < mPartitionLevels - 1) ; + llassert_always(preferred_block_size == (idx + 1) * mMinBlockSize) ; //round to integer times of mMinBlockSize. LLMemoryBlock* blk = NULL ; if(mFreeSpaceList[idx])//if there is free slot for blk_idx { - blk = createNewBlock(&mFreeSpaceList[idx], preferred_block_size, slot_size, blk_idx) ; + blk = createNewBlock(mFreeSpaceList[idx], preferred_block_size, slot_size, blk_idx) ; } else if(mFreeSpaceList[mPartitionLevels - 1]) //search free pool { - blk = createNewBlock(&mFreeSpaceList[mPartitionLevels - 1], preferred_block_size, slot_size, blk_idx) ; + blk = createNewBlock(mFreeSpaceList[mPartitionLevels - 1], preferred_block_size, slot_size, blk_idx) ; } else //search for other non-preferred but enough space slot. { - for(U32 i = idx - 1 ; i >= 0 ; i--) //search the small slots first + for(S32 i = (S32)idx - 1 ; i >= 0 ; i--) //search the small slots first { if(mFreeSpaceList[i]) { + U32 new_preferred_block_size = mFreeSpaceList[i]->getBufferSize(); + new_preferred_block_size = (new_preferred_block_size / mMinBlockSize) * mMinBlockSize ; //round to integer times of mMinBlockSize. + //create a NEW BLOCK THERE. - if(mFreeSpaceList[i]->getBufferSize() >= slot_size) //at least there is space for one slot. + if(new_preferred_block_size >= slot_size) //at least there is space for one slot. { - blk = createNewBlock(&mFreeSpaceList[i], preferred_block_size, slot_size, blk_idx) ; + + blk = createNewBlock(mFreeSpaceList[i], new_preferred_block_size, slot_size, blk_idx) ; } break ; } @@ -680,70 +902,72 @@ LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::addBlock if(mFreeSpaceList[i]) { //create a NEW BLOCK THERE. - blk = createNewBlock(&mFreeSpaceList[i], preferred_block_size, slot_size, blk_idx) ; + blk = createNewBlock(mFreeSpaceList[i], preferred_block_size, slot_size, blk_idx) ; break ; } } } } + dump() ; + return blk ; } -LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::createNewBlock(LLMemoryBlock** cur_idxp, U32 buffer_size, U32 slot_size, U32 blk_idx) +char* _prev = NULL ; +LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::createNewBlock(LLMemoryBlock* blk, U32 buffer_size, U32 slot_size, U32 blk_idx) { - LLMemoryBlock* blk = *cur_idxp ; - - buffer_size = llmin(buffer_size, blk->getBufferSize()) ; - U32 new_free_blk_size = blk->getBufferSize() - buffer_size ; - if(new_free_blk_size < mMinBlockSize) //can not partition the memory into size smaller than mMinBlockSize + llassert_always(blk->getBufferSize() >= buffer_size) ; + + //debug { - buffer_size += new_free_blk_size ; - new_free_blk_size = 0 ; + { + U32 blk_idx = getPageIndex((U32)blk->getBuffer()) ; + llassert_always(blk == (LLMemoryBlock*)(mMetaBuffer + blk_idx * sizeof(LLMemoryBlock))) ; + } + U32 end = (blk->getBufferSize() / mMinBlockSize) ; + llassert_always(blk->mSelf == blk && blk->isFree()) ; + llassert_always((blk + end - 1)->mSelf == blk) ; + for(U32 i = 1 ; i < end - 1; i++) + { + llassert_always(!(blk + i)->mSelf) ; + } } - blk->init(blk->getBuffer(), buffer_size, slot_size) ; - - if(new_free_blk_size > 0) //cur_idx still has free space + + //unlink from the free space + removeFromFreeSpace(blk) ; + + //check the rest space + U32 new_free_blk_size = blk->getBufferSize() - buffer_size ; + if(new_free_blk_size < mMinBlockSize) //can not partition the memory into size smaller than mMinBlockSize + { + new_free_blk_size = 0 ; //discard the last small extra space. + } + + //add the rest space back to the free list + if(new_free_blk_size > 0) //blk still has free space { LLMemoryBlock* next_blk = blk + (buffer_size / mMinBlockSize) ; next_blk->setBuffer(blk->getBuffer() + buffer_size, new_free_blk_size) ; - - if(new_free_blk_size > mMaxBlockSize) //stays in the free pool - { - next_blk->mPrev = NULL ; - next_blk->mNext = blk->mNext ; - if(next_blk->mNext) - { - next_blk->mNext->mPrev = next_blk ; - } - *cur_idxp = next_blk ; - } - else - { - *cur_idxp = blk->mNext ; //move to the next slot - if(*cur_idxp) - { - (*cur_idxp)->mPrev = NULL ; - } - addToFreeSpace(next_blk) ; - } - } - else //move to the next block - { - *cur_idxp = blk->mNext ; - if(*cur_idxp) { - (*cur_idxp)->mPrev = NULL ; + U32 blk_idx = getPageIndex((U32)next_blk->getBuffer()) ; + llassert_always(next_blk == (LLMemoryBlock*)(mMetaBuffer + blk_idx * sizeof(LLMemoryBlock))) ; } + llassert_always(buffer_size == (buffer_size / mMinBlockSize) * mMinBlockSize) ; + llassert_always(((U32)next_blk->getBuffer() - (U32)mDataBuffer) == ((U32)next_blk->getBuffer() - (U32)mDataBuffer) / mMinBlockSize * mMinBlockSize) ; + addToFreeSpace(next_blk) ; } + blk->init(blk->getBuffer(), buffer_size, slot_size) ; //insert to the available block list... - blk->mNext = NULL ; - blk->mPrev = NULL ; - blk->mSelf = blk ; + llassert_always(!mAvailBlockList[blk_idx]) ; mAvailBlockList[blk_idx] = blk ; + llassert_always(blk->getTotalSlots() > 0) ; + llassert_always(mAvailBlockList[blk_idx]->getSlotSize() == (blk_idx + 1) * mMinSlotSize) ; + llassert_always(buffer_size == (buffer_size / mMinBlockSize) * mMinBlockSize) ; + //mark the address map U32 end = (buffer_size / mMinBlockSize) ; for(U32 i = 1 ; i < end ; i++) @@ -751,6 +975,12 @@ LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::createNe (blk + i)->mSelf = blk ; } + llassert_always(blk->getBuffer() != _prev) ; + + llassert_always(mActiveBlockList.find(blk) == mActiveBlockList.end()) ; + + mActiveBlockList.insert(blk) ; + return blk ; } @@ -765,29 +995,54 @@ void LLPrivateMemoryPool::LLMemoryChunk::removeBlock(LLMemoryBlock* blk) { blk->mNext->mPrev = blk->mPrev ; } + U32 blk_idx = getBlockLevel(blk->getSlotSize()); + if(mAvailBlockList[blk_idx] == blk) + { + mAvailBlockList[blk_idx] = blk->mNext ; + } + + blk->mNext = NULL ; + blk->mPrev = NULL ; + + std::set::iterator iter = mActiveBlockList.find(blk) ; + llassert_always(iter != mActiveBlockList.end()) ; + mActiveBlockList.erase(iter) ; //mark it free blk->setBuffer(blk->getBuffer(), blk->getBufferSize()) ; + //debug + U32 end = (blk->getBufferSize() / mMinBlockSize) ; + for(U32 i = 1 ; i < end ; i++) + { + llassert_always((blk + i)->mSelf == blk) ; + (blk + i)->mSelf = NULL ; + } +#if 0 //merge blk with neighbors if possible if(blk->getBuffer() > mDataBuffer) //has the left neighbor { if((blk - 1)->mSelf->isFree()) { + LLMemoryBlock* left_blk = (blk - 1)->mSelf ; removeFromFreeSpace((blk - 1)->mSelf); - (blk - 1)->mSelf->setBuffer((blk-1)->mSelf->getBuffer(), (blk-1)->mSelf->getBufferSize() + blk->getBufferSize()) ; - blk = (blk - 1)->mSelf ; + left_blk->setBuffer(left_blk->getBuffer(), left_blk->getBufferSize() + blk->getBufferSize()) ; + blk = left_blk ; } } - if(blk->getBuffer() + blk->getBufferSize() < mBuffer + mBufferSize) //has the right neighbor + if(blk->getBuffer() + blk->getBufferSize() <= mBuffer + mBufferSize - mMinBlockSize) //has the right neighbor { U32 d = blk->getBufferSize() / mMinBlockSize ; if((blk + d)->isFree()) { + LLMemoryBlock* right_blk = blk + d ; removeFromFreeSpace(blk + d) ; - blk->setBuffer(blk->getBuffer(), blk->getBufferSize() + (blk + d)->getBufferSize()) ; + blk->setBuffer(blk->getBuffer(), blk->getBufferSize() + right_blk->getBufferSize()) ; } } +#endif + llassert_always(blk->getBuffer() != _prev) ; + llassert_always(mActiveBlockList.find(blk) == mActiveBlockList.end()) ; addToFreeSpace(blk) ; @@ -800,16 +1055,29 @@ void LLPrivateMemoryPool::LLMemoryChunk::popAvailBlockList(U32 blk_idx) if(mAvailBlockList[blk_idx]) { LLMemoryBlock* next = mAvailBlockList[blk_idx]->mNext ; - next->mPrev = NULL ; + if(next) + { + next->mPrev = NULL ; + } + mAvailBlockList[blk_idx]->mPrev = NULL ; mAvailBlockList[blk_idx]->mNext = NULL ; mAvailBlockList[blk_idx] = next ; + if(next) + { + llassert_always(mAvailBlockList[blk_idx]->getTotalSlots() > 0) ; + llassert_always(mAvailBlockList[blk_idx]->getSlotSize() == (blk_idx + 1) * mMinSlotSize) ; + } + + dump() ; } } void LLPrivateMemoryPool::LLMemoryChunk::addToFreeSpace(LLMemoryBlock* blk) { - U16 free_idx = blk->getBufferSize() / mMinBlockSize; - if(free_idx > 0) free_idx--; + llassert_always(!blk->mPrev) ; + llassert_always(!blk->mNext) ; + + U16 free_idx = blk->getBufferSize() / mMinBlockSize - 1; (blk + free_idx)->mSelf = blk ; //mark the end pointing back to the head. free_idx = llmin(free_idx, (U16)(mPartitionLevels - 1)) ; @@ -828,8 +1096,7 @@ void LLPrivateMemoryPool::LLMemoryChunk::addToFreeSpace(LLMemoryBlock* blk) void LLPrivateMemoryPool::LLMemoryChunk::removeFromFreeSpace(LLMemoryBlock* blk) { - U16 free_idx = blk->getBufferSize() / mMinBlockSize; - if(free_idx > 0) free_idx-- ; + U16 free_idx = blk->getBufferSize() / mMinBlockSize - 1; free_idx = llmin(free_idx, (U16)(mPartitionLevels - 1)) ; if(mFreeSpaceList[free_idx] == blk) @@ -844,37 +1111,70 @@ void LLPrivateMemoryPool::LLMemoryChunk::removeFromFreeSpace(LLMemoryBlock* blk) { blk->mNext->mPrev = blk->mPrev ; } - + blk->mNext = NULL ; + blk->mPrev = NULL ; + blk->mSelf = NULL ; + return ; } void LLPrivateMemoryPool::LLMemoryChunk::addToAvailBlockList(LLMemoryBlock* blk) { + llassert_always(!blk->mPrev) ; + llassert_always(!blk->mNext) ; + U32 blk_idx = getBlockLevel(blk->getSlotSize()); + llassert_always(blk->getSlotSize() == (blk_idx + 1) * mMinSlotSize) ; + blk->mNext = mAvailBlockList[blk_idx] ; if(blk->mNext) { blk->mNext->mPrev = blk ; } blk->mPrev = NULL ; - + mAvailBlockList[blk_idx] = blk ; + + llassert_always(mAvailBlockList[blk_idx]->getTotalSlots() > 0) ; + llassert_always(mAvailBlockList[blk_idx]->getSlotSize() == (blk_idx + 1) * mMinSlotSize) ; + return ; } +U32 LLPrivateMemoryPool::LLMemoryChunk::getPageIndex(U32 addr) +{ + return (addr - (U32)mDataBuffer) / mMinBlockSize ; +} + +//for mAvailBlockList U32 LLPrivateMemoryPool::LLMemoryChunk::getBlockLevel(U32 size) { + llassert(size >= mMinSlotSize && size <= mMaxSlotSize) ; + + //start from 0 return (size + mMinSlotSize - 1) / mMinSlotSize - 1 ; } -U32 LLPrivateMemoryPool::LLMemoryChunk::getPageLevel(U32 size) +//for mFreeSpaceList +U16 LLPrivateMemoryPool::LLMemoryChunk::getPageLevel(U32 size) { - return (size + mMinBlockSize - 1) / mMinBlockSize - 1 ; + llassert_always(size >= mMinBlockSize); + llassert_always(!(size % mMinBlockSize)) ; + + //start from 0 + U16 level = size / mMinBlockSize - 1 ; + if(level >= mPartitionLevels) + { + level = mPartitionLevels - 1 ; + } + return level ; } //------------------------------------------------------------------- //class LLPrivateMemoryPool //-------------------------------------------------------------------- +const U32 CHUNK_SIZE = 4 << 20 ; //4 MB +const U32 HASH_FACTOR = 255 ; LLPrivateMemoryPool::LLPrivateMemoryPool(U32 max_size, bool threaded) : mMutexp(NULL), mMaxPoolSize(max_size), @@ -890,8 +1190,12 @@ LLPrivateMemoryPool::LLPrivateMemoryPool(U32 max_size, bool threaded) : mChunkList[i] = NULL ; } - mChunkVectorCapacity = 128 ; - mChunks.resize(mChunkVectorCapacity) ; //at most 128 chunks + mChunkHashList.resize(HASH_FACTOR + 1) ; + for(U32 i = 0 ; i <= HASH_FACTOR ; i++) + { + mChunkHashList[i] = NULL ; + } + mNumOfChunks = 0 ; } @@ -903,15 +1207,13 @@ LLPrivateMemoryPool::~LLPrivateMemoryPool() char* LLPrivateMemoryPool::allocate(U32 size) { - const static U32 MAX_BLOCK_SIZE = 4 * 1024 * 1024 ; //4MB - if(!size) { return NULL ; } //if the asked size larger than MAX_BLOCK_SIZE, fetch from heap directly, the pool does not manage it - if(size >= MAX_BLOCK_SIZE) + if(size >= CHUNK_SIZE) { return new char[size] ; } @@ -936,6 +1238,19 @@ char* LLPrivateMemoryPool::allocate(U32 size) //fetch new memory chunk if(!p) { + if(mReservedPoolSize + CHUNK_SIZE > mMaxPoolSize) + { + chunk = mChunkList[chunk_idx]; + while(chunk) + { + if(p = chunk->allocate(size)) + { + break ; + } + chunk = chunk->mNext ; + } + } + chunk = addChunk(chunk_idx) ; if(chunk) { @@ -957,28 +1272,92 @@ void LLPrivateMemoryPool::free(void* addr) lock() ; - LLMemoryChunk* chunk = mChunks[findChunk((char*)addr)] ; + U16 key ; + LLMemoryChunk* chunk =findChunk((char*)addr, key) ; + if(!chunk) { delete[] (char*)addr ; //release from heap } else { + llassert_always((U32)addr >= (U32)chunk->getBuffer() && (U32)addr < (U32)chunk->getBuffer() + chunk->getBufferSize()) ; + chunk->free(addr) ; if(chunk->empty()) { - removeChunk(chunk) ; + removeChunk(chunk, key) ; } } unlock() ; } +LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::findChunk(const char* addr, U16& key) +{ + key = findHashKey(addr) ; + + //check the hash value "key" + LLMemoryChunk* chunk = mChunkHashList[key] ; + while(chunk && !chunk->containsAddress(addr)) + { + chunk = chunk->mHashNext ; + } + + if(!chunk && key > 0) //check the "key - 1" + { + chunk = mChunkHashList[key - 1] ; + while(chunk && !chunk->containsAddress(addr)) + { + chunk = chunk->mHashNext ; + } + + if(chunk) + { + key-- ; + } + } + + if(!chunk && key < HASH_FACTOR) //check the "key + 1" + { + chunk = mChunkHashList[key + 1] ; + while(chunk && !chunk->containsAddress(addr)) + { + chunk = chunk->mHashNext ; + } + + if(chunk) + { + key++ ; + } + } + + return chunk ; +} + void LLPrivateMemoryPool::dump() { } +U32 LLPrivateMemoryPool::getTotalAllocatedSize() +{ + U32 total_allocated = 0 ; + + LLMemoryChunk* chunk ; + for(S32 i = 0 ; i < SUPER_ALLOCATION ; i++) + { + chunk = mChunkList[i]; + while(chunk) + { + total_allocated += chunk->getAllocatedSize() ; + chunk = chunk->mNext ; + } + } + + return total_allocated ; +} + void LLPrivateMemoryPool::lock() { if(mMutexp) @@ -997,58 +1376,72 @@ void LLPrivateMemoryPool::unlock() S32 LLPrivateMemoryPool::getChunkIndex(U32 size) { - if(size < 2048) - { - return 0 ; - } - else if(size < (512 << 10)) - { - return 1 ; - } - else - { - return 2 ; - } + S32 i ; + for(i = 0 ; size > MAX_SLOT_SIZES[i]; i++); + + llassert_always(i < SUPER_ALLOCATION); + + return i ; } //destroy the entire pool void LLPrivateMemoryPool::destroyPool() { - for(U16 i = 0 ; i < mNumOfChunks ; i++) + lock() ; + for(U32 i = 0 ; i <= HASH_FACTOR; i++) { - delete[] mChunks[i]->getBuffer() ; + while(mChunkHashList[i]) + { + removeChunk(mChunkHashList[i], i) ; + } } - mNumOfChunks = 0 ; + llassert_always(mNumOfChunks == 0) ; + llassert_always(mReservedPoolSize == 0) ; + for(S32 i = 0 ; i < SUPER_ALLOCATION ; i++) { mChunkList[i] = NULL ; } + + unlock() ; } -LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::addChunk(S32 chunk_index) +void LLPrivateMemoryPool::checkSize(U32 asked_size) { - static const U32 MIN_BLOCK_SIZES[SUPER_ALLOCATION] = {2 << 10, 32 << 10, 64 << 10} ; - static const U32 MAX_BLOCK_SIZES[SUPER_ALLOCATION] = {64 << 10, 1 << 20, 4 << 20} ; - static const U32 MIN_SLOT_SIZES[SUPER_ALLOCATION] = {8, 2 << 10, 512 << 10}; - static const U32 MAX_SLOT_SIZES[SUPER_ALLOCATION] = {(2 << 10) - 8, (512 - 2) << 10, 4 << 20}; + if(mReservedPoolSize + asked_size > mMaxPoolSize) + { + llinfos << "Max pool size: " << mMaxPoolSize << llendl ; + llinfos << "Total reserved size: " << mReservedPoolSize + asked_size << llendl ; + llinfos << "Total_allocated Size: " << getTotalAllocatedSize() << llendl ; + + llerrs << "The pool is overflowing..." << llendl ; + } +} +LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::addChunk(S32 chunk_index) +{ U32 preferred_size ; U32 overhead ; if(chunk_index < LARGE_ALLOCATION) { - preferred_size = (4 << 20) ; //4MB + preferred_size = CHUNK_SIZE ; //4MB overhead = LLMemoryChunk::getMaxOverhead(preferred_size, MIN_BLOCK_SIZES[chunk_index]) ; } else { - preferred_size = (16 << 20) ; //16MB + preferred_size = 4 * CHUNK_SIZE ; //16MB overhead = LLMemoryChunk::getMaxOverhead(preferred_size, MIN_BLOCK_SIZES[chunk_index]) ; } + + checkSize(preferred_size + overhead) ; + mReservedPoolSize += preferred_size + overhead ; + char* buffer = new(std::nothrow) char[preferred_size + overhead] ; if(!buffer) { return NULL ; } + memset(buffer, 0, preferred_size + overhead) ; LLMemoryChunk* chunk = new (buffer) LLMemoryChunk() ; chunk->init(buffer, preferred_size + overhead, MIN_SLOT_SIZES[chunk_index], @@ -1063,37 +1456,35 @@ LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::addChunk(S32 chunk_inde chunk->mPrev = NULL ; mChunkList[chunk_index] = chunk ; - //insert into the array - llassert_always(mNumOfChunks + 1 < mChunkVectorCapacity) ; - if(!mNumOfChunks) - { - mChunks[0] = chunk ; - } - else - { - U16 k ; - if(mChunks[0]->getBuffer() > chunk->getBuffer()) - { - k = 0 ; - } - else - { - k = findChunk(chunk->getBuffer()) + 1 ; - } - for(U16 i = mNumOfChunks ; i > k ; i++) - { - mChunks[i] = mChunks[i-1] ; - } - mChunks[k] = chunk ; - } + //insert into the hash table + U16 key = findHashKey(chunk->getBuffer()) ; + chunk->mHashNext = mChunkHashList[key] ; + mChunkHashList[key] = chunk ; + mNumOfChunks++; return chunk ; } -void LLPrivateMemoryPool::removeChunk(LLMemoryChunk* chunk) +char*** _p = NULL ; +U32 _times; +U32 _levels; +void LLPrivateMemoryPool::removeChunk(LLMemoryChunk* chunk, U16 key) { + if(!chunk) + { + return ; + } + //remove from the linked list + for(S32 i = 0 ; i < SUPER_ALLOCATION ; i++) + { + if(mChunkList[i] == chunk) + { + mChunkList[i] = chunk->mNext ; + } + } + if(chunk->mPrev) { chunk->mPrev->mNext = chunk->mNext ; @@ -1103,43 +1494,47 @@ void LLPrivateMemoryPool::removeChunk(LLMemoryChunk* chunk) chunk->mNext->mPrev = chunk->mPrev ; } - //remove from the array - U16 k = findChunk(chunk->getBuffer()) ; - mNumOfChunks--; - for(U16 i = k ; i < mNumOfChunks ; i++) + //remove from the hash table + if(mChunkHashList[key] == chunk) { - mChunks[i] = mChunks[i+1] ; + mChunkHashList[key] = chunk->mHashNext ; } - - //release memory - delete[] chunk->getBuffer() ; -} - -U16 LLPrivateMemoryPool::findChunk(const char* addr) -{ - llassert_always(mNumOfChunks > 0) ; - - U16 s = 0, e = mNumOfChunks; - U16 k = (s + e) / 2 ; - while(s < e) + else { - if(mChunks[k]->mKey > (U32)addr) + LLMemoryChunk* prev = mChunkHashList[key] ; + while(prev->mHashNext && prev->mHashNext != chunk) { - e = k ; + prev = prev->mHashNext ; } - else if(k < mNumOfChunks - 1 && mChunks[k+1]->mKey < (U32)addr) - { - s = k ; - } - else + llassert_always(prev->mHashNext == chunk) ; + + prev->mHashNext = chunk->mHashNext ; + } + mNumOfChunks--; + mReservedPoolSize -= chunk->getBufferSize() ; + + //debug check + if(_p) + { + for(U32 i = 0 ; i < _times; i++) { - break ; + for(U32 j = 0 ; j < _levels ;j++) + { + if( i == col && j == row) + { + continue ; + } + llassert_always(!_p[i][j] || !chunk->containsAddress(_p[i][j])) ; + } } - - k = (s + e) / 2 ; } + //release memory + delete[] chunk->getBuffer() ; +} - return k ; +U16 LLPrivateMemoryPool::findHashKey(const char* addr) +{ + return (((U32)addr) / CHUNK_SIZE) % HASH_FACTOR ; } //-------------------------------------------------------------------- @@ -1182,7 +1577,7 @@ void LLPrivateMemoryPoolTester::destroy() void LLPrivateMemoryPoolTester::run(bool threaded) { - const U32 max_pool_size = 16 << 20 ; + const U32 max_pool_size = 1024 << 20 ; if(sPool) { @@ -1192,8 +1587,8 @@ void LLPrivateMemoryPoolTester::run(bool threaded) //run the test correctnessTest() ; - performanceTest() ; - fragmentationtest() ; + //performanceTest() ; + //fragmentationtest() ; //release pool. ::delete sPool ; @@ -1206,6 +1601,7 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 U32 levels = (max_size - min_size) / stride + 1 ; char*** p ; U32 i, j ; + U32 total_allocated_size = 0 ; //allocate space for p ; if(!(p = ::new char**[times]) || !(*p = ::new char*[times * levels])) @@ -1223,6 +1619,10 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 } } + _p = p ; + _times = times; + _levels = levels ; + //allocation U32 size ; for(i = 0 ; i < times ; i++) @@ -1230,15 +1630,33 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 for(j = 0 ; j < levels; j++) { size = min_size + j * stride ; - p[i][j] = sPool->allocate(size) ; - p[i][j][size - 1] = '\0' ; //access the last element to verify the success of the allocation. + _prev = p[i][j] = sPool->allocate(size) ; + + total_allocated_size+= size ; + + *(U32*)p[i][j] = i ; + *((U32*)p[i][j] + 1) = j ; + //p[i][j][size - 1] = '\0' ; //access the last element to verify the success of the allocation. //randomly release memory if(random_deletion) { S32 k = rand() % levels ; - sPool->free(p[i][k]) ; - p[i][k] = NULL ; + + col = i ; + row = k ; + + if(p[i][k]) + { + if(_prev == p[i][k]) + { + _prev = NULL ; + } + llassert_always(*(U32*)p[i][k] == i && *((U32*)p[i][k] + 1) == k) ; + sPool->free(p[i][k]) ; + total_allocated_size -= min_size + k * stride ; + p[i][k] = NULL ; + } } } } @@ -1248,18 +1666,28 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 { } + _prev = NULL ; //release all memory allocations for(i = 0 ; i < times; i++) { for(j = 0 ; j < levels; j++) { - sPool->free(p[i][j]) ; - p[i][j] = NULL ; + col = i ; + row = j ; + + if(p[i][j]) + { + llassert_always(*(U32*)p[i][j] == i && *((U32*)p[i][j] + 1) == j) ; + sPool->free(p[i][j]) ; + total_allocated_size -= min_size + j * stride ; + p[i][j] = NULL ; + } } } ::delete[] *p ; ::delete[] p ; + _p = NULL ; } void LLPrivateMemoryPoolTester::correctnessTest() @@ -1281,7 +1709,7 @@ void LLPrivateMemoryPoolTester::correctnessTest() //large sized //[512KB, 4MB], each asks for 8 allocations and deallocations - test(512 * 1024, 4 * 1024 * 1024, 64 * 1024, 8, true, true) ; + test(512 * 1024, 4 * 1024 * 1024, 64 * 1024, 6, true, true) ; } void LLPrivateMemoryPoolTester::performanceTest() diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 128e7aefe6..f0e26d6b2f 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -95,6 +95,8 @@ public: U32 getBufferSize()const {return mBufferSize;} char* getBuffer() const {return mBuffer;} + //debug use + void resetBitMap() ; private: char* mBuffer; U32 mSlotSize ; //when the block is not initialized, it is the buffer size. @@ -108,6 +110,14 @@ public: LLMemoryBlock* mPrev ; LLMemoryBlock* mNext ; LLMemoryBlock* mSelf ; + + struct CompareAddress + { + bool operator()(const LLMemoryBlock* const& lhs, const LLMemoryBlock* const& rhs) + { + return (U32)lhs->getBuffer() < (U32)rhs->getBuffer(); + } + }; }; class LL_COMMON_API LLMemoryChunk //is divided into memory blocks. @@ -126,19 +136,26 @@ public: const char* getBuffer() const {return mBuffer;} U32 getBufferSize() const {return mBufferSize;} + U32 getAllocatedSize() const {return mAlloatedSize;} + + bool containsAddress(const char* addr) const; static U32 getMaxOverhead(U32 data_buffer_size, U32 min_page_size) ; + void dump() ; + private: + U32 getPageIndex(U32 addr) ; U32 getBlockLevel(U32 size) ; - U32 getPageLevel(U32 size) ; + U16 getPageLevel(U32 size) ; LLMemoryBlock* addBlock(U32 blk_idx) ; void popAvailBlockList(U32 blk_idx) ; void addToFreeSpace(LLMemoryBlock* blk) ; void removeFromFreeSpace(LLMemoryBlock* blk) ; void removeBlock(LLMemoryBlock* blk) ; void addToAvailBlockList(LLMemoryBlock* blk) ; - LLMemoryBlock* createNewBlock(LLMemoryBlock** cur_idxp, U32 buffer_size, U32 slot_size, U32 blk_idx) ; + U32 calcBlockSize(U32 slot_size); + LLMemoryBlock* createNewBlock(LLMemoryBlock* blk, U32 buffer_size, U32 slot_size, U32 blk_idx) ; private: LLMemoryBlock** mAvailBlockList ;//256 by mMinSlotSize @@ -150,18 +167,21 @@ public: char* mDataBuffer ; char* mMetaBuffer ; U32 mMinBlockSize ; - U32 mMaxBlockSize; U32 mMinSlotSize ; + U32 mMaxSlotSize ; U32 mAlloatedSize ; U16 mBlockLevels; U16 mPartitionLevels; + //debug use + std::set mActiveBlockList ; + public: //form a linked list LLMemoryChunk* mNext ; LLMemoryChunk* mPrev ; - U32 mKey ; //= mBuffer + LLMemoryChunk* mHashNext ; } ; public: @@ -170,22 +190,22 @@ public: char *allocate(U32 size) ; void free(void* addr) ; + void dump() ; + U32 getTotalAllocatedSize() ; private: void lock() ; void unlock() ; S32 getChunkIndex(U32 size) ; LLMemoryChunk* addChunk(S32 chunk_index) ; - void removeChunk(LLMemoryChunk* chunk) ; - U16 findChunk(const char* addr) ; + void checkSize(U32 asked_size) ; + void removeChunk(LLMemoryChunk* chunk, U16 key) ; + U16 findHashKey(const char* addr); + LLMemoryChunk* findChunk(const char* addr, U16& key) ; void destroyPool() ; -private: - LLMutex* mMutexp ; - U32 mMaxPoolSize; - U32 mReservedPoolSize ; - +public: enum { SMALL_ALLOCATION = 0, //from 8 bytes to 2KB(exclusive), page size 2KB, max chunk size is 4MB. @@ -194,10 +214,14 @@ private: SUPER_ALLOCATION //allocation larger than 4MB. }; +private: + LLMutex* mMutexp ; + U32 mMaxPoolSize; + U32 mReservedPoolSize ; + LLMemoryChunk* mChunkList[SUPER_ALLOCATION] ; //all memory chunks reserved by this pool, sorted by address - std::vector mChunks ; + std::vector mChunkHashList ; U16 mNumOfChunks ; - U16 mChunkVectorCapacity ; }; // -- cgit v1.2.3 From f4a8027feb2bbeafe7b0cfb3b05fd27f3cf243d3 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Thu, 6 Jan 2011 12:36:44 -0700 Subject: removed some debug code, redesigned the hash function, fixed bugs --- indra/llcommon/llmemory.cpp | 605 +++++++++++++++++++++--------------------- indra/llcommon/llmemory.h | 13 +- indra/newview/llappviewer.cpp | 6 +- 3 files changed, 320 insertions(+), 304 deletions(-) (limited to 'indra') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 00ef09d7a2..f9a2770691 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -356,7 +356,8 @@ U64 LLMemory::getCurrentRSS() #endif -//------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- //minimum block sizes (page size) for small allocation, medium allocation, large allocation const U32 MIN_BLOCK_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {2 << 10, 4 << 10, 16 << 10} ; // @@ -389,6 +390,7 @@ LLPrivateMemoryPool::LLMemoryBlock::~LLMemoryBlock() //empty } +//create and initialize a memory block void LLPrivateMemoryPool::LLMemoryBlock::init(char* buffer, U32 buffer_size, U32 slot_size) { llassert_always(buffer_size >= slot_size) ; @@ -397,17 +399,20 @@ void LLPrivateMemoryPool::LLMemoryBlock::init(char* buffer, U32 buffer_size, U32 mBufferSize = buffer_size ; mSlotSize = slot_size ; mTotalSlots = buffer_size / mSlotSize ; + llassert_always(mTotalSlots < 256) ; //max number is 256 + mAllocatedSlots = 0 ; + //init the bit map. //mark free bits S32 usage_bit_len = (mTotalSlots + 31) / 32 ; - mDummySize = usage_bit_len - 1 ; - if(mDummySize > 0) //extra space to store mUsageBits + mDummySize = usage_bit_len - 1 ; //if the mTotalSlots more than 32, needs extra space for bit map + if(mDummySize > 0) //reserve extra space from mBuffer to store bitmap if needed. { mTotalSlots -= (mDummySize * sizeof(mUsageBits) + mSlotSize - 1) / mSlotSize ; usage_bit_len = (mTotalSlots + 31) / 32 ; - mDummySize = usage_bit_len - 1 ; + mDummySize = usage_bit_len - 1 ;//number of 32bits reserved from mBuffer for bitmap if(mDummySize > 0) { @@ -423,7 +428,7 @@ void LLPrivateMemoryPool::LLMemoryBlock::init(char* buffer, U32 buffer_size, U32 } } - if(mDummySize < 1) + if(mDummySize < 1)//no extra bitmap space reserved { mUsageBits = 0 ; if(mTotalSlots & 31) @@ -439,16 +444,16 @@ void LLPrivateMemoryPool::LLMemoryBlock::init(char* buffer, U32 buffer_size, U32 llassert_always(mTotalSlots > 0) ; } +//mark this block to be free with the memory [mBuffer, mBuffer + mBufferSize). void LLPrivateMemoryPool::LLMemoryBlock::setBuffer(char* buffer, U32 buffer_size) { - llassert_always(buffer_size <= (16 << 20)) ; - mBuffer = buffer ; mBufferSize = buffer_size ; mSelf = NULL ; mTotalSlots = 0 ; //set the block is free. } +//reserve a slot char* LLPrivateMemoryPool::LLMemoryBlock::allocate() { llassert_always(mAllocatedSlots < mTotalSlots) ; @@ -479,47 +484,31 @@ char* LLPrivateMemoryPool::LLMemoryBlock::allocate() //set the slot reserved if(!idx) { - llassert_always(!(*bits & 1)); *bits |= 1 ; } else { - llassert_always(!(*bits & (1 << idx))) ; *bits |= (1 << idx) ; } mAllocatedSlots++ ; - //return mBuffer + mDummySize * sizeof(U32) + (k * 32 + idx) * mSlotSize ; - - char* p = mBuffer + mDummySize * sizeof(U32) + (k * 32 + idx) * mSlotSize ; - llassert_always(mBuffer != p || !mDummySize) ; - llassert_always(*(U32*)p == 0 && *((U32*)p + 1) == 0) ; - - return p ; + return mBuffer + mDummySize * sizeof(U32) + (k * 32 + idx) * mSlotSize ; } -U32 col = 0, row = 0 ; +//free a slot void LLPrivateMemoryPool::LLMemoryBlock::free(void* addr) { - llassert_always((U32)addr >= (U32)mBuffer + mDummySize * sizeof(U32) && - (U32)addr < (U32)mBuffer + mBufferSize) ; - + //bit index U32 idx = ((U32)addr - (U32)mBuffer - mDummySize * sizeof(U32)) / mSlotSize ; - llassert_always(idx < mTotalSlots) ; - llassert_always(addr == mBuffer + mDummySize * sizeof(U32) + idx * mSlotSize) ; - llassert_always(*(U32*)addr == col && *((U32*)addr + 1) == row) ; - - *(U32*)addr = 0 ; - *((U32*)addr + 1) = 0 ; - U32* bits = &mUsageBits ; if(idx >= 32) { bits = (U32*)mBuffer + (idx - 32) / 32 ; } + //reset the bit if(idx & 31) { *bits &= ~(1 << (idx & 31)) ; @@ -532,7 +521,7 @@ void LLPrivateMemoryPool::LLMemoryBlock::free(void* addr) mAllocatedSlots-- ; } -//for debug use +//for debug use: reset the entire bitmap. void LLPrivateMemoryPool::LLMemoryBlock::resetBitMap() { for(S32 i = 0 ; i < mDummySize ; i++) @@ -554,6 +543,7 @@ LLPrivateMemoryPool::LLMemoryChunk::~LLMemoryChunk() //empty } +//create and init a memory chunk void LLPrivateMemoryPool::LLMemoryChunk::init(char* buffer, U32 buffer_size, U32 min_slot_size, U32 max_slot_size, U32 min_block_size, U32 max_block_size) { mBuffer = buffer ; @@ -562,7 +552,7 @@ void LLPrivateMemoryPool::LLMemoryChunk::init(char* buffer, U32 buffer_size, U32 mMetaBuffer = mBuffer + sizeof(LLMemoryChunk) ; - mMinBlockSize = min_block_size; + mMinBlockSize = min_block_size; //page size mMinSlotSize = min_slot_size; mMaxSlotSize = max_slot_size ; mBlockLevels = mMaxSlotSize / mMinSlotSize ; @@ -571,11 +561,11 @@ void LLPrivateMemoryPool::LLMemoryChunk::init(char* buffer, U32 buffer_size, U32 S32 max_num_blocks = (buffer_size - sizeof(LLMemoryChunk) - mBlockLevels * sizeof(LLMemoryBlock*) - mPartitionLevels * sizeof(LLMemoryBlock*)) / (mMinBlockSize + sizeof(LLMemoryBlock)) ; //meta data space - mBlocks = (LLMemoryBlock*)mMetaBuffer ; + mBlocks = (LLMemoryBlock*)mMetaBuffer ; //space reserved for all memory blocks. mAvailBlockList = (LLMemoryBlock**)((char*)mBlocks + sizeof(LLMemoryBlock) * max_num_blocks) ; mFreeSpaceList = (LLMemoryBlock**)((char*)mAvailBlockList + sizeof(LLMemoryBlock*) * mBlockLevels) ; - //data buffer + //data buffer, which can be used for allocation mDataBuffer = (char*)mFreeSpaceList + sizeof(LLMemoryBlock*) * mPartitionLevels ; //init @@ -588,17 +578,10 @@ void LLPrivateMemoryPool::LLMemoryChunk::init(char* buffer, U32 buffer_size, U32 mFreeSpaceList[i] = NULL ; } + //assign the entire chunk to the first block mBlocks[0].mPrev = NULL ; mBlocks[0].mNext = NULL ; mBlocks[0].setBuffer(mDataBuffer, buffer_size - (mDataBuffer - mBuffer)) ; - - //debug - U32 end = (mBlocks[0].getBufferSize() / mMinBlockSize) ; - for(U32 i = 1 ; i < end ; i++) - { - mBlocks[i].mSelf = NULL ; - } - addToFreeSpace(&mBlocks[0]) ; mHashNext = NULL ; @@ -609,6 +592,7 @@ void LLPrivateMemoryPool::LLMemoryChunk::init(char* buffer, U32 buffer_size, U32 //static U32 LLPrivateMemoryPool::LLMemoryChunk::getMaxOverhead(U32 data_buffer_size, U32 min_page_size) { + //for large allocations, reserve some extra memory for meta data to avoid wasting much if(data_buffer_size / min_page_size < 64) //large allocations { return 4096 ; //4KB @@ -621,6 +605,15 @@ U32 LLPrivateMemoryPool::LLMemoryChunk::getMaxOverhead(U32 data_buffer_size, U32 char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) { + if(mMinSlotSize > size) + { + size = mMinSlotSize ; + } + if(mAlloatedSize + size > mBufferSize - (mDataBuffer - mBuffer)) + { + return NULL ; //no enough space in this chunk. + } + char* p = NULL ; U32 blk_idx = getBlockLevel(size); @@ -653,7 +646,7 @@ char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) } } - //ask for space from higher level blocks + //ask for space from larger blocks if(!p) { for(S32 i = blk_idx + 1 ; i < mBlockLevels; i++) @@ -672,18 +665,8 @@ char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) } } - llassert_always(!p || blk) ; - if(p && blk) - { - if(blk->getTotalSlots() == 1) - { - llassert_always(blk->getBuffer() == (char*)p) ; - } - U32 blk_idx = getPageIndex((U32)p) ; - LLMemoryBlock* b = (LLMemoryBlock*)(mMetaBuffer + blk_idx * sizeof(LLMemoryBlock)) ; - llassert_always(blk == b || b->mSelf == blk) ; - + { mAlloatedSize += blk->getSlotSize() ; } return p ; @@ -693,31 +676,19 @@ void LLPrivateMemoryPool::LLMemoryChunk::free(void* addr) { U32 blk_idx = getPageIndex((U32)addr) ; LLMemoryBlock* blk = (LLMemoryBlock*)(mMetaBuffer + blk_idx * sizeof(LLMemoryBlock)) ; - llassert_always(blk->mSelf) ; blk = blk->mSelf ; - llassert_always(addr >= blk->getBuffer() && addr < blk->getBuffer() + blk->getBufferSize()) ; - if(blk->getTotalSlots() == 1) - { - llassert_always(blk->getBuffer() == (char*)addr) ; - } - bool was_full = blk->isFull() ; blk->free(addr) ; mAlloatedSize -= blk->getSlotSize() ; if(blk->empty()) { - blk->resetBitMap() ; //debug use removeBlock(blk) ; - - dump(); } else if(was_full) { addToAvailBlockList(blk) ; - - dump(); } } @@ -731,14 +702,11 @@ bool LLPrivateMemoryPool::LLMemoryChunk::containsAddress(const char* addr) const return (U32)mBuffer <= (U32)addr && (U32)mBuffer + mBufferSize > (U32)addr ; } +//debug use void LLPrivateMemoryPool::LLMemoryChunk::dump() { +#if 0 //sanity check - std::vector< LLMemoryBlock* > blk_list ; - for(std::set::iterator iter = mActiveBlockList.begin() ; iter != mActiveBlockList.end(); ++iter) - { - blk_list.push_back(*iter) ; - } //for(S32 i = 0 ; i < mBlockLevels ; i++) //{ // LLMemoryBlock* blk = mAvailBlockList[i] ; @@ -790,6 +758,7 @@ void LLPrivateMemoryPool::LLMemoryChunk::dump() llerrs << "gap happens" << llendl ; } } +#endif #if 0 llinfos << "---------------------------" << llendl ; llinfos << "Chunk buffer: " << (U32)getBuffer() << " size: " << getBufferSize() << llendl ; @@ -818,6 +787,7 @@ void LLPrivateMemoryPool::LLMemoryChunk::dump() #endif } +//compute the size for a block, the size is round to integer times of mMinBlockSize. U32 LLPrivateMemoryPool::LLMemoryChunk::calcBlockSize(U32 slot_size) { // @@ -857,15 +827,12 @@ U32 LLPrivateMemoryPool::LLMemoryChunk::calcBlockSize(U32 slot_size) return block_size ; } +//create a new block in the chunk LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::addBlock(U32 blk_idx) { U32 slot_size = mMinSlotSize * (blk_idx + 1) ; - U32 preferred_block_size = calcBlockSize(slot_size) ; - + U32 preferred_block_size = calcBlockSize(slot_size) ; U16 idx = getPageLevel(preferred_block_size); - llassert_always(idx < mPartitionLevels - 1) ; - llassert_always(preferred_block_size == (idx + 1) * mMinBlockSize) ; //round to integer times of mMinBlockSize. - LLMemoryBlock* blk = NULL ; if(mFreeSpaceList[idx])//if there is free slot for blk_idx @@ -878,7 +845,12 @@ LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::addBlock } else //search for other non-preferred but enough space slot. { - for(S32 i = (S32)idx - 1 ; i >= 0 ; i--) //search the small slots first + S32 min_idx = 0 ; + if(slot_size > mMinBlockSize) + { + min_idx = getPageLevel(slot_size) ; + } + for(S32 i = (S32)idx - 1 ; i >= min_idx ; i--) //search the small slots first { if(mFreeSpaceList[i]) { @@ -909,31 +881,12 @@ LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::addBlock } } - dump() ; - return blk ; } -char* _prev = NULL ; +//create a new block at the designed location LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::createNewBlock(LLMemoryBlock* blk, U32 buffer_size, U32 slot_size, U32 blk_idx) { - llassert_always(blk->getBufferSize() >= buffer_size) ; - - //debug - { - { - U32 blk_idx = getPageIndex((U32)blk->getBuffer()) ; - llassert_always(blk == (LLMemoryBlock*)(mMetaBuffer + blk_idx * sizeof(LLMemoryBlock))) ; - } - U32 end = (blk->getBufferSize() / mMinBlockSize) ; - llassert_always(blk->mSelf == blk && blk->isFree()) ; - llassert_always((blk + end - 1)->mSelf == blk) ; - for(U32 i = 1 ; i < end - 1; i++) - { - llassert_always(!(blk + i)->mSelf) ; - } - } - //unlink from the free space removeFromFreeSpace(blk) ; @@ -949,41 +902,24 @@ LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::createNe { LLMemoryBlock* next_blk = blk + (buffer_size / mMinBlockSize) ; next_blk->setBuffer(blk->getBuffer() + buffer_size, new_free_blk_size) ; - - { - U32 blk_idx = getPageIndex((U32)next_blk->getBuffer()) ; - llassert_always(next_blk == (LLMemoryBlock*)(mMetaBuffer + blk_idx * sizeof(LLMemoryBlock))) ; - } - llassert_always(buffer_size == (buffer_size / mMinBlockSize) * mMinBlockSize) ; - llassert_always(((U32)next_blk->getBuffer() - (U32)mDataBuffer) == ((U32)next_blk->getBuffer() - (U32)mDataBuffer) / mMinBlockSize * mMinBlockSize) ; addToFreeSpace(next_blk) ; } blk->init(blk->getBuffer(), buffer_size, slot_size) ; //insert to the available block list... - llassert_always(!mAvailBlockList[blk_idx]) ; mAvailBlockList[blk_idx] = blk ; - llassert_always(blk->getTotalSlots() > 0) ; - llassert_always(mAvailBlockList[blk_idx]->getSlotSize() == (blk_idx + 1) * mMinSlotSize) ; - llassert_always(buffer_size == (buffer_size / mMinBlockSize) * mMinBlockSize) ; - - //mark the address map + //mark the address map: all blocks covered by this block space pointing back to this block. U32 end = (buffer_size / mMinBlockSize) ; for(U32 i = 1 ; i < end ; i++) { (blk + i)->mSelf = blk ; } - llassert_always(blk->getBuffer() != _prev) ; - - llassert_always(mActiveBlockList.find(blk) == mActiveBlockList.end()) ; - - mActiveBlockList.insert(blk) ; - return blk ; } +//delete a block, release the block to the free pool. void LLPrivateMemoryPool::LLMemoryChunk::removeBlock(LLMemoryBlock* blk) { //remove from the available block list @@ -1003,22 +939,11 @@ void LLPrivateMemoryPool::LLMemoryChunk::removeBlock(LLMemoryBlock* blk) blk->mNext = NULL ; blk->mPrev = NULL ; - - std::set::iterator iter = mActiveBlockList.find(blk) ; - llassert_always(iter != mActiveBlockList.end()) ; - mActiveBlockList.erase(iter) ; //mark it free blk->setBuffer(blk->getBuffer(), blk->getBufferSize()) ; - //debug - U32 end = (blk->getBufferSize() / mMinBlockSize) ; - for(U32 i = 1 ; i < end ; i++) - { - llassert_always((blk + i)->mSelf == blk) ; - (blk + i)->mSelf = NULL ; - } -#if 0 +#if 1 //merge blk with neighbors if possible if(blk->getBuffer() > mDataBuffer) //has the left neighbor { @@ -1041,9 +966,7 @@ void LLPrivateMemoryPool::LLMemoryChunk::removeBlock(LLMemoryBlock* blk) } } #endif - llassert_always(blk->getBuffer() != _prev) ; - llassert_always(mActiveBlockList.find(blk) == mActiveBlockList.end()) ; - + addToFreeSpace(blk) ; return ; @@ -1062,16 +985,10 @@ void LLPrivateMemoryPool::LLMemoryChunk::popAvailBlockList(U32 blk_idx) mAvailBlockList[blk_idx]->mPrev = NULL ; mAvailBlockList[blk_idx]->mNext = NULL ; mAvailBlockList[blk_idx] = next ; - if(next) - { - llassert_always(mAvailBlockList[blk_idx]->getTotalSlots() > 0) ; - llassert_always(mAvailBlockList[blk_idx]->getSlotSize() == (blk_idx + 1) * mMinSlotSize) ; - } - - dump() ; } } +//add the block back to the free pool void LLPrivateMemoryPool::LLMemoryChunk::addToFreeSpace(LLMemoryBlock* blk) { llassert_always(!blk->mPrev) ; @@ -1094,6 +1011,7 @@ void LLPrivateMemoryPool::LLMemoryChunk::addToFreeSpace(LLMemoryBlock* blk) return ; } +//remove the space from the free pool void LLPrivateMemoryPool::LLMemoryChunk::removeFromFreeSpace(LLMemoryBlock* blk) { U16 free_idx = blk->getBufferSize() / mMinBlockSize - 1; @@ -1125,8 +1043,6 @@ void LLPrivateMemoryPool::LLMemoryChunk::addToAvailBlockList(LLMemoryBlock* blk) U32 blk_idx = getBlockLevel(blk->getSlotSize()); - llassert_always(blk->getSlotSize() == (blk_idx + 1) * mMinSlotSize) ; - blk->mNext = mAvailBlockList[blk_idx] ; if(blk->mNext) { @@ -1135,9 +1051,6 @@ void LLPrivateMemoryPool::LLMemoryChunk::addToAvailBlockList(LLMemoryBlock* blk) blk->mPrev = NULL ; mAvailBlockList[blk_idx] = blk ; - llassert_always(mAvailBlockList[blk_idx]->getTotalSlots() > 0) ; - llassert_always(mAvailBlockList[blk_idx]->getSlotSize() == (blk_idx + 1) * mMinSlotSize) ; - return ; } @@ -1158,9 +1071,6 @@ U32 LLPrivateMemoryPool::LLMemoryChunk::getBlockLevel(U32 size) //for mFreeSpaceList U16 LLPrivateMemoryPool::LLMemoryChunk::getPageLevel(U32 size) { - llassert_always(size >= mMinBlockSize); - llassert_always(!(size % mMinBlockSize)) ; - //start from 0 U16 level = size / mMinBlockSize - 1 ; if(level >= mPartitionLevels) @@ -1174,11 +1084,12 @@ U16 LLPrivateMemoryPool::LLMemoryChunk::getPageLevel(U32 size) //class LLPrivateMemoryPool //-------------------------------------------------------------------- const U32 CHUNK_SIZE = 4 << 20 ; //4 MB -const U32 HASH_FACTOR = 255 ; +const U32 LARGE_CHUNK_SIZE = 4 * CHUNK_SIZE ; //16 MB LLPrivateMemoryPool::LLPrivateMemoryPool(U32 max_size, bool threaded) : mMutexp(NULL), mMaxPoolSize(max_size), - mReservedPoolSize(0) + mReservedPoolSize(0), + mHashFactor(1) { if(threaded) { @@ -1188,13 +1099,7 @@ LLPrivateMemoryPool::LLPrivateMemoryPool(U32 max_size, bool threaded) : for(S32 i = 0 ; i < SUPER_ALLOCATION ; i++) { mChunkList[i] = NULL ; - } - - mChunkHashList.resize(HASH_FACTOR + 1) ; - for(U32 i = 0 ; i <= HASH_FACTOR ; i++) - { - mChunkHashList[i] = NULL ; - } + } mNumOfChunks = 0 ; } @@ -1272,70 +1177,25 @@ void LLPrivateMemoryPool::free(void* addr) lock() ; - U16 key ; - LLMemoryChunk* chunk =findChunk((char*)addr, key) ; + LLMemoryChunk* chunk = findChunk((char*)addr) ; if(!chunk) { - delete[] (char*)addr ; //release from heap + delete[] addr ; //release from heap } else { - llassert_always((U32)addr >= (U32)chunk->getBuffer() && (U32)addr < (U32)chunk->getBuffer() + chunk->getBufferSize()) ; - chunk->free(addr) ; if(chunk->empty()) { - removeChunk(chunk, key) ; + removeChunk(chunk) ; } } unlock() ; } -LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::findChunk(const char* addr, U16& key) -{ - key = findHashKey(addr) ; - - //check the hash value "key" - LLMemoryChunk* chunk = mChunkHashList[key] ; - while(chunk && !chunk->containsAddress(addr)) - { - chunk = chunk->mHashNext ; - } - - if(!chunk && key > 0) //check the "key - 1" - { - chunk = mChunkHashList[key - 1] ; - while(chunk && !chunk->containsAddress(addr)) - { - chunk = chunk->mHashNext ; - } - - if(chunk) - { - key-- ; - } - } - - if(!chunk && key < HASH_FACTOR) //check the "key + 1" - { - chunk = mChunkHashList[key + 1] ; - while(chunk && !chunk->containsAddress(addr)) - { - chunk = chunk->mHashNext ; - } - - if(chunk) - { - key++ ; - } - } - - return chunk ; -} - void LLPrivateMemoryPool::dump() { } @@ -1388,11 +1248,11 @@ S32 LLPrivateMemoryPool::getChunkIndex(U32 size) void LLPrivateMemoryPool::destroyPool() { lock() ; - for(U32 i = 0 ; i <= HASH_FACTOR; i++) + for(U32 i = 0 ; i < mHashFactor; i++) { while(mChunkHashList[i]) { - removeChunk(mChunkHashList[i], i) ; + removeChunk(mChunkHashList[i]) ; } } llassert_always(mNumOfChunks == 0) ; @@ -1429,7 +1289,7 @@ LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::addChunk(S32 chunk_inde } else { - preferred_size = 4 * CHUNK_SIZE ; //16MB + preferred_size = LARGE_CHUNK_SIZE ; //16MB overhead = LLMemoryChunk::getMaxOverhead(preferred_size, MIN_BLOCK_SIZES[chunk_index]) ; } @@ -1457,19 +1317,14 @@ LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::addChunk(S32 chunk_inde mChunkList[chunk_index] = chunk ; //insert into the hash table - U16 key = findHashKey(chunk->getBuffer()) ; - chunk->mHashNext = mChunkHashList[key] ; - mChunkHashList[key] = chunk ; + addToHashTable(chunk) ; mNumOfChunks++; return chunk ; } -char*** _p = NULL ; -U32 _times; -U32 _levels; -void LLPrivateMemoryPool::removeChunk(LLMemoryChunk* chunk, U16 key) +void LLPrivateMemoryPool::removeChunk(LLMemoryChunk* chunk) { if(!chunk) { @@ -1495,46 +1350,210 @@ void LLPrivateMemoryPool::removeChunk(LLMemoryChunk* chunk, U16 key) } //remove from the hash table - if(mChunkHashList[key] == chunk) + removeFromHashTable(chunk) ; + + mNumOfChunks--; + mReservedPoolSize -= chunk->getBufferSize() ; + + //release memory + delete[] chunk->getBuffer() ; +} + +U16 LLPrivateMemoryPool::findHashKey(const char* addr) +{ + return (((U32)addr) / CHUNK_SIZE) % mHashFactor ; +} + +LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::findChunk(const char* addr) +{ + U16 key = findHashKey(addr) ; + if(mChunkHashList.size() <= key) { - mChunkHashList[key] = chunk->mHashNext ; + return NULL ; } - else + + //check the hash value "key" + LLMemoryChunk* chunk = mChunkHashList[key] ; + while(chunk && !chunk->containsAddress(addr)) + { + chunk = chunk->mHashNext ; + } + + return chunk ; +} + +void LLPrivateMemoryPool::addToHashTable(LLMemoryChunk* chunk) +{ + static const U16 HASH_FACTORS[] = {41, 83, 193, 317, 419, 523, 0xFFFF}; + + U16 i ; + if(mChunkHashList.empty()) + { + mHashFactor = HASH_FACTORS[0] ; + rehash() ; + } + + U16 start_key = findHashKey(chunk->getBuffer()) ; + U16 end_key = findHashKey(chunk->getBuffer() + chunk->getBufferSize() - 1) ; + bool need_rehash = false ; + + if(mChunkHashList[start_key]) { - LLMemoryChunk* prev = mChunkHashList[key] ; - while(prev->mHashNext && prev->mHashNext != chunk) + if(mChunkHashList[start_key] == chunk) { - prev = prev->mHashNext ; + return; //already inserted. } - llassert_always(prev->mHashNext == chunk) ; + + need_rehash = mChunkHashList[start_key]->mHashNext != NULL ; + if(!need_rehash) + { + llassert_always(!chunk->mHashNext) ; - prev->mHashNext = chunk->mHashNext ; + chunk->mHashNext = mChunkHashList[start_key] ; + mChunkHashList[start_key] = chunk ; + } } - mNumOfChunks--; - mReservedPoolSize -= chunk->getBufferSize() ; - - //debug check - if(_p) + else + { + mChunkHashList[start_key] = chunk ; + } + + if(!need_rehash) + { + if(mChunkHashList[end_key]) + { + llassert_always(mChunkHashList[end_key] != chunk) + + need_rehash = mChunkHashList[end_key]->mHashNext != NULL ; + if(!need_rehash) + { + mChunkHashList[end_key]->mHashNext = chunk ; + } + } + else + { + mChunkHashList[end_key] = chunk ; + } + } + + if(!need_rehash) { - for(U32 i = 0 ; i < _times; i++) + if(end_key < start_key) { - for(U32 j = 0 ; j < _levels ;j++) + for(U16 i = start_key + 1 ; i < mHashFactor; i++) { - if( i == col && j == row) + if(mChunkHashList[i]) { - continue ; + llassert_always(mChunkHashList[i] != chunk) ; + need_rehash = true ; + break ; + } + else + { + mChunkHashList[i] = chunk ; + } + } + + if(!need_rehash) + { + for(U16 i = 0 ; i < end_key; i++) + { + if(mChunkHashList[i]) + { + llassert_always(mChunkHashList[i] != chunk) ; + need_rehash = true ; + break ; + } + else + { + mChunkHashList[i] = chunk ; + } + } + } + } + else + { + for(i = start_key + 1; i < end_key; i++) + { + if(mChunkHashList[i]) + { + llassert_always(mChunkHashList[i] != chunk) ; + need_rehash = true ; + break ; + } + else + { + mChunkHashList[i] = chunk ; } - llassert_always(!_p[i][j] || !chunk->containsAddress(_p[i][j])) ; } } } - //release memory - delete[] chunk->getBuffer() ; + + if(need_rehash) + { + i = 0 ; + while(HASH_FACTORS[i] <= mHashFactor) i++; + + mHashFactor = HASH_FACTORS[i] ; + llassert_always(mHashFactor != 0xFFFF) ;//stop point of the recursive calls + + rehash() ; + } } -U16 LLPrivateMemoryPool::findHashKey(const char* addr) +void LLPrivateMemoryPool::removeFromHashTable(LLMemoryChunk* chunk) +{ + U16 start_key = findHashKey(chunk->getBuffer()) ; + U16 end_key = findHashKey(chunk->getBuffer() + chunk->getBufferSize() - 1) ; + + mChunkHashList[start_key] = chunk->mHashNext ; + chunk->mHashNext = NULL ; + + if(mChunkHashList[end_key] != chunk) + { + mChunkHashList[end_key]->mHashNext = NULL ; + } + else + { + mChunkHashList[end_key] = NULL ; + } + + if(end_key < start_key) + { + for(U16 i = start_key + 1 ; i < mHashFactor; i++) + { + mChunkHashList[i] = NULL ; + } + for(U16 i = 0 ; i < end_key; i++) + { + mChunkHashList[i] = NULL ; + } + } + else + { + for(U16 i = start_key + 1 ; i < end_key; i++) + { + mChunkHashList[i] = NULL ; + } + } +} + +void LLPrivateMemoryPool::rehash() { - return (((U32)addr) / CHUNK_SIZE) % HASH_FACTOR ; + mChunkHashList.clear() ; + mChunkHashList.resize(mHashFactor, NULL) ; + + LLMemoryChunk* chunk ; + for(U16 i = 0 ; i < SUPER_ALLOCATION ; i++) + { + chunk = mChunkList[i] ; + while(chunk) + { + chunk->mHashNext = NULL ; + addToHashTable(chunk) ; + chunk = chunk->mNext ; + } + } } //-------------------------------------------------------------------- @@ -1587,7 +1606,7 @@ void LLPrivateMemoryPoolTester::run(bool threaded) //run the test correctnessTest() ; - //performanceTest() ; + performanceTest() ; //fragmentationtest() ; //release pool. @@ -1619,10 +1638,6 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 } } - _p = p ; - _times = times; - _levels = levels ; - //allocation U32 size ; for(i = 0 ; i < times ; i++) @@ -1630,7 +1645,7 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 for(j = 0 ; j < levels; j++) { size = min_size + j * stride ; - _prev = p[i][j] = sPool->allocate(size) ; + p[i][j] = sPool->allocate(size) ; total_allocated_size+= size ; @@ -1643,15 +1658,8 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 { S32 k = rand() % levels ; - col = i ; - row = k ; - if(p[i][k]) { - if(_prev == p[i][k]) - { - _prev = NULL ; - } llassert_always(*(U32*)p[i][k] == i && *((U32*)p[i][k] + 1) == k) ; sPool->free(p[i][k]) ; total_allocated_size -= min_size + k * stride ; @@ -1666,15 +1674,11 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 { } - _prev = NULL ; //release all memory allocations for(i = 0 ; i < times; i++) { for(j = 0 ; j < levels; j++) { - col = i ; - row = j ; - if(p[i][j]) { llassert_always(*(U32*)p[i][j] == i && *((U32*)p[i][j] + 1) == j) ; @@ -1687,7 +1691,57 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 ::delete[] *p ; ::delete[] p ; - _p = NULL ; +} + +void LLPrivateMemoryPoolTester::testAndTime(U32 size, U32 times) +{ + LLTimer timer ; + + llinfos << " -**********************- " << llendl ; + llinfos << "test size: " << size << " test times: " << times << llendl ; + + timer.reset() ; + char** p = new char*[times] ; + + //using the customized memory pool + //allocation + for(U32 i = 0 ; i < times; i++) + { + p[i] = sPool->allocate(size) ; + if(!p[i]) + { + llerrs << "allocation failed" << llendl ; + } + } + //de-allocation + for(U32 i = 0 ; i < times; i++) + { + sPool->free(p[i]) ; + p[i] = NULL ; + } + llinfos << "time spent using customized memory pool: " << timer.getElapsedTimeF32() << llendl ; + + timer.reset() ; + + //using the standard allocator/de-allocator: + //allocation + for(U32 i = 0 ; i < times; i++) + { + p[i] = ::new char[size] ; + if(!p[i]) + { + llerrs << "allocation failed" << llendl ; + } + } + //de-allocation + for(U32 i = 0 ; i < times; i++) + { + ::delete[] p[i] ; + p[i] = NULL ; + } + llinfos << "time spent using standard allocator/de-allocator: " << timer.getElapsedTimeF32() << llendl ; + + delete[] p; } void LLPrivateMemoryPoolTester::correctnessTest() @@ -1715,56 +1769,15 @@ void LLPrivateMemoryPoolTester::correctnessTest() void LLPrivateMemoryPoolTester::performanceTest() { U32 test_size[3] = {768, 3* 1024, 3* 1024 * 1024}; - - S32 i ; - LLFrameTimer timer ; - - //do 1024 various-sized allocations / deallocations, compare the performance with the normal ones. - + //small sized - { - timer.reset() ; - char* p[1024] = {NULL} ; - for(i = 0 ; i < 1024; i++) - { - p[i] = sPool->allocate(test_size[0]) ; - if(!p[i]) - { - llerrs << "allocation failed" << llendl ; - } - } - - for(i = 0 ; i < 1024; i++) - { - sPool->free(p[i]) ; - p[i] = NULL ; - } - llinfos << "time spent on 1024 small allocations: %f " << timer.getElapsedTimeF32() << llendl ; - - timer.reset() ; - - //using the standard allocator/de-allocator: - for(i = 0 ; i < 1024; i++) - { - p[i] = ::new char[test_size[0]] ; - if(!p[i]) - { - llerrs << "allocation failed" << llendl ; - } - } - - for(i = 0 ; i < 1024; i++) - { - ::delete[] p[i] ; - p[i] = NULL ; - } - llinfos << "time spent on 1024 small allocations: %f using standard allocator/de-allocator." << timer.getElapsedTimeF32() << llendl ; - - timer.reset() ; - } + testAndTime(test_size[0], 8) ; + //medium sized + testAndTime(test_size[1], 8) ; //large sized + testAndTime(test_size[2], 8) ; } void LLPrivateMemoryPoolTester::fragmentationtest() diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index f0e26d6b2f..f7ca33a279 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -173,9 +173,6 @@ public: U16 mBlockLevels; U16 mPartitionLevels; - //debug use - std::set mActiveBlockList ; - public: //form a linked list LLMemoryChunk* mNext ; @@ -200,9 +197,13 @@ private: S32 getChunkIndex(U32 size) ; LLMemoryChunk* addChunk(S32 chunk_index) ; void checkSize(U32 asked_size) ; - void removeChunk(LLMemoryChunk* chunk, U16 key) ; + void removeChunk(LLMemoryChunk* chunk) ; U16 findHashKey(const char* addr); - LLMemoryChunk* findChunk(const char* addr, U16& key) ; + void addToHashTable(LLMemoryChunk* chunk) ; + void removeFromHashTable(LLMemoryChunk* chunk) ; + void rehash() ; + LLMemoryChunk* findChunk(const char* addr) ; + void destroyPool() ; public: @@ -222,6 +223,7 @@ private: LLMemoryChunk* mChunkList[SUPER_ALLOCATION] ; //all memory chunks reserved by this pool, sorted by address std::vector mChunkHashList ; U16 mNumOfChunks ; + U16 mHashFactor ; }; // @@ -245,6 +247,7 @@ private: void fragmentationtest() ; void test(U32 min_size, U32 max_size, U32 stride, U32 times, bool random_deletion, bool output_statistics) ; + void testAndTime(U32 size, U32 times) ; public: void* operator new(size_t size) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index fd7e1eda7f..d1727a0e83 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1087,9 +1087,9 @@ bool LLAppViewer::mainLoop() // point of posting. LLSD newFrame; - LLPrivateMemoryPoolTester::getInstance()->run(false) ; - LLPrivateMemoryPoolTester::getInstance()->run(true) ; - LLPrivateMemoryPoolTester::destroy() ; + //LLPrivateMemoryPoolTester::getInstance()->run(false) ; + //LLPrivateMemoryPoolTester::getInstance()->run(true) ; + //LLPrivateMemoryPoolTester::destroy() ; // Handle messages while (!LLApp::isExiting()) -- cgit v1.2.3 From a3759a7815f7ba55b825bc76f30a1e333e01f295 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Thu, 6 Jan 2011 16:17:38 -0700 Subject: add the class LLPrivateMemoryPoolManager --- indra/llcommon/llmemory.cpp | 157 +++++++++++++++++++++++++++++--------------- indra/llcommon/llmemory.h | 32 ++++++++- 2 files changed, 136 insertions(+), 53 deletions(-) (limited to 'indra') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index f9a2770691..f1285841b3 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -1404,14 +1404,10 @@ void LLPrivateMemoryPool::addToHashTable(LLMemoryChunk* chunk) return; //already inserted. } - need_rehash = mChunkHashList[start_key]->mHashNext != NULL ; - if(!need_rehash) - { - llassert_always(!chunk->mHashNext) ; + llassert_always(!chunk->mHashNext) ; - chunk->mHashNext = mChunkHashList[start_key] ; - mChunkHashList[start_key] = chunk ; - } + chunk->mHashNext = mChunkHashList[start_key] ; + mChunkHashList[start_key] = chunk ; } else { @@ -1440,52 +1436,15 @@ void LLPrivateMemoryPool::addToHashTable(LLMemoryChunk* chunk) { if(end_key < start_key) { - for(U16 i = start_key + 1 ; i < mHashFactor; i++) - { - if(mChunkHashList[i]) - { - llassert_always(mChunkHashList[i] != chunk) ; - need_rehash = true ; - break ; - } - else - { - mChunkHashList[i] = chunk ; - } - } - + need_rehash = fillHashTable(start_key + 1, mHashFactor, chunk) ; if(!need_rehash) { - for(U16 i = 0 ; i < end_key; i++) - { - if(mChunkHashList[i]) - { - llassert_always(mChunkHashList[i] != chunk) ; - need_rehash = true ; - break ; - } - else - { - mChunkHashList[i] = chunk ; - } - } + need_rehash = fillHashTable(0, end_key, chunk) ; } } else { - for(i = start_key + 1; i < end_key; i++) - { - if(mChunkHashList[i]) - { - llassert_always(mChunkHashList[i] != chunk) ; - need_rehash = true ; - break ; - } - else - { - mChunkHashList[i] = chunk ; - } - } + need_rehash = fillHashTable(start_key + 1, end_key, chunk) ; } } @@ -1495,7 +1454,7 @@ void LLPrivateMemoryPool::addToHashTable(LLMemoryChunk* chunk) while(HASH_FACTORS[i] <= mHashFactor) i++; mHashFactor = HASH_FACTORS[i] ; - llassert_always(mHashFactor != 0xFFFF) ;//stop point of the recursive calls + llassert_always(mHashFactor != 0xFFFF) ;//stop point to prevent endlessly recursive calls rehash() ; } @@ -1540,6 +1499,8 @@ void LLPrivateMemoryPool::removeFromHashTable(LLMemoryChunk* chunk) void LLPrivateMemoryPool::rehash() { + llinfos << "new hash factor: " << mHashFactor << llendl ; + mChunkHashList.clear() ; mChunkHashList.resize(mHashFactor, NULL) ; @@ -1556,8 +1517,100 @@ void LLPrivateMemoryPool::rehash() } } +bool LLPrivateMemoryPool::fillHashTable(U16 start, U16 end, LLMemoryChunk* chunk) +{ + for(U16 i = start; i < end; i++) + { + if(mChunkHashList[i]) //the slot is occupied. + { + llassert_always(mChunkHashList[i] != chunk) ; + return true ; + } + else + { + mChunkHashList[i] = chunk ; + } + } + + return false ; +} + +//-------------------------------------------------------------------- +//class LLPrivateMemoryPoolManager +//-------------------------------------------------------------------- +LLPrivateMemoryPoolManager* LLPrivateMemoryPoolManager::sInstance = NULL ; + +LLPrivateMemoryPoolManager::LLPrivateMemoryPoolManager() +{ +} + +LLPrivateMemoryPoolManager::~LLPrivateMemoryPoolManager() +{ + //all private pools should be released by their owners before reaching here. + llassert_always(mPoolList.empty()) ; + +#if 0 + if(!mPoolList.empty()) + { + for(std::set::iterator iter = mPoolList.begin(); iter != mPoolList.end(); ++iter) + { + delete *iter; + } + mPoolList.clear() ; + } +#endif +} + +//static +LLPrivateMemoryPoolManager* LLPrivateMemoryPoolManager::getInstance() +{ + if(!sInstance) + { + sInstance = new LLPrivateMemoryPoolManager() ; + } + return sInstance ; +} + +//static +void LLPrivateMemoryPoolManager::destroyClass() +{ + if(sInstance) + { + delete sInstance ; + sInstance = NULL ; + } +} + +LLPrivateMemoryPool* LLPrivateMemoryPoolManager::newPool(U32 max_size, bool threaded) +{ + LLPrivateMemoryPool* pool = new LLPrivateMemoryPool(max_size, threaded) ; + mPoolList.insert(pool) ; + + return pool ; +} + +void LLPrivateMemoryPoolManager::deletePool(LLPrivateMemoryPool* pool) +{ + mPoolList.erase(pool) ; + delete pool; +} + +//debug +void LLPrivateMemoryPoolManager::updateStatistics() +{ + mTotalReservedSize = 0 ; + mTotalAllocatedSize = 0 ; + + for(std::set::iterator iter = mPoolList.begin(); iter != mPoolList.end(); ++iter) + { + mTotalReservedSize += (*iter)->getTotalReservedSize() ; + mTotalAllocatedSize += (*iter)->getTotalAllocatedSize() ; + } +} + //-------------------------------------------------------------------- //class LLPrivateMemoryPoolTester +//-------------------------------------------------------------------- LLPrivateMemoryPoolTester* LLPrivateMemoryPoolTester::sInstance = NULL ; LLPrivateMemoryPool* LLPrivateMemoryPoolTester::sPool = NULL ; LLPrivateMemoryPoolTester::LLPrivateMemoryPoolTester() @@ -1589,7 +1642,7 @@ void LLPrivateMemoryPoolTester::destroy() if(sPool) { - ::delete sPool ; + LLPrivateMemoryPoolManager::getInstance()->deletePool(sPool) ; sPool = NULL ; } } @@ -1600,9 +1653,9 @@ void LLPrivateMemoryPoolTester::run(bool threaded) if(sPool) { - ::delete sPool ; + LLPrivateMemoryPoolManager::getInstance()->deletePool(sPool) ; } - sPool = ::new LLPrivateMemoryPool(max_pool_size, threaded) ; + sPool = LLPrivateMemoryPoolManager::getInstance()->newPool(max_pool_size, threaded) ; //run the test correctnessTest() ; @@ -1610,7 +1663,7 @@ void LLPrivateMemoryPoolTester::run(bool threaded) //fragmentationtest() ; //release pool. - ::delete sPool ; + LLPrivateMemoryPoolManager::getInstance()->deletePool(sPool) ; sPool = NULL ; } diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index f7ca33a279..e42dc174b5 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -73,6 +73,8 @@ private: // class LL_COMMON_API LLPrivateMemoryPool { + friend class LLPrivateMemoryPoolManager ; + public: class LL_COMMON_API LLMemoryBlock //each block is devided into slots uniformly { @@ -181,15 +183,17 @@ public: LLMemoryChunk* mHashNext ; } ; -public: +private: LLPrivateMemoryPool(U32 max_size, bool threaded) ; ~LLPrivateMemoryPool() ; +public: char *allocate(U32 size) ; void free(void* addr) ; void dump() ; U32 getTotalAllocatedSize() ; + U32 getTotalReservedSize() {return mReservedPoolSize;} private: void lock() ; @@ -202,6 +206,7 @@ private: void addToHashTable(LLMemoryChunk* chunk) ; void removeFromHashTable(LLMemoryChunk* chunk) ; void rehash() ; + bool fillHashTable(U16 start, U16 end, LLMemoryChunk* chunk) ; LLMemoryChunk* findChunk(const char* addr) ; void destroyPool() ; @@ -226,6 +231,31 @@ private: U16 mHashFactor ; }; +class LL_COMMON_API LLPrivateMemoryPoolManager +{ +private: + LLPrivateMemoryPoolManager() ; + ~LLPrivateMemoryPoolManager() ; + +public: + static LLPrivateMemoryPoolManager* getInstance() ; + static void destroyClass() ; + + LLPrivateMemoryPool* newPool(U32 max_size, bool threaded) ; + void deletePool(LLPrivateMemoryPool* pool) ; + +private: + static LLPrivateMemoryPoolManager* sInstance ; + std::set mPoolList ; + +public: + //debug and statistics info. + void updateStatistics() ; + + U32 mTotalReservedSize ; + U32 mTotalAllocatedSize ; +}; + // //the below singleton is used to test the private memory pool. // -- cgit v1.2.3 From 4de6759cd9d566ab92f0d9efa0c0338359dfa85c Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Thu, 6 Jan 2011 16:18:26 -0700 Subject: add debug info to the UI. --- indra/newview/app_settings/settings.xml | 11 +++++++++++ indra/newview/llviewerwindow.cpp | 11 +++++++++++ indra/newview/skins/default/xui/en/menu_viewer.xml | 10 ++++++++++ 3 files changed, 32 insertions(+) (limited to 'indra') diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 905c683f69..ca48f8b16a 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1829,6 +1829,17 @@ Value 0 + DebugShowPrivateMem + + Comment + Show Private Mem Info + Persist + 1 + Type + Boolean + Value + 0 + DebugShowRenderInfo Comment diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 943b5b5886..f1d0cf2128 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -548,6 +548,17 @@ public: addText(xpos, ypos, llformat("%d %d %d %d", color[0], color[1], color[2], color[3])); ypos += y_inc; } + + if (gSavedSettings.getBOOL("DebugShowPrivateMem")) + { + LLPrivateMemoryPoolManager::getInstance()->updateStatistics() ; + addText(xpos, ypos, llformat("Total Reserved(KB): %d", LLPrivateMemoryPoolManager::getInstance()->mTotalReservedSize / 1024)); + ypos += y_inc; + + addText(xpos, ypos, llformat("Total Allocated(KB): %d", LLPrivateMemoryPoolManager::getInstance()->mTotalAllocatedSize / 1024)); + ypos += y_inc; + } + // only display these messages if we are actually rendering beacons at this moment if (LLPipeline::getRenderBeacons(NULL) && LLFloaterReg::instanceVisible("beacons")) { diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 9a08be2405..1371411656 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -1937,6 +1937,16 @@ function="ToggleControl" parameter="DebugShowColor" /> + + + + -- cgit v1.2.3 From 611d8bdf6155f6c7b440ab745f197d278a74b209 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Thu, 6 Jan 2011 16:20:21 -0700 Subject: use the private pool in the texture pipeline --- indra/llimage/llimage.cpp | 70 ++++++++++++++++++++++++++++++++++++---- indra/llimage/llimage.h | 15 ++++++--- indra/llimage/llimagedxt.cpp | 2 +- indra/llimage/llimagej2c.cpp | 4 +-- indra/newview/llappviewer.cpp | 3 ++ indra/newview/lltexturecache.cpp | 30 ++++++++--------- indra/newview/lltexturefetch.cpp | 14 ++++---- 7 files changed, 103 insertions(+), 35 deletions(-) (limited to 'indra') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 5c33b675ca..c99313f0ea 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -39,6 +39,7 @@ #include "llimagepng.h" #include "llimagedxt.h" #include "llimageworker.h" +#include "llmemory.h" //--------------------------------------------------------------------------- // LLImage @@ -47,12 +48,15 @@ //static std::string LLImage::sLastErrorMessage; LLMutex* LLImage::sMutex = NULL; +LLPrivateMemoryPool* LLImageBase::sPrivatePoolp = NULL ; //static void LLImage::initClass() { sMutex = new LLMutex(NULL); LLImageJ2C::openDSO(); + + LLImageBase::createPrivatePool() ; } //static @@ -61,6 +65,8 @@ void LLImage::cleanupClass() LLImageJ2C::closeDSO(); delete sMutex; sMutex = NULL; + + LLImageBase::destroyPrivatePool() ; } //static @@ -99,6 +105,53 @@ LLImageBase::~LLImageBase() deleteData(); // virtual } +//static +void LLImageBase::createPrivatePool() +{ + const U32 MAX_POOL_SIZE = 512 * 1024 * 1024 ; //512 MB + + if(!sPrivatePoolp) + { + sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(MAX_POOL_SIZE, true) ; + } +} + +//static +void LLImageBase::destroyPrivatePool() +{ + if(sPrivatePoolp) + { + LLPrivateMemoryPoolManager::getInstance()->deletePool(sPrivatePoolp) ; + sPrivatePoolp = NULL ; + } +} + +//static +char* LLImageBase::allocateMemory(S32 size) +{ + if(sPrivatePoolp) + { + return sPrivatePoolp->allocate(size) ; + } + else + { + return new char[size]; + } +} + +//static +void LLImageBase::deleteMemory(void* p) +{ + if(sPrivatePoolp) + { + sPrivatePoolp->free(p) ; + } + else + { + delete[] p ; + } +} + // virtual void LLImageBase::dump() { @@ -132,7 +185,7 @@ void LLImageBase::sanityCheck() // virtual void LLImageBase::deleteData() { - delete[] mData; + deleteMemory(mData) ; mData = NULL; mDataSize = 0; } @@ -169,7 +222,7 @@ U8* LLImageBase::allocateData(S32 size) { deleteData(); // virtual mBadBufferAllocation = false ; - mData = new U8[size]; + mData = (U8*)allocateMemory(size); if (!mData) { llwarns << "allocate image data: " << size << llendl; @@ -187,7 +240,7 @@ U8* LLImageBase::allocateData(S32 size) U8* LLImageBase::reallocateData(S32 size) { LLMemType mt1(mMemType); - U8 *new_datap = new U8[size]; + U8 *new_datap = (U8*)allocateMemory(size); if (!new_datap) { llwarns << "Out of memory in LLImageBase::reallocateData" << llendl; @@ -197,7 +250,7 @@ U8* LLImageBase::reallocateData(S32 size) { S32 bytes = llmin(mDataSize, size); memcpy(new_datap, mData, bytes); /* Flawfinder: ignore */ - delete[] mData; + deleteMemory(mData) ; } mData = new_datap; mDataSize = size; @@ -343,6 +396,7 @@ BOOL LLImageRaw::resize(U16 width, U16 height, S8 components) return TRUE; } +#if 0 U8 * LLImageRaw::getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const { LLMemType mt1(mMemType); @@ -363,6 +417,7 @@ U8 * LLImageRaw::getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const } return data; } +#endif BOOL LLImageRaw::setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height, const U8 *data, U32 stride, BOOL reverse_y) @@ -832,6 +887,7 @@ void LLImageRaw::copyScaled( LLImageRaw* src ) } } +#if 0 //scale down image by not blending a pixel with its neighbors. BOOL LLImageRaw::scaleDownWithoutBlending( S32 new_width, S32 new_height) { @@ -855,7 +911,7 @@ BOOL LLImageRaw::scaleDownWithoutBlending( S32 new_width, S32 new_height) ratio_x -= 1.0f ; ratio_y -= 1.0f ; - U8* new_data = new U8[new_data_size] ; + U8* new_data = allocateMemory(new_data_size) ; llassert_always(new_data != NULL) ; U8* old_data = getData() ; @@ -877,6 +933,7 @@ BOOL LLImageRaw::scaleDownWithoutBlending( S32 new_width, S32 new_height) return TRUE ; } +#endif BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data ) { @@ -1529,6 +1586,7 @@ void LLImageFormatted::setData(U8 *data, S32 size) { deleteData(); setDataAndSize(data, size); // Access private LLImageBase members + sGlobalFormattedMemory += getDataSize(); } } @@ -1547,7 +1605,7 @@ void LLImageFormatted::appendData(U8 *data, S32 size) S32 newsize = cursize + size; reallocateData(newsize); memcpy(getData() + cursize, data, size); - delete[] data; + deleteMemory(data); } } } diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index bca7e915fa..b137ea9a61 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -29,7 +29,6 @@ #include "lluuid.h" #include "llstring.h" -//#include "llmemory.h" #include "llthread.h" #include "llmemtype.h" @@ -56,6 +55,7 @@ const S32 MAX_IMG_PACKET_SIZE = 1000; class LLImageFormatted; class LLImageRaw; class LLColor4U; +class LLPrivateMemoryPool; typedef enum e_image_codec { @@ -127,7 +127,7 @@ public: protected: // special accessor to allow direct setting of mData and mDataSize by LLImageFormatted - void setDataAndSize(U8 *data, S32 size) { mData = data; mDataSize = size; } + void setDataAndSize(U8 *data, S32 size) { mData = data; mDataSize = size; } public: static void generateMip(const U8 *indata, U8* mipdata, int width, int height, S32 nchannels); @@ -138,6 +138,11 @@ public: static EImageCodec getCodecFromExtension(const std::string& exten); + static void createPrivatePool() ; + static void destroyPrivatePool() ; + static char* allocateMemory(S32 size) ; + static void deleteMemory(void* p) ; + private: U8 *mData; S32 mDataSize; @@ -149,6 +154,8 @@ private: bool mBadBufferAllocation ; bool mAllowOverSize ; + + static LLPrivateMemoryPool* sPrivatePoolp ; public: LLMemType::DeclareMemType& mMemType; // debug }; @@ -172,7 +179,7 @@ public: BOOL resize(U16 width, U16 height, S8 components); - U8 * getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const; + //U8 * getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const; BOOL setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height, const U8 *data, U32 stride = 0, BOOL reverse_y = FALSE); @@ -184,7 +191,7 @@ public: void contractToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE); void biasedScaleToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE); BOOL scale( S32 new_width, S32 new_height, BOOL scale_image = TRUE ); - BOOL scaleDownWithoutBlending( S32 new_width, S32 new_height) ; + //BOOL scaleDownWithoutBlending( S32 new_width, S32 new_height) ; // Fill the buffer with a constant color void fill( const LLColor4U& color ); diff --git a/indra/llimage/llimagedxt.cpp b/indra/llimage/llimagedxt.cpp index 4bd3efddaa..81be09a412 100644 --- a/indra/llimage/llimagedxt.cpp +++ b/indra/llimage/llimagedxt.cpp @@ -429,7 +429,7 @@ bool LLImageDXT::convertToDXR() S32 nmips = calcNumMips(width,height); S32 total_bytes = getDataSize(); U8* olddata = getData(); - U8* newdata = new U8[total_bytes]; + U8* newdata = (U8*)allocateMemory(total_bytes); if (!newdata) { llerrs << "Out of memory in LLImageDXT::convertToDXR()" << llendl; diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index c8c866b7f2..0a13372b07 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -471,14 +471,14 @@ BOOL LLImageJ2C::loadAndValidate(const std::string &filename) } else { - U8 *data = new U8[file_size]; + U8 *data = (U8*)allocateMemory(file_size); apr_size_t bytes_read = file_size; apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read infile.close() ; if (s != APR_SUCCESS || (S32)bytes_read != file_size) { - delete[] data; + deleteMemory(data); setLastError("Unable to read entire file"); res = FALSE; } diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index d1727a0e83..664ec7b0fb 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1797,6 +1797,9 @@ bool LLAppViewer::cleanup() llinfos << "File launched." << llendflush; } + //release all private memory pools. + LLPrivateMemoryPoolManager::destroyClass() ; + ll_close_fail_log(); llinfos << "Goodbye!" << llendflush; diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 6a213309a0..d64345deee 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -113,7 +113,7 @@ public: ~LLTextureCacheWorker() { llassert_always(!haveWork()); - delete[] mReadData; + LLImageBase::deleteMemory(mReadData); } // override this interface @@ -215,7 +215,7 @@ bool LLTextureCacheLocalFileWorker::doRead() mDataSize = 0; return true; } - mReadData = new U8[mDataSize]; + mReadData = (U8*)LLImageBase::allocateMemory(mDataSize); mBytesRead = -1; mBytesToRead = mDataSize; setPriority(LLWorkerThread::PRIORITY_LOW | mPriority); @@ -233,7 +233,7 @@ bool LLTextureCacheLocalFileWorker::doRead() // << " Bytes: " << mDataSize << " Offset: " << mOffset // << " / " << mDataSize << llendl; mDataSize = 0; // failed - delete[] mReadData; + LLImageBase::deleteMemory(mReadData); mReadData = NULL; } return true; @@ -248,7 +248,7 @@ bool LLTextureCacheLocalFileWorker::doRead() { mDataSize = local_size; } - mReadData = new U8[mDataSize]; + mReadData = (U8*)LLImageBase::allocateMemory(mDataSize); S32 bytes_read = LLAPRFile::readEx(mFileName, mReadData, mOffset, mDataSize, mCache->getLocalAPRFilePool()); @@ -258,7 +258,7 @@ bool LLTextureCacheLocalFileWorker::doRead() // << " Bytes: " << mDataSize << " Offset: " << mOffset // << " / " << mDataSize << llendl; mDataSize = 0; - delete[] mReadData; + LLImageBase::deleteMemory(mReadData); mReadData = NULL; } else @@ -371,7 +371,7 @@ bool LLTextureCacheRemoteWorker::doRead() mDataSize = local_size; } // Allocate read buffer - mReadData = new U8[mDataSize]; + mReadData = (U8*)LLImageBase::allocateMemory(mDataSize); S32 bytes_read = LLAPRFile::readEx(local_filename, mReadData, mOffset, mDataSize, mCache->getLocalAPRFilePool()); if (bytes_read != mDataSize) @@ -380,7 +380,7 @@ bool LLTextureCacheRemoteWorker::doRead() << " Bytes: " << mDataSize << " Offset: " << mOffset << " / " << mDataSize << llendl; mDataSize = 0; - delete[] mReadData; + LLImageBase::deleteMemory(mReadData); mReadData = NULL; } else @@ -423,7 +423,7 @@ bool LLTextureCacheRemoteWorker::doRead() S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset; size = llmin(size, mDataSize); // Allocate the read buffer - mReadData = new U8[size]; + mReadData = (U8*)LLImageBase::allocateMemory(size); S32 bytes_read = LLAPRFile::readEx(mCache->mHeaderDataFileName, mReadData, offset, size, mCache->getLocalAPRFilePool()); if (bytes_read != size) @@ -431,7 +431,7 @@ bool LLTextureCacheRemoteWorker::doRead() llwarns << "LLTextureCacheWorker: " << mID << " incorrect number of bytes read from header: " << bytes_read << " / " << size << llendl; - delete[] mReadData; + LLImageBase::deleteMemory(mReadData); mReadData = NULL; mDataSize = -1; // failed done = true; @@ -461,7 +461,7 @@ bool LLTextureCacheRemoteWorker::doRead() S32 data_offset, file_size, file_offset; // Reserve the whole data buffer first - U8* data = new U8[mDataSize]; + U8* data = (U8*)LLImageBase::allocateMemory(mDataSize); // Set the data file pointers taking the read offset into account. 2 cases: if (mOffset < TEXTURE_CACHE_ENTRY_SIZE) @@ -474,7 +474,7 @@ bool LLTextureCacheRemoteWorker::doRead() // Copy the raw data we've been holding from the header cache into the new sized buffer llassert_always(mReadData); memcpy(data, mReadData, data_offset); - delete[] mReadData; + LLImageBase::deleteMemory(mReadData); mReadData = NULL; } else @@ -500,7 +500,7 @@ bool LLTextureCacheRemoteWorker::doRead() llwarns << "LLTextureCacheWorker: " << mID << " incorrect number of bytes read from body: " << bytes_read << " / " << file_size << llendl; - delete[] mReadData; + LLImageBase::deleteMemory(mReadData); mReadData = NULL; mDataSize = -1; // failed done = true; @@ -592,11 +592,11 @@ bool LLTextureCacheRemoteWorker::doWrite() { // We need to write a full record in the header cache so, if the amount of data is smaller // than a record, we need to transfer the data to a buffer padded with 0 and write that - U8* padBuffer = new U8[TEXTURE_CACHE_ENTRY_SIZE]; + U8* padBuffer = (U8*)LLImageBase::allocateMemory(TEXTURE_CACHE_ENTRY_SIZE); memset(padBuffer, 0, TEXTURE_CACHE_ENTRY_SIZE); // Init with zeros memcpy(padBuffer, mWriteData, mDataSize); // Copy the write buffer bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, padBuffer, offset, size, mCache->getLocalAPRFilePool()); - delete [] padBuffer; + LLImageBase::deleteMemory(padBuffer); } else { @@ -692,7 +692,7 @@ void LLTextureCacheWorker::finishWork(S32 param, bool completed) } else { - delete[] mReadData; + LLImageBase::deleteMemory(mReadData); mReadData = NULL; } } diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index d6d38de225..510afc6b9b 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -572,7 +572,7 @@ void LLTextureFetchWorker::setImagePriority(F32 priority) void LLTextureFetchWorker::resetFormattedData() { - delete[] mBuffer; + LLImageBase::deleteMemory(mBuffer); mBuffer = NULL; mBufferSize = 0; if (mFormattedImage.notNull()) @@ -642,7 +642,7 @@ bool LLTextureFetchWorker::doWork(S32 param) mSentRequest = UNSENT; mDecoded = FALSE; mWritten = FALSE; - delete[] mBuffer; + LLImageBase::deleteMemory(mBuffer); mBuffer = NULL; mBufferSize = 0; mHaveAllData = FALSE; @@ -997,7 +997,7 @@ bool LLTextureFetchWorker::doWork(S32 param) llassert_always(mBufferSize == cur_size + mRequestedSize); if(!mBufferSize)//no data received. { - delete[] mBuffer; + LLImageBase::deleteMemory(mBuffer); mBuffer = NULL; //abort. @@ -1025,7 +1025,7 @@ bool LLTextureFetchWorker::doWork(S32 param) mFileSize = mBufferSize + 1 ; //flag the file is not fully loaded. } - U8* buffer = new U8[mBufferSize]; + U8* buffer = (U8*)LLImageBase::allocateMemory(mBufferSize); if (cur_size > 0) { memcpy(buffer, mFormattedImage->getData(), cur_size); @@ -1034,7 +1034,7 @@ bool LLTextureFetchWorker::doWork(S32 param) // NOTE: setData releases current data and owns new data (buffer) mFormattedImage->setData(buffer, mBufferSize); // delete temp data - delete[] mBuffer; // Note: not 'buffer' (assigned in setData()) + LLImageBase::deleteMemory(mBuffer); // Note: not 'buffer' (assigned in setData()) mBuffer = NULL; mBufferSize = 0; mLoadedDiscard = mRequestedDiscard; @@ -1331,7 +1331,7 @@ bool LLTextureFetchWorker::processSimulatorPackets() if (buffer_size > cur_size) { /// We have new data - U8* buffer = new U8[buffer_size]; + U8* buffer = (U8*)LLImageBase::allocateMemory(buffer_size); S32 offset = 0; if (cur_size > 0 && mFirstPacket > 0) { @@ -1383,7 +1383,7 @@ S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels, if (data_size > 0) { // *TODO: set the formatted image data here directly to avoid the copy - mBuffer = new U8[data_size]; + mBuffer = (U8*)LLImageBase::allocateMemory(data_size); buffer->readAfter(channels.in(), NULL, mBuffer, data_size); mBufferSize += data_size; if (data_size < mRequestedSize && mRequestedDiscard == 0) -- cgit v1.2.3 From 9434f0c2a0e46c580a2aacc04cc1b58876bd3bd8 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Thu, 6 Jan 2011 16:48:00 -0700 Subject: fix an exit crash. --- indra/llcommon/llmemory.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'indra') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index f1285841b3..1f40f5e17a 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -1248,13 +1248,18 @@ S32 LLPrivateMemoryPool::getChunkIndex(U32 size) void LLPrivateMemoryPool::destroyPool() { lock() ; - for(U32 i = 0 ; i < mHashFactor; i++) + if(mNumOfChunks > 0) { - while(mChunkHashList[i]) + for(U32 i = 0 ; i < mHashFactor; i++) { - removeChunk(mChunkHashList[i]) ; + while(mChunkHashList[i]) + { + removeChunk(mChunkHashList[i]) ; + } } } + mChunkHashList.clear() ; + mHashFactor = 1 ; llassert_always(mNumOfChunks == 0) ; llassert_always(mReservedPoolSize == 0) ; -- cgit v1.2.3 From 7daa3d1ca10199468946feef0ce8eb67489deee0 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Fri, 7 Jan 2011 14:57:35 -0700 Subject: fixed a hash bug, enlarged the overhead for large allocations, and add new chunk to the tail of the linked list so new allocations go to oldest chunks first. --- indra/llcommon/llmemory.cpp | 46 +++++++++++++++++++++++++++++---------------- indra/llcommon/llmemory.h | 3 ++- 2 files changed, 32 insertions(+), 17 deletions(-) (limited to 'indra') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 1f40f5e17a..543f17baf4 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -393,8 +393,6 @@ LLPrivateMemoryPool::LLMemoryBlock::~LLMemoryBlock() //create and initialize a memory block void LLPrivateMemoryPool::LLMemoryBlock::init(char* buffer, U32 buffer_size, U32 slot_size) { - llassert_always(buffer_size >= slot_size) ; - mBuffer = buffer ; mBufferSize = buffer_size ; mSlotSize = slot_size ; @@ -590,12 +588,18 @@ void LLPrivateMemoryPool::LLMemoryChunk::init(char* buffer, U32 buffer_size, U32 } //static -U32 LLPrivateMemoryPool::LLMemoryChunk::getMaxOverhead(U32 data_buffer_size, U32 min_page_size) +U32 LLPrivateMemoryPool::LLMemoryChunk::getMaxOverhead(U32 data_buffer_size, U32 min_slot_size, + U32 max_slot_size, U32 min_block_size, U32 max_block_size) { //for large allocations, reserve some extra memory for meta data to avoid wasting much - if(data_buffer_size / min_page_size < 64) //large allocations + if(data_buffer_size / min_slot_size < 64) //large allocations { - return 4096 ; //4KB + U32 overhead = sizeof(LLMemoryChunk) + (data_buffer_size / min_block_size) * sizeof(LLMemoryBlock) + + sizeof(LLMemoryBlock*) * (max_slot_size / min_slot_size) + sizeof(LLMemoryBlock*) * (max_block_size / min_block_size + 1) ; + + //round to integer times of min_block_size + overhead = ((overhead + min_block_size - 1) / min_block_size) * min_block_size ; + return overhead ; } else { @@ -1290,12 +1294,14 @@ LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::addChunk(S32 chunk_inde if(chunk_index < LARGE_ALLOCATION) { preferred_size = CHUNK_SIZE ; //4MB - overhead = LLMemoryChunk::getMaxOverhead(preferred_size, MIN_BLOCK_SIZES[chunk_index]) ; + overhead = LLMemoryChunk::getMaxOverhead(preferred_size, MIN_SLOT_SIZES[chunk_index], + MAX_SLOT_SIZES[chunk_index], MIN_BLOCK_SIZES[chunk_index], MAX_BLOCK_SIZES[chunk_index]) ; } else { preferred_size = LARGE_CHUNK_SIZE ; //16MB - overhead = LLMemoryChunk::getMaxOverhead(preferred_size, MIN_BLOCK_SIZES[chunk_index]) ; + overhead = LLMemoryChunk::getMaxOverhead(preferred_size, MIN_SLOT_SIZES[chunk_index], + MAX_SLOT_SIZES[chunk_index], MIN_BLOCK_SIZES[chunk_index], MAX_BLOCK_SIZES[chunk_index]) ; } checkSize(preferred_size + overhead) ; @@ -1306,20 +1312,28 @@ LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::addChunk(S32 chunk_inde { return NULL ; } - memset(buffer, 0, preferred_size + overhead) ; - + LLMemoryChunk* chunk = new (buffer) LLMemoryChunk() ; chunk->init(buffer, preferred_size + overhead, MIN_SLOT_SIZES[chunk_index], MAX_SLOT_SIZES[chunk_index], MIN_BLOCK_SIZES[chunk_index], MAX_BLOCK_SIZES[chunk_index]) ; - //add to the head of the linked list - chunk->mNext = mChunkList[chunk_index] ; - if(mChunkList[chunk_index]) + //add to the tail of the linked list { - mChunkList[chunk_index]->mPrev = chunk ; + if(!mChunkList[chunk_index]) + { + mChunkList[chunk_index] = chunk ; + } + else + { + LLMemoryChunk* cur = mChunkList[chunk_index] ; + while(cur->mNext) + { + cur = cur->mNext ; + } + cur->mNext = chunk ; + chunk->mPrev = cur ; + } } - chunk->mPrev = NULL ; - mChunkList[chunk_index] = chunk ; //insert into the hash table addToHashTable(chunk) ; @@ -1425,7 +1439,7 @@ void LLPrivateMemoryPool::addToHashTable(LLMemoryChunk* chunk) { llassert_always(mChunkHashList[end_key] != chunk) - need_rehash = mChunkHashList[end_key]->mHashNext != NULL ; + need_rehash = mChunkHashList[end_key]->mHashNext != NULL || mChunkHashList[end_key] == chunk->mHashNext; if(!need_rehash) { mChunkHashList[end_key]->mHashNext = chunk ; diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index e42dc174b5..5a2889958b 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -142,7 +142,8 @@ public: bool containsAddress(const char* addr) const; - static U32 getMaxOverhead(U32 data_buffer_size, U32 min_page_size) ; + static U32 getMaxOverhead(U32 data_buffer_size, U32 min_slot_size, + U32 max_slot_size, U32 min_block_size, U32 max_block_size) ; void dump() ; -- cgit v1.2.3 From bcb5b209d1813681202524362dd186c8b0982357 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Wed, 12 Jan 2011 07:51:14 -0800 Subject: trivial: fix some mac compiling errors --- indra/llcommon/llmemory.cpp | 8 ++++---- indra/llimage/llimage.cpp | 2 +- indra/newview/llappviewer.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'indra') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 543f17baf4..875ff9971c 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -398,7 +398,7 @@ void LLPrivateMemoryPool::LLMemoryBlock::init(char* buffer, U32 buffer_size, U32 mSlotSize = slot_size ; mTotalSlots = buffer_size / mSlotSize ; - llassert_always(mTotalSlots < 256) ; //max number is 256 + llassert_always(buffer_size / mSlotSize < 256) ; //max number is 256 mAllocatedSlots = 0 ; @@ -1137,7 +1137,7 @@ char* LLPrivateMemoryPool::allocate(U32 size) LLMemoryChunk* chunk = mChunkList[chunk_idx]; while(chunk) { - if(p = chunk->allocate(size)) + if((p = chunk->allocate(size))) { break ; } @@ -1152,7 +1152,7 @@ char* LLPrivateMemoryPool::allocate(U32 size) chunk = mChunkList[chunk_idx]; while(chunk) { - if(p = chunk->allocate(size)) + if((p = chunk->allocate(size))) { break ; } @@ -1185,7 +1185,7 @@ void LLPrivateMemoryPool::free(void* addr) if(!chunk) { - delete[] addr ; //release from heap + delete[] (char*)addr ; //release from heap } else { diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index c99313f0ea..3baaa25617 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -148,7 +148,7 @@ void LLImageBase::deleteMemory(void* p) } else { - delete[] p ; + delete[] (char*)p ; } } diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 664ec7b0fb..c3122504cc 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -977,7 +977,7 @@ void LLAppViewer::initMaxHeapSize() void LLAppViewer::checkMemory() { const static F32 MEMORY_CHECK_INTERVAL = 1.0f ; //second - const static F32 MAX_QUIT_WAIT_TIME = 30.0f ; //seconds + //const static F32 MAX_QUIT_WAIT_TIME = 30.0f ; //seconds const static U32 MAX_SIZE_CHECKED_MEMORY_BLOCK = 64 * 1024 * 1024 ; //64 MB //static F32 force_quit_timer = MAX_QUIT_WAIT_TIME + MEMORY_CHECK_INTERVAL ; static void* last_reserved_address = NULL ; -- cgit v1.2.3 From ef490e308ccce8e6df85144784a0f4580f5ac6a1 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sat, 5 Feb 2011 15:58:07 +0100 Subject: Introduces a LLThreadLocalData class that can be accessed through the static LLThread::tldata(). Currently this object contains two (public) thread-local objects: a LLAPRRootPool and a LLVolatileAPRPool. The first is the general memory pool used by this thread (and this thread alone), while the second is intended for short lived memory allocations (needed for APR). The advantages of not mixing those two is that the latter is used most frequently, and as a result of it's nature can be destroyed and reconstructed on a "regular" basis. This patch adds LLAPRPool (completely replacing the old one), which is a wrapper around apr_pool_t* and has complete thread-safity checking. Whenever an apr call requires memory for some resource, a memory pool in the form of an LLAPRPool object can be created with the same life-time as this resource; assuring clean up of the memory no sooner, but also not much later than the life-time of the resource that needs the memory. Many, many function calls and constructors had the pool parameter simply removed (it is no longer the concern of the developer, if you don't write code that actually does an libapr call then you are no longer bothered with memory pools at all). However, I kept the notion of short-lived and long-lived allocations alive (see my remark in the jira here: https://jira.secondlife.com/browse/STORM-864?focusedCommentId=235356&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-235356 which requires that the LLAPRFile API needs to allow the user to specify how long they think a file will stay open. By choosing 'short_lived' as default for the constructor that immediately opens a file, the number of instances where this needs to be specified is drastically reduced however (obviously, any automatic LLAPRFile is short lived). *** Addressed Boroondas remarks in https://codereview.secondlife.com/r/99/ regarding (doxygen) comments. This patch effectively only changes comments. Includes some 'merge' stuff that ended up in llvocache.cpp (while starting as a bug fix, now only resulting in a cleanup). *** Added comment 'The use of apr_pool_t is OK here'. Added this comment on every line where apr_pool_t is correctly being used. This should make it easier to spot (future) errors where someone started to use apr_pool_t; you can just grep all sources for 'apr_pool_t' and immediately see where it's being used while LLAPRPool should have been used. Note that merging this patch is very easy: If there are no other uses of apr_pool_t in the code (one grep) and it compiles, then it will work. *** Second Merge (needed to remove 'delete mCreationMutex' from LLImageDecodeThread::~LLImageDecodeThread). *** Added back #include . Apparently that is needed on libapr version 1.2.8., the version used by Linden Lab, for calls to apr_queue_*. This is a bug in libapr (we also include , that is fixed in (at least) 1.3.7. Note that 1.2.8 is VERY old. Even 1.3.x is old. *** License fixes (GPL -> LGPL). And typo in comments. Addresses merov's comments on the review board. *** Added Merov's compile fixes for windows. --- indra/llaudio/llaudioengine_fmod.cpp | 2 +- indra/llaudio/llvorbisencode.cpp | 9 +- indra/llcharacter/llbvhloader.cpp | 3 +- indra/llcharacter/llkeyframemotionparam.cpp | 3 +- indra/llcharacter/llstatemachine.cpp | 3 +- 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 +- indra/llcrashlogger/llcrashlogger.cpp | 3 +- indra/llimage/llimage.cpp | 8 +- indra/llimage/llimagedimensionsinfo.cpp | 2 +- indra/llimage/llimagej2c.cpp | 3 +- indra/llimage/llimageworker.cpp | 8 +- indra/llimage/llimageworker.h | 2 +- indra/llmath/llvolumemgr.cpp | 4 +- indra/llmessage/llares.cpp | 17 +- indra/llmessage/llcurl.cpp | 2 +- indra/llmessage/lliohttpserver.cpp | 10 +- indra/llmessage/lliohttpserver.h | 2 +- indra/llmessage/lliosocket.cpp | 99 ++--- indra/llmessage/lliosocket.h | 33 +- indra/llmessage/llmail.cpp | 17 +- indra/llmessage/llmail.h | 4 +- indra/llmessage/llpumpio.cpp | 74 ++-- indra/llmessage/llpumpio.h | 31 +- indra/llmessage/llurlrequest.cpp | 25 +- indra/llmessage/message.cpp | 17 +- indra/llmessage/tests/networkio.h | 9 +- indra/llplugin/llplugininstance.cpp | 6 +- indra/llplugin/llplugininstance.h | 2 + indra/llplugin/llpluginmessagepipe.cpp | 2 - indra/llplugin/llpluginprocesschild.cpp | 2 +- indra/llplugin/llpluginprocessparent.cpp | 57 ++- indra/llplugin/llpluginprocessparent.h | 2 + indra/llplugin/llpluginsharedmemory.cpp | 9 +- indra/llplugin/llpluginsharedmemory.h | 3 + indra/llplugin/slplugin/slplugin.cpp | 4 - indra/llvfs/lllfsthread.cpp | 10 +- indra/llvfs/llvfs.cpp | 5 +- .../gstreamer010/llmediaimplgstreamer.h | 1 - .../gstreamer010/llmediaimplgstreamer_syms.cpp | 15 +- .../media_plugins/webkit/linux_volume_catcher.cpp | 14 +- indra/newview/llappviewer.cpp | 47 ++- indra/newview/llappviewer.h | 2 +- indra/newview/llappviewerlinux.cpp | 1 + indra/newview/llappviewerlinux_api_dbus.cpp | 14 +- indra/newview/llappviewermacosx.cpp | 1 + indra/newview/llfloateranimpreview.cpp | 3 +- indra/newview/llmainlooprepeater.cpp | 2 +- indra/newview/lltexturecache.cpp | 61 ++- indra/newview/lltexturecache.h | 3 - indra/newview/lltexturefetch.cpp | 3 - indra/newview/llviewermenufile.cpp | 3 +- indra/newview/llvoavatar.cpp | 3 +- indra/newview/llvocache.cpp | 54 ++- indra/newview/llvocache.h | 5 +- indra/newview/llvoicevivox.cpp | 2 +- indra/newview/llwatchdog.cpp | 4 +- indra/newview/tests/llworldmap_test.cpp | 1 - indra/test/lltemplatemessagebuilder_tut.cpp | 2 - indra/test/message_tut.cpp | 2 - indra/test/test.cpp | 17 +- indra/test_apps/llplugintest/llmediaplugintest.cpp | 4 - .../updater/llupdateinstaller.cpp | 4 +- 79 files changed, 1092 insertions(+), 1076 deletions(-) create mode 100644 indra/llcommon/llaprpool.cpp create mode 100644 indra/llcommon/llaprpool.h create mode 100644 indra/llcommon/llscopedvolatileaprpool.h (limited to 'indra') diff --git a/indra/llaudio/llaudioengine_fmod.cpp b/indra/llaudio/llaudioengine_fmod.cpp index a40de9fa68..88dfdb9c24 100644 --- a/indra/llaudio/llaudioengine_fmod.cpp +++ b/indra/llaudio/llaudioengine_fmod.cpp @@ -673,7 +673,7 @@ bool LLAudioBufferFMOD::loadWAV(const std::string& filename) return false; } - if (!LLAPRFile::isExist(filename, NULL, LL_APR_RPB)) + if (!LLAPRFile::isExist(filename, LL_APR_RPB)) { // File not found, abort. return false; diff --git a/indra/llaudio/llvorbisencode.cpp b/indra/llaudio/llvorbisencode.cpp index 0e0c80a456..44eeea0ca4 100644 --- a/indra/llaudio/llvorbisencode.cpp +++ b/indra/llaudio/llvorbisencode.cpp @@ -82,8 +82,7 @@ S32 check_for_invalid_wav_formats(const std::string& in_fname, std::string& erro error_msg.clear(); //******************************** - LLAPRFile infile ; - infile.open(in_fname,LL_APR_RB); + LLAPRFile infile(in_fname, LL_APR_RB); //******************************** if (!infile.getFileHandle()) { @@ -233,8 +232,7 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname S32 data_left = 0; - LLAPRFile infile ; - infile.open(in_fname,LL_APR_RB); + LLAPRFile infile(in_fname,LL_APR_RB); if (!infile.getFileHandle()) { llwarns << "Couldn't open temporary ogg file for writing: " << in_fname @@ -242,8 +240,7 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname return(LLVORBISENC_SOURCE_OPEN_ERR); } - LLAPRFile outfile ; - outfile.open(out_fname,LL_APR_WPB); + LLAPRFile outfile(out_fname, LL_APR_WPB); if (!outfile.getFileHandle()) { llwarns << "Couldn't open upload sound file for reading: " << in_fname diff --git a/indra/llcharacter/llbvhloader.cpp b/indra/llcharacter/llbvhloader.cpp index 532a2c1b0d..a39a344684 100644 --- a/indra/llcharacter/llbvhloader.cpp +++ b/indra/llcharacter/llbvhloader.cpp @@ -219,8 +219,7 @@ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName) //-------------------------------------------------------------------- std::string path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,fileName); - LLAPRFile infile ; - infile.open(path, LL_APR_R); + LLAPRFile infile(path, LL_APR_R); apr_file_t *fp = infile.getFileHandle(); if (!fp) return E_ST_NO_XLT_FILE; diff --git a/indra/llcharacter/llkeyframemotionparam.cpp b/indra/llcharacter/llkeyframemotionparam.cpp index 82fe8971f5..c3d5dec875 100644 --- a/indra/llcharacter/llkeyframemotionparam.cpp +++ b/indra/llcharacter/llkeyframemotionparam.cpp @@ -351,8 +351,7 @@ BOOL LLKeyframeMotionParam::loadMotions() // open the file //------------------------------------------------------------------------- S32 fileSize = 0; - LLAPRFile infile ; - infile.open(path, LL_APR_R, NULL, &fileSize); + LLAPRFile infile(path, LL_APR_R, &fileSize); apr_file_t* fp = infile.getFileHandle() ; if (!fp || fileSize == 0) { diff --git a/indra/llcharacter/llstatemachine.cpp b/indra/llcharacter/llstatemachine.cpp index e0454131a5..dcc4ff5f0e 100644 --- a/indra/llcharacter/llstatemachine.cpp +++ b/indra/llcharacter/llstatemachine.cpp @@ -204,8 +204,7 @@ LLFSMState* LLStateDiagram::getState(U32 state_id) BOOL LLStateDiagram::saveDotFile(const std::string& filename) { - LLAPRFile outfile ; - outfile.open(filename, LL_APR_W); + LLAPRFile outfile(filename, LL_APR_W); apr_file_t* dot_file = outfile.getFileHandle() ; if (!dot_file) diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 9342a22d46..d5b0a67533 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -32,6 +32,7 @@ set(llcommon_SOURCE_FILES llallocator_heap_profile.cpp llapp.cpp llapr.cpp + llaprpool.cpp llassettype.cpp llavatarname.cpp llbase32.cpp @@ -80,6 +81,7 @@ set(llcommon_SOURCE_FILES llrand.cpp llrefcount.cpp llrun.cpp + llscopedvolatileaprpool.h llsd.cpp llsdserialize.cpp llsdserialize_xml.cpp @@ -121,6 +123,7 @@ 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 39daefd1ad..e5bd2bfa3d 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -136,10 +136,6 @@ 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 d1c44c9403..1e4a51102e 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -29,212 +29,8 @@ #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 @@ -313,15 +109,17 @@ void ll_apr_assert_status(apr_status_t status, apr_dso_handle_t *handle) // LLAPRFile::LLAPRFile() : mFile(NULL), - mCurrentFilePoolp(NULL) + mVolatileFilePoolp(NULL), + mRegularFilePoolp(NULL) { } -LLAPRFile::LLAPRFile(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool) +LLAPRFile::LLAPRFile(std::string const& filename, apr_int32_t flags, S32* sizep, access_t access_type) : mFile(NULL), - mCurrentFilePoolp(NULL) + mVolatileFilePoolp(NULL), + mRegularFilePoolp(NULL) { - open(filename, flags, pool); + open(filename, flags, access_type, sizep); } LLAPRFile::~LLAPRFile() @@ -338,36 +136,58 @@ apr_status_t LLAPRFile::close() mFile = NULL ; } - if(mCurrentFilePoolp) + if (mVolatileFilePoolp) { - mCurrentFilePoolp->clearVolatileAPRPool() ; - mCurrentFilePoolp = NULL ; + mVolatileFilePoolp->clearVolatileAPRPool() ; + mVolatileFilePoolp = NULL ; + } + + if (mRegularFilePoolp) + { + delete mRegularFilePoolp; + mRegularFilePoolp = NULL; } return ret ; } -apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool, S32* sizep) +apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, access_t access_type, S32* sizep) { - apr_status_t s ; - - //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)); + llassert_always(!mFile); + llassert_always(!mVolatileFilePoolp && !mRegularFilePoolp); - if (s != APR_SUCCESS || !mFile) + 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) { mFile = NULL ; - + close() ; if (sizep) { *sizep = 0; } + return status; } - else if (sizep) + + if (sizep) { S32 file_size = 0; apr_off_t offset = 0; @@ -381,49 +201,7 @@ apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, LLV *sizep = file_size; } - 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 ; + return status; } // File I/O @@ -481,45 +259,6 @@ 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) { @@ -553,13 +292,15 @@ 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, LLVolatileAPRPool* pool) +S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes) { - //***************************************** - apr_file_t* file_handle = open(filename, pool, APR_READ|APR_BINARY); - //***************************************** - if (!file_handle) + 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) { + ll_apr_warn_status(s); + LL_WARNS("APR") << " while attempting to open file \"" << filename << '"' << LL_ENDL; return 0; } @@ -589,14 +330,13 @@ S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nb } } - //***************************************** - close(file_handle, pool) ; - //***************************************** + apr_file_close(file_handle); + return (S32)bytes_read; } //static -S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool) +S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes) { apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY; if (offset < 0) @@ -605,11 +345,13 @@ S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 n offset = 0; } - //***************************************** - apr_file_t* file_handle = open(filename, pool, flags); - //***************************************** - if (!file_handle) + 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) { + ll_apr_warn_status(s); + LL_WARNS("APR") << " while attempting to open file \"" << filename << '"' << LL_ENDL; return 0; } @@ -639,21 +381,18 @@ S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 n } } - //***************************************** - LLAPRFile::close(file_handle, pool); - //***************************************** + apr_file_close(file_handle); return (S32)bytes_written; } //static -bool LLAPRFile::remove(const std::string& filename, LLVolatileAPRPool* pool) +bool LLAPRFile::remove(const std::string& filename) { apr_status_t s; - pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; - s = apr_file_remove(filename.c_str(), pool->getVolatileAPRPool()); - pool->clearVolatileAPRPool() ; + LLScopedVolatileAPRPool pool; + s = apr_file_remove(filename.c_str(), pool); if (s != APR_SUCCESS) { @@ -665,13 +404,12 @@ bool LLAPRFile::remove(const std::string& filename, LLVolatileAPRPool* pool) } //static -bool LLAPRFile::rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool) +bool LLAPRFile::rename(const std::string& filename, const std::string& newname) { apr_status_t s; - pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; - s = apr_file_rename(filename.c_str(), newname.c_str(), pool->getVolatileAPRPool()); - pool->clearVolatileAPRPool() ; + LLScopedVolatileAPRPool pool; + s = apr_file_rename(filename.c_str(), newname.c_str(), pool); if (s != APR_SUCCESS) { @@ -683,49 +421,44 @@ bool LLAPRFile::rename(const std::string& filename, const std::string& newname, } //static -bool LLAPRFile::isExist(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags) +bool LLAPRFile::isExist(const std::string& filename, apr_int32_t flags) { - apr_file_t* apr_file; + apr_file_t* file_handle; apr_status_t s; - pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; - s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, pool->getVolatileAPRPool()); + LLScopedVolatileAPRPool pool; + s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool); - if (s != APR_SUCCESS || !apr_file) + if (s != APR_SUCCESS || !file_handle) { - pool->clearVolatileAPRPool() ; return false; } else { - apr_file_close(apr_file) ; - pool->clearVolatileAPRPool() ; + apr_file_close(file_handle); return true; } } //static -S32 LLAPRFile::size(const std::string& filename, LLVolatileAPRPool* pool) +S32 LLAPRFile::size(const std::string& filename) { - apr_file_t* apr_file; + apr_file_t* file_handle; apr_finfo_t info; apr_status_t s; - pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; - s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool->getVolatileAPRPool()); + LLScopedVolatileAPRPool pool; + s = apr_file_open(&file_handle, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool); - if (s != APR_SUCCESS || !apr_file) + if (s != APR_SUCCESS || !file_handle) { - pool->clearVolatileAPRPool() ; - return 0; } else { - apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, apr_file); + apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, file_handle); - apr_file_close(apr_file) ; - pool->clearVolatileAPRPool() ; + apr_file_close(file_handle) ; if (s == APR_SUCCESS) { @@ -739,31 +472,29 @@ S32 LLAPRFile::size(const std::string& filename, LLVolatileAPRPool* pool) } //static -bool LLAPRFile::makeDir(const std::string& dirname, LLVolatileAPRPool* pool) +bool LLAPRFile::makeDir(const std::string& dirname) { apr_status_t s; - pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; - s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool->getVolatileAPRPool()); - pool->clearVolatileAPRPool() ; + LLScopedVolatileAPRPool pool; + s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool); if (s != APR_SUCCESS) { ll_apr_warn_status(s); - LL_WARNS("APR") << " Attempting to make directory: " << dirname << LL_ENDL; + LL_WARNS("APR") << " while attempting to make directory: " << dirname << LL_ENDL; return false; } return true; } //static -bool LLAPRFile::removeDir(const std::string& dirname, LLVolatileAPRPool* pool) +bool LLAPRFile::removeDir(const std::string& dirname) { apr_status_t s; - pool = pool ? pool : LLAPRFile::sAPRFilePoolp ; - s = apr_file_remove(dirname.c_str(), pool->getVolatileAPRPool()); - pool->clearVolatileAPRPool() ; + LLScopedVolatileAPRPool pool; + s = apr_file_remove(dirname.c_str(), pool); if (s != APR_SUCCESS) { diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index af33ce666f..3f846f1314 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -50,71 +50,9 @@ #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; - -/** - * @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 LLAPRPool; +class LLVolatileAPRPool; /** * @class LLScopedLock @@ -205,15 +143,20 @@ class LL_COMMON_API LLAPRFile : boost::noncopyable // make this non copyable since a copy closes the file private: apr_file_t* mFile ; - LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool. + LLVolatileAPRPool* mVolatileFilePoolp; // (Thread local) APR pool currently in use. + LLAPRPool* mRegularFilePoolp; // ...or a regular 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(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool = NULL); + LLAPRFile(std::string const& filename, apr_int32_t flags, S32* sizep = NULL, access_t access_type = short_lived); ~LLAPRFile() ; - - 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 open(const std::string& filename, apr_int32_t flags, access_t access_type, S32* sizep = NULL); apr_status_t close() ; // Returns actual offset, -1 if seek fails @@ -226,32 +169,24 @@ 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, 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); + 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); // 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); // offset<0 means append + 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 //******************************************************************************************************************************* }; @@ -267,6 +202,4 @@ 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 new file mode 100644 index 0000000000..6f21b61b65 --- /dev/null +++ b/indra/llcommon/llaprpool.cpp @@ -0,0 +1,202 @@ +/** + * @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 new file mode 100644 index 0000000000..bf4102c584 --- /dev/null +++ b/indra/llcommon/llaprpool.h @@ -0,0 +1,256 @@ +/** + * @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 8be9e4f4de..b8a7394852 100644 --- a/indra/llcommon/llcommon.cpp +++ b/indra/llcommon/llcommon.cpp @@ -30,18 +30,10 @@ #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(); @@ -55,10 +47,5 @@ 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 ca9cad5d05..171590f3d8 100644 --- a/indra/llcommon/llcommon.h +++ b/indra/llcommon/llcommon.h @@ -35,8 +35,6 @@ 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 bb64152407..75048073ca 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -866,6 +866,9 @@ 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 4a42241c4f..15d167c32e 100644 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -296,5 +296,4 @@ 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 d394f179fb..4b5cdbe288 100644 --- a/indra/llcommon/llfixedbuffer.cpp +++ b/indra/llcommon/llfixedbuffer.cpp @@ -30,8 +30,7 @@ LLFixedBuffer::LLFixedBuffer(const U32 max_lines) : LLLineBuffer(), - mMaxLines(max_lines), - mMutex(NULL) + mMaxLines(max_lines) { mTimer.reset(); } diff --git a/indra/llcommon/llscopedvolatileaprpool.h b/indra/llcommon/llscopedvolatileaprpool.h new file mode 100644 index 0000000000..dbaf4edcad --- /dev/null +++ b/indra/llcommon/llscopedvolatileaprpool.h @@ -0,0 +1,52 @@ +/** + * @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 49d05ef411..4917e3b935 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -63,6 +63,9 @@ 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(); @@ -75,38 +78,20 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap } -LLThread::LLThread(const std::string& name, apr_pool_t *poolp) : - mPaused(FALSE), +LLThread::LLThread(std::string const& name) : + mPaused(false), mName(name), mAPRThreadp(NULL), - mStatus(STOPPED) + mStatus(STOPPED), + mThreadLocalData(NULL) { - // 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 ; + mRunCondition = new LLCondition; } LLThread::~LLThread() { shutdown(); - - if(mLocalAPRFilePoolp) - { - delete mLocalAPRFilePoolp ; - mLocalAPRFilePoolp = NULL ; - } } void LLThread::shutdown() @@ -143,7 +128,7 @@ void LLThread::shutdown() if (!isStopped()) { // This thread just wouldn't stop, even though we gave it time - llwarns << "LLThread::~LLThread() exiting thread before clean exit!" << llendl; + llwarns << "LLThread::shutdown() exiting thread before clean exit!" << llendl; // Put a stake in its heart. apr_thread_exit(mAPRThreadp, -1); return; @@ -153,15 +138,8 @@ void LLThread::shutdown() delete mRunCondition; mRunCondition = 0; - - if (mIsLocalPool && mAPRPoolp) - { - apr_pool_destroy(mAPRPoolp); - mAPRPoolp = 0; - } } - void LLThread::start() { llassert(isStopped()); @@ -170,7 +148,7 @@ void LLThread::start() mStatus = RUNNING; apr_status_t status = - apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, mAPRPoolp); + apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, tldata().mRootPool()); if(status == APR_SUCCESS) { @@ -195,7 +173,7 @@ void LLThread::pause() if (!mPaused) { // this will cause the thread to stop execution as soon as checkPause() is called - mPaused = 1; // Does not need to be atomic since this is only set/unset from the main thread + mPaused = true; // Does not need to be atomic since this is only set/unset from the main thread } } @@ -203,7 +181,7 @@ void LLThread::unpause() { if (mPaused) { - mPaused = 0; + mPaused = false; } wake(); // wake up the thread if necessary @@ -280,85 +258,76 @@ void LLThread::wakeLocked() } } -//============================================================================ - -LLMutex::LLMutex(apr_pool_t *poolp) : - mAPRMutexp(NULL) -{ - //if (poolp) - //{ - // mIsLocalPool = FALSE; - // mAPRPoolp = poolp; - //} - //else - { - mIsLocalPool = TRUE; - apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread - } - apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mAPRPoolp); -} +#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; -LLMutex::~LLMutex() +//static +void LLThreadLocalData::init(void) { -#if MUTEX_DEBUG - llassert_always(!isLocked()); // better not be locked! -#endif - apr_thread_mutex_destroy(mAPRMutexp); - mAPRMutexp = NULL; - if (mIsLocalPool) + // Only do this once. + if (sThreadLocalDataKey) { - apr_pool_destroy(mAPRPoolp); + return; } -} + 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. -void LLMutex::lock() -{ - 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; + // 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(); #endif } -void LLMutex::unlock() +// This is called once for every thread when the thread is destructed. +//static +void LLThreadLocalData::destroy(void* thread_local_data) { -#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); + delete static_cast(thread_local_data); } -bool LLMutex::isLocked() +//static +void LLThreadLocalData::create(LLThread* threadp) { - apr_status_t status = apr_thread_mutex_trylock(mAPRMutexp); - if (APR_STATUS_IS_EBUSY(status)) + LLThreadLocalData* new_tld = new LLThreadLocalData; + if (threadp) { - return true; + threadp->mThreadLocalData = new_tld; } - else + apr_status_t status = apr_threadkey_private_set(new_tld, sThreadLocalDataKey); + llassert_always(status == APR_SUCCESS); +} + +//static +LLThreadLocalData& LLThreadLocalData::tldata(void) +{ + if (!sThreadLocalDataKey) { - apr_thread_mutex_unlock(mAPRMutexp); - return false; + LLThreadLocalData::init(); } + + void* data; + apr_status_t status = apr_threadkey_private_get(&data, sThreadLocalDataKey); + llassert_always(status == APR_SUCCESS); + return *static_cast(data); } //============================================================================ -LLCondition::LLCondition(apr_pool_t *poolp) : - LLMutex(poolp) +LLCondition::LLCondition(LLAPRPool& parent) : LLMutex(parent) { - // base class (LLMutex) has already ensured that mAPRPoolp is set up. - - apr_thread_cond_create(&mAPRCondp, mAPRPoolp); + apr_thread_cond_create(&mAPRCondp, mPool()); } @@ -396,7 +365,7 @@ void LLThreadSafeRefCount::initThreadSafeRefCount() { if (!sMutex) { - sMutex = new LLMutex(0); + sMutex = new LLMutex; } } diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index f1c6cd75af..757832b8ca 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -29,12 +29,34 @@ #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: @@ -45,7 +67,7 @@ public: QUITTING= 2 // Someone wants this thread to quit } EThreadStatus; - LLThread(const std::string& name, apr_pool_t *poolp = NULL); + LLThread(std::string const& name); virtual ~LLThread(); // Warning! You almost NEVER want to destroy a thread unless it's in the STOPPED state. virtual void shutdown(); // stops the thread @@ -60,7 +82,7 @@ public: // Called from MAIN THREAD. void pause(); void unpause(); - bool isPaused() { return isStopped() || mPaused == TRUE; } + bool isPaused() { return isStopped() || mPaused; } // Cause the thread to wake up and check its condition void wake(); @@ -74,11 +96,11 @@ public: // this kicks off the apr thread void start(void); - apr_pool_t *getAPRPool() { return mAPRPoolp; } - LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; } + // Return thread-local data for the current thread. + static LLThreadLocalData& tldata(void) { return LLThreadLocalData::tldata(); } 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); @@ -88,14 +110,10 @@ protected: LLCondition* mRunCondition; apr_thread_t *mAPRThreadp; - apr_pool_t *mAPRPoolp; - 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 ; + friend void LLThreadLocalData::create(LLThread* threadp); + LLThreadLocalData* mThreadLocalData; void setQuitting(); @@ -125,30 +143,80 @@ protected: #define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO) -class LL_COMMON_API LLMutex +#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: - 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 - + 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 +{ +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; + } + protected: - apr_thread_mutex_t *mAPRMutexp; - apr_pool_t *mAPRPoolp; - BOOL mIsLocalPool; -#if MUTEX_DEBUG - std::map mIsLocked; + 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(); #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(apr_pool_t *apr_poolp); // Defaults to global pool, could use the thread pool as well. + LLCondition(LLAPRPool& parent = LLThread::tldata().mRootPool); ~LLCondition(); void wait(); // blocks @@ -159,10 +227,10 @@ protected: apr_thread_cond_t *mAPRCondp; }; -class LLMutexLock +class LL_COMMON_API LLMutexLock { public: - LLMutexLock(LLMutex* mutex) + LLMutexLock(LLMutexBase* mutex) { mMutex = mutex; mMutex->lock(); @@ -172,7 +240,7 @@ public: mMutex->unlock(); } private: - LLMutex* mMutex; + LLMutexBase* mMutex; }; //============================================================================ diff --git a/indra/llcommon/llthreadsafequeue.cpp b/indra/llcommon/llthreadsafequeue.cpp index 8a73e632a9..05d24944f3 100644 --- a/indra/llcommon/llthreadsafequeue.cpp +++ b/indra/llcommon/llthreadsafequeue.cpp @@ -34,19 +34,11 @@ //----------------------------------------------------------------------------- -LLThreadSafeQueueImplementation::LLThreadSafeQueueImplementation(apr_pool_t * pool, unsigned int capacity): - mOwnsPool(pool == 0), - mPool(pool), +LLThreadSafeQueueImplementation::LLThreadSafeQueueImplementation(unsigned int capacity): mQueue(0) { - 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); + mPool.create(); + apr_status_t status = apr_queue_create(&mQueue, capacity, mPool()); if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate queue"); } @@ -59,7 +51,6 @@ 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 58cac38769..43d0b396f2 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(apr_pool_t * pool, unsigned int capacity); + LLThreadSafeQueueImplementation(unsigned int capacity); ~LLThreadSafeQueueImplementation(); void pushFront(void * element); bool tryPushFront(void * element); @@ -84,8 +84,7 @@ public: size_t size(); private: - bool mOwnsPool; - apr_pool_t * mPool; + LLAPRPool mPool; // The pool used for mQueue. apr_queue_t * mQueue; }; @@ -99,9 +98,8 @@ class LLThreadSafeQueue public: typedef ElementT value_type; - // 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); + // Constructor. + LLThreadSafeQueue(unsigned int capacity = 1024); // Add an element to the front of queue (will block if the queue has // reached capacity). @@ -139,8 +137,8 @@ private: template -LLThreadSafeQueue::LLThreadSafeQueue(apr_pool_t * pool, unsigned int capacity): - mImplementation(pool, capacity) +LLThreadSafeQueue::LLThreadSafeQueue(unsigned int capacity) : + mImplementation(capacity) { ; // No op. } diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp index 3ac50832fd..6b308bb917 100644 --- a/indra/llcommon/llworkerthread.cpp +++ b/indra/llcommon/llworkerthread.cpp @@ -37,12 +37,7 @@ LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded) : LLQueuedThread(name, threaded) { - mDeleteMutex = new LLMutex(NULL); - - if(!mLocalAPRFilePoolp) - { - mLocalAPRFilePoolp = new LLVolatileAPRPool() ; - } + mDeleteMutex = new LLMutex; } LLWorkerThread::~LLWorkerThread() @@ -204,7 +199,6 @@ 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 9bff18303e..bef5ef53fe 100644 --- a/indra/llcommon/llworkerthread.h +++ b/indra/llcommon/llworkerthread.h @@ -94,7 +94,6 @@ public: private: void deleteWorker(LLWorkerClass* workerclass); // schedule for deletion - }; //============================================================================ @@ -194,7 +193,7 @@ protected: U32 mRequestPriority; // last priority set private: - LLMutex mMutex; + LLMutexRootPool mMutex; // Use LLMutexRootPool since this object is created and destructed by multiple threads. LLAtomicU32 mWorkFlags; }; diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp index 68e45f36e4..8f7916f565 100644 --- a/indra/llcrashlogger/llcrashlogger.cpp +++ b/indra/llcrashlogger/llcrashlogger.cpp @@ -390,8 +390,7 @@ bool LLCrashLogger::init() return false; } - gServicePump = new LLPumpIO(gAPRPoolp); - gServicePump->prime(gAPRPoolp); + gServicePump = new LLPumpIO; LLHTTPClient::setPump(*gServicePump); //If we've opened the crash logger, assume we can delete the marker file if it exists diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 39211bf7fa..f4399d4ed4 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -51,7 +51,7 @@ LLMutex* LLImage::sMutex = NULL; //static void LLImage::initClass() { - sMutex = new LLMutex(NULL); + sMutex = new LLMutex; } //static @@ -1557,8 +1557,7 @@ BOOL LLImageFormatted::load(const std::string &filename) resetLastError(); S32 file_size = 0; - LLAPRFile infile ; - infile.open(filename, LL_APR_RB, NULL, &file_size); + LLAPRFile infile(filename, LL_APR_RB, &file_size); apr_file_t* apr_file = infile.getFileHandle(); if (!apr_file) { @@ -1593,8 +1592,7 @@ BOOL LLImageFormatted::save(const std::string &filename) { resetLastError(); - LLAPRFile outfile ; - outfile.open(filename, LL_APR_WB); + LLAPRFile outfile(filename, LL_APR_WB); if (!outfile.getFileHandle()) { setLastError("Unable to open file for writing", filename); diff --git a/indra/llimage/llimagedimensionsinfo.cpp b/indra/llimage/llimagedimensionsinfo.cpp index 835664c60f..8a10956a5b 100644 --- a/indra/llimage/llimagedimensionsinfo.cpp +++ b/indra/llimage/llimagedimensionsinfo.cpp @@ -40,7 +40,7 @@ bool LLImageDimensionsInfo::load(const std::string& src_filename,U32 codec) mSrcFilename = src_filename; S32 file_size = 0; - apr_status_t s = mInfile.open(src_filename, LL_APR_RB, NULL, &file_size); + apr_status_t s = mInfile.open(src_filename, LL_APR_RB, LLAPRFile::long_lived, &file_size); if (s != APR_SUCCESS) { diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index cb2a85fa91..5f488a6764 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -358,8 +358,7 @@ BOOL LLImageJ2C::loadAndValidate(const std::string &filename) resetLastError(); S32 file_size = 0; - LLAPRFile infile ; - infile.open(filename, LL_APR_RB, NULL, &file_size); + LLAPRFile infile(filename, LL_APR_RB, &file_size); apr_file_t* apr_file = infile.getFileHandle() ; if (!apr_file) { diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp index 28dc3bd313..2c6d6f31ea 100644 --- a/indra/llimage/llimageworker.cpp +++ b/indra/llimage/llimageworker.cpp @@ -35,20 +35,18 @@ LLImageDecodeThread::LLImageDecodeThread(bool threaded) : LLQueuedThread("imagedecode", threaded) { - mCreationMutex = new LLMutex(getAPRPool()); } //virtual LLImageDecodeThread::~LLImageDecodeThread() { - delete mCreationMutex ; } // MAIN THREAD // virtual S32 LLImageDecodeThread::update(U32 max_time_ms) { - LLMutexLock lock(mCreationMutex); + LLMutexLock lock(&mCreationMutex); for (creation_list_t::iterator iter = mCreationList.begin(); iter != mCreationList.end(); ++iter) { @@ -71,7 +69,7 @@ S32 LLImageDecodeThread::update(U32 max_time_ms) LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(LLImageFormatted* image, U32 priority, S32 discard, BOOL needs_aux, Responder* responder) { - LLMutexLock lock(mCreationMutex); + LLMutexLock lock(&mCreationMutex); handle_t handle = generateHandle(); mCreationList.push_back(creation_info(handle, image, priority, discard, needs_aux, responder)); return handle; @@ -81,7 +79,7 @@ LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(LLImageFormatted* // Returns the size of the mutex guarded list as an indication of sanity S32 LLImageDecodeThread::tut_size() { - LLMutexLock lock(mCreationMutex); + LLMutexLock lock(&mCreationMutex); S32 res = mCreationList.size(); return res; } diff --git a/indra/llimage/llimageworker.h b/indra/llimage/llimageworker.h index c684222fa5..6a24b7522a 100644 --- a/indra/llimage/llimageworker.h +++ b/indra/llimage/llimageworker.h @@ -98,7 +98,7 @@ private: }; typedef std::list creation_list_t; creation_list_t mCreationList; - LLMutex* mCreationMutex; + LLMutex mCreationMutex; }; #endif diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp index 88c195936c..734440d312 100644 --- a/indra/llmath/llvolumemgr.cpp +++ b/indra/llmath/llvolumemgr.cpp @@ -49,7 +49,7 @@ LLVolumeMgr::LLVolumeMgr() { // the LLMutex magic interferes with easy unit testing, // so you now must manually call useMutex() to use it - //mDataMutex = new LLMutex(gAPRPoolp); + //mDataMutex = new LLMutex; } LLVolumeMgr::~LLVolumeMgr() @@ -216,7 +216,7 @@ void LLVolumeMgr::useMutex() { if (!mDataMutex) { - mDataMutex = new LLMutex(gAPRPoolp); + mDataMutex = new LLMutex; } } diff --git a/indra/llmessage/llares.cpp b/indra/llmessage/llares.cpp index 5a67035ed1..fab9858b69 100644 --- a/indra/llmessage/llares.cpp +++ b/indra/llmessage/llares.cpp @@ -28,6 +28,7 @@ #include "linden_common.h" #include "llares.h" +#include "llscopedvolatileaprpool.h" #include #include @@ -464,11 +465,6 @@ void LLAres::search(const std::string &query, LLResType type, bool LLAres::process(U64 timeout) { - if (!gAPRPoolp) - { - ll_init_apr(); - } - ares_socket_t socks[ARES_GETSOCK_MAXNUM]; apr_pollfd_t aprFds[ARES_GETSOCK_MAXNUM]; apr_int32_t nsds = 0; @@ -482,10 +478,7 @@ bool LLAres::process(U64 timeout) return nsds > 0; } - apr_status_t status; - LLAPRPool pool; - status = pool.getStatus() ; - ll_apr_assert_status(status); + LLScopedVolatileAPRPool scoped_pool; for (int i = 0; i < ARES_GETSOCK_MAXNUM; i++) { @@ -502,7 +495,7 @@ bool LLAres::process(U64 timeout) apr_socket_t *aprSock = NULL; - status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], pool.getAPRPool()); + apr_status_t status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], scoped_pool); if (status != APR_SUCCESS) { ll_apr_warn_status(status); @@ -511,7 +504,7 @@ bool LLAres::process(U64 timeout) aprFds[nactive].desc.s = aprSock; aprFds[nactive].desc_type = APR_POLL_SOCKET; - aprFds[nactive].p = pool.getAPRPool(); + aprFds[nactive].p = scoped_pool; aprFds[nactive].rtnevents = 0; aprFds[nactive].client_data = &socks[i]; @@ -520,7 +513,7 @@ bool LLAres::process(U64 timeout) if (nactive > 0) { - status = apr_poll(aprFds, nactive, &nsds, timeout); + apr_status_t status = apr_poll(aprFds, nactive, &nsds, timeout); if (status != APR_SUCCESS && status != APR_TIMEUP) { diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index a485fa0160..4d3b382f7a 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -1039,7 +1039,7 @@ void LLCurl::initClass() S32 mutex_count = CRYPTO_num_locks(); for (S32 i=0; i factory_ptr(factory); - LLIOServerSocket* server = new LLIOServerSocket(pool, socket, factory_ptr); + LLIOServerSocket* server = new LLIOServerSocket(socket, factory_ptr); LLPumpIO::chain_t chain; chain.push_back(LLIOPipe::ptr_t(server)); diff --git a/indra/llmessage/lliohttpserver.h b/indra/llmessage/lliohttpserver.h index 5c1b0531ff..2294e4b8ae 100644 --- a/indra/llmessage/lliohttpserver.h +++ b/indra/llmessage/lliohttpserver.h @@ -50,7 +50,7 @@ class LLIOHTTPServer public: typedef void (*timing_callback_t)(const char* hashed_name, F32 time, void* data); - static LLHTTPNode& create(apr_pool_t* pool, LLPumpIO& pump, U16 port); + static LLHTTPNode& create(LLPumpIO& pump, U16 port); /**< Creates an HTTP wire server on the pump for the given TCP port. * * Returns the root node of the new server. Add LLHTTPNode instances diff --git a/indra/llmessage/lliosocket.cpp b/indra/llmessage/lliosocket.cpp index ca84fa8bb8..e802d9b3a6 100644 --- a/indra/llmessage/lliosocket.cpp +++ b/indra/llmessage/lliosocket.cpp @@ -35,6 +35,7 @@ #include "llhost.h" #include "llmemtype.h" #include "llpumpio.h" +#include "llthread.h" // // constants @@ -98,51 +99,31 @@ void ll_debug_socket(const char* msg, apr_socket_t* apr_sock) /// // static -LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port) +LLSocket::ptr_t LLSocket::create(EType type, U16 port) { LLMemType m1(LLMemType::MTYPE_IO_TCP); - LLSocket::ptr_t rv; - apr_socket_t* socket = NULL; - apr_pool_t* new_pool = NULL; apr_status_t status = APR_EGENERAL; - - // create a pool for the socket - status = apr_pool_create(&new_pool, pool); - if(ll_apr_warn_status(status)) - { - if(new_pool) apr_pool_destroy(new_pool); - return rv; - } + LLSocket::ptr_t rv(new LLSocket); if(STREAM_TCP == type) { - status = apr_socket_create( - &socket, - APR_INET, - SOCK_STREAM, - APR_PROTO_TCP, - new_pool); + status = apr_socket_create(&rv->mSocket, APR_INET, SOCK_STREAM, APR_PROTO_TCP, rv->mPool()); } else if(DATAGRAM_UDP == type) { - status = apr_socket_create( - &socket, - APR_INET, - SOCK_DGRAM, - APR_PROTO_UDP, - new_pool); + status = apr_socket_create(&rv->mSocket, APR_INET, SOCK_DGRAM, APR_PROTO_UDP, rv->mPool()); } else { - if(new_pool) apr_pool_destroy(new_pool); + rv.reset(); return rv; } if(ll_apr_warn_status(status)) { - if(new_pool) apr_pool_destroy(new_pool); + rv->mSocket = NULL; + rv.reset(); return rv; } - rv = ptr_t(new LLSocket(socket, new_pool)); if(port > 0) { apr_sockaddr_t* sa = NULL; @@ -152,7 +133,7 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port) APR_UNSPEC, port, 0, - new_pool); + rv->mPool()); if(ll_apr_warn_status(status)) { rv.reset(); @@ -160,8 +141,8 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port) } // This allows us to reuse the address on quick down/up. This // is unlikely to create problems. - ll_apr_warn_status(apr_socket_opt_set(socket, APR_SO_REUSEADDR, 1)); - status = apr_socket_bind(socket, sa); + ll_apr_warn_status(apr_socket_opt_set(rv->mSocket, APR_SO_REUSEADDR, 1)); + status = apr_socket_bind(rv->mSocket, sa); if(ll_apr_warn_status(status)) { rv.reset(); @@ -175,7 +156,7 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port) // to keep a queue of incoming connections for ACCEPT. lldebugs << "Setting listen state for socket." << llendl; status = apr_socket_listen( - socket, + rv->mSocket, LL_DEFAULT_LISTEN_BACKLOG); if(ll_apr_warn_status(status)) { @@ -196,21 +177,28 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port) } // static -LLSocket::ptr_t LLSocket::create(apr_socket_t* socket, apr_pool_t* pool) +LLSocket::ptr_t LLSocket::create(apr_status_t& status, LLSocket::ptr_t& listen_socket) { LLMemType m1(LLMemType::MTYPE_IO_TCP); - LLSocket::ptr_t rv; - if(!socket) + if (!listen_socket->getSocket()) + { + status = APR_ENOSOCKET; + return LLSocket::ptr_t(); + } + LLSocket::ptr_t rv(new LLSocket); + lldebugs << "accepting socket" << llendl; + status = apr_socket_accept(&rv->mSocket, listen_socket->getSocket(), rv->mPool()); + if (status != APR_SUCCESS) { + rv->mSocket = NULL; + rv.reset(); return rv; } - rv = ptr_t(new LLSocket(socket, pool)); rv->mPort = PORT_EPHEMERAL; rv->setOptions(); return rv; } - bool LLSocket::blockingConnect(const LLHost& host) { if(!mSocket) return false; @@ -223,7 +211,7 @@ bool LLSocket::blockingConnect(const LLHost& host) APR_UNSPEC, host.getPort(), 0, - mPool))) + mPool()))) { return false; } @@ -234,13 +222,11 @@ bool LLSocket::blockingConnect(const LLHost& host) return true; } -LLSocket::LLSocket(apr_socket_t* socket, apr_pool_t* pool) : - mSocket(socket), - mPool(pool), +LLSocket::LLSocket() : + mSocket(NULL), + mPool(LLThread::tldata().mRootPool), mPort(PORT_INVALID) { - ll_debug_socket("Constructing wholely formed socket", mSocket); - LLMemType m1(LLMemType::MTYPE_IO_TCP); } LLSocket::~LLSocket() @@ -252,10 +238,6 @@ LLSocket::~LLSocket() ll_debug_socket("Destroying socket", mSocket); apr_socket_close(mSocket); } - if(mPool) - { - apr_pool_destroy(mPool); - } } void LLSocket::setOptions() @@ -516,10 +498,8 @@ LLIOPipe::EStatus LLIOSocketWriter::process_impl( /// LLIOServerSocket::LLIOServerSocket( - apr_pool_t* pool, LLIOServerSocket::socket_t listener, factory_t factory) : - mPool(pool), mListenSocket(listener), mReactor(factory), mInitialized(false), @@ -579,21 +559,15 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl( lldebugs << "accepting socket" << llendl; PUMP_DEBUG; - apr_pool_t* new_pool = NULL; - apr_status_t status = apr_pool_create(&new_pool, mPool); - apr_socket_t* socket = NULL; - status = apr_socket_accept( - &socket, - mListenSocket->getSocket(), - new_pool); - LLSocket::ptr_t llsocket(LLSocket::create(socket, new_pool)); + apr_status_t status; + LLSocket::ptr_t llsocket(LLSocket::create(status, mListenSocket)); //EStatus rv = STATUS_ERROR; - if(llsocket) + if(llsocket && status == APR_SUCCESS) { PUMP_DEBUG; apr_sockaddr_t* remote_addr; - apr_socket_addr_get(&remote_addr, APR_REMOTE, socket); + apr_socket_addr_get(&remote_addr, APR_REMOTE, llsocket->getSocket()); char* remote_host_string; apr_sockaddr_ip_get(&remote_host_string, remote_addr); @@ -608,7 +582,6 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl( { chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(llsocket))); pump->addChain(chain, mResponseTimeout); - status = STATUS_OK; } else { @@ -617,7 +590,8 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl( } else { - llwarns << "Unable to create linden socket." << llendl; + char buf[256]; + llwarns << "Unable to accept linden socket: " << apr_strerror(status, buf, sizeof(buf)) << llendl; } PUMP_DEBUG; @@ -630,11 +604,10 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl( #if 0 LLIODataSocket::LLIODataSocket( U16 suggested_port, - U16 start_discovery_port, - apr_pool_t* pool) : + U16 start_discovery_port) : mSocket(NULL) { - if(!pool || (PORT_INVALID == suggested_port)) return; + if(PORT_INVALID == suggested_port) return; if(ll_apr_warn_status(apr_socket_create(&mSocket, APR_INET, SOCK_DGRAM, APR_PROTO_UDP, pool))) return; apr_sockaddr_t* sa = NULL; if(ll_apr_warn_status(apr_sockaddr_info_get(&sa, APR_ANYADDR, APR_UNSPEC, suggested_port, 0, pool))) return; diff --git a/indra/llmessage/lliosocket.h b/indra/llmessage/lliosocket.h index 6806e5084a..1e35225512 100644 --- a/indra/llmessage/lliosocket.h +++ b/indra/llmessage/lliosocket.h @@ -38,7 +38,6 @@ */ #include "lliopipe.h" -#include "apr_pools.h" #include "apr_network_io.h" #include "llchainio.h" @@ -88,34 +87,22 @@ public: * socket. If you intend the socket to be known to external * clients without prior port notification, do not use * PORT_EPHEMERAL. - * @param pool The apr pool to use. A child pool will be created - * and associated with the socket. * @param type The type of socket to create * @param port The port for the socket * @return A valid socket shared pointer if the call worked. */ static ptr_t create( - apr_pool_t* pool, EType type, U16 port = PORT_EPHEMERAL); /** - * @brief Create a LLSocket when you already have an apr socket. + * @brief Create a LLSocket by accepting a connection from a listen socket. * - * This method assumes an ephemeral port. This is typically used - * by calls which spawn a socket such as a call to - * accept() as in the server socket. This call should - * not fail if you have a valid apr socket. - * Because of the nature of how accept() works, you are expected - * to create a new pool for the socket, use that pool for the - * accept, and pass it in here where it will be bound with the - * socket and destroyed at the same time. - * @param socket The apr socket to use - * @param pool The pool used to create the socket. *NOTE: The pool - * passed in will be DESTROYED. + * @param status Output. Status of the accept if a valid listen socket was passed. + * @param listen_socket The listen socket to use. * @return A valid socket shared pointer if the call worked. */ - static ptr_t create(apr_socket_t* socket, apr_pool_t* pool); + static ptr_t create(apr_status_t& status, ptr_t& listen_socket); /** * @brief Perform a blocking connect to a host. Do not use in production. @@ -150,7 +137,7 @@ protected: * @brief Protected constructor since should only make sockets * with one of the two create() calls. */ - LLSocket(apr_socket_t* socket, apr_pool_t* pool); + LLSocket(void); /** * @brief Set default socket options. @@ -167,8 +154,8 @@ protected: // The apr socket. apr_socket_t* mSocket; - // our memory pool - apr_pool_t* mPool; + // Our memory pool. + LLAPRPool mPool; // The port if we know it. U16 mPort; @@ -293,7 +280,7 @@ class LLIOServerSocket : public LLIOPipe public: typedef LLSocket::ptr_t socket_t; typedef boost::shared_ptr factory_t; - LLIOServerSocket(apr_pool_t* pool, socket_t listener, factory_t reactor); + LLIOServerSocket(socket_t listener, factory_t reactor); virtual ~LLIOServerSocket(); /** @@ -325,7 +312,6 @@ protected: //@} protected: - apr_pool_t* mPool; socket_t mListenSocket; factory_t mReactor; bool mInitialized; @@ -359,8 +345,7 @@ public: */ LLIODataSocket( U16 suggested_port, - U16 start_discovery_port, - apr_pool_t* pool); + U16 start_discovery_port); virtual ~LLIODataSocket(); protected: diff --git a/indra/llmessage/llmail.cpp b/indra/llmessage/llmail.cpp index 08b31e9c7a..8a898ab1b0 100644 --- a/indra/llmessage/llmail.cpp +++ b/indra/llmessage/llmail.cpp @@ -50,6 +50,7 @@ #include "llstring.h" #include "lluuid.h" #include "net.h" +#include "llaprpool.h" // // constants @@ -57,7 +58,7 @@ const size_t LL_MAX_KNOWN_GOOD_MAIL_SIZE = 4096; static bool gMailEnabled = true; -static apr_pool_t* gMailPool; +static LLAPRPool gMailPool; static apr_sockaddr_t* gSockAddr; static apr_socket_t* gMailSocket; @@ -82,7 +83,7 @@ bool connect_smtp() gSockAddr->sa.sin.sin_family, SOCK_STREAM, APR_PROTO_TCP, - gMailPool); + gMailPool()); if(ll_apr_warn_status(status)) return false; status = apr_socket_connect(gMailSocket, gSockAddr); if(ll_apr_warn_status(status)) @@ -139,19 +140,19 @@ BOOL LLMail::send( } // static -void LLMail::init(const std::string& hostname, apr_pool_t* pool) +void LLMail::init(const std::string& hostname) { gMailSocket = NULL; - if(hostname.empty() || !pool) + if (hostname.empty()) { - gMailPool = NULL; gSockAddr = NULL; + gMailPool.destroy(); } else { - gMailPool = pool; + gMailPool.create(); - // collect all the information into a socaddr sturcture. the + // Collect all the information into a sockaddr structure. the // documentation is a bit unclear, but I either have to // specify APR_UNSPEC or not specify any flags. I am not sure // which option is better. @@ -161,7 +162,7 @@ void LLMail::init(const std::string& hostname, apr_pool_t* pool) APR_UNSPEC, 25, APR_IPV4_ADDR_OK, - gMailPool); + gMailPool()); ll_apr_warn_status(status); } } diff --git a/indra/llmessage/llmail.h b/indra/llmessage/llmail.h index 3791714363..0a5c532088 100644 --- a/indra/llmessage/llmail.h +++ b/indra/llmessage/llmail.h @@ -27,15 +27,13 @@ #ifndef LL_LLMAIL_H #define LL_LLMAIL_H -typedef struct apr_pool_t apr_pool_t; - #include "llsd.h" class LLMail { public: // if hostname is NULL, then the host is resolved as 'mail' - static void init(const std::string& hostname, apr_pool_t* pool); + static void init(const std::string& hostname); // Allow all email transmission to be disabled/enabled. static void enable(bool mail_enabled); diff --git a/indra/llmessage/llpumpio.cpp b/indra/llmessage/llpumpio.cpp index a8d2a0a224..89cfd66e1b 100644 --- a/indra/llmessage/llpumpio.cpp +++ b/indra/llmessage/llpumpio.cpp @@ -37,6 +37,7 @@ #include "llmemtype.h" #include "llstl.h" #include "llstat.h" +#include "llthread.h" // These should not be enabled in production, but they can be // intensely useful during development for finding certain kinds of @@ -162,14 +163,12 @@ struct ll_delete_apr_pollset_fd_client_data /** * LLPumpIO */ -LLPumpIO::LLPumpIO(apr_pool_t* pool) : +LLPumpIO::LLPumpIO(void) : mState(LLPumpIO::NORMAL), mRebuildPollset(false), mPollset(NULL), mPollsetClientID(0), mNextLock(0), - mPool(NULL), - mCurrentPool(NULL), mCurrentPoolReallocCount(0), mChainsMutex(NULL), mCallbackMutex(NULL), @@ -178,21 +177,24 @@ LLPumpIO::LLPumpIO(apr_pool_t* pool) : mCurrentChain = mRunningChains.end(); LLMemType m1(LLMemType::MTYPE_IO_PUMP); - initialize(pool); + initialize(); } LLPumpIO::~LLPumpIO() { LLMemType m1(LLMemType::MTYPE_IO_PUMP); - cleanup(); -} - -bool LLPumpIO::prime(apr_pool_t* pool) -{ - LLMemType m1(LLMemType::MTYPE_IO_PUMP); - cleanup(); - initialize(pool); - return ((pool == NULL) ? false : true); +#if LL_THREADS_APR + if (mChainsMutex) apr_thread_mutex_destroy(mChainsMutex); + if (mCallbackMutex) apr_thread_mutex_destroy(mCallbackMutex); +#endif + mChainsMutex = NULL; + mCallbackMutex = NULL; + if(mPollset) + { +// lldebugs << "cleaning up pollset" << llendl; + apr_pollset_destroy(mPollset); + mPollset = NULL; + } } bool LLPumpIO::addChain(const chain_t& chain, F32 timeout) @@ -352,8 +354,7 @@ bool LLPumpIO::setConditional(LLIOPipe* pipe, const apr_pollfd_t* poll) { // each fd needs a pool to work with, so if one was // not specified, use this pool. - // *FIX: Should it always be this pool? - value.second.p = mPool; + value.second.p = (*mCurrentChain).mDescriptorsPool->operator()(); } value.second.client_data = new S32(++mPollsetClientID); (*mCurrentChain).mDescriptors.push_back(value); @@ -825,39 +826,15 @@ void LLPumpIO::control(LLPumpIO::EControl op) } } -void LLPumpIO::initialize(apr_pool_t* pool) +void LLPumpIO::initialize(void) { LLMemType m1(LLMemType::MTYPE_IO_PUMP); - if(!pool) return; + mPool.create(); #if LL_THREADS_APR // SJB: Windows defaults to NESTED and OSX defaults to UNNESTED, so use UNNESTED explicitly. - apr_thread_mutex_create(&mChainsMutex, APR_THREAD_MUTEX_UNNESTED, pool); - apr_thread_mutex_create(&mCallbackMutex, APR_THREAD_MUTEX_UNNESTED, pool); -#endif - mPool = pool; -} - -void LLPumpIO::cleanup() -{ - LLMemType m1(LLMemType::MTYPE_IO_PUMP); -#if LL_THREADS_APR - if(mChainsMutex) apr_thread_mutex_destroy(mChainsMutex); - if(mCallbackMutex) apr_thread_mutex_destroy(mCallbackMutex); + apr_thread_mutex_create(&mChainsMutex, APR_THREAD_MUTEX_UNNESTED, mPool()); + apr_thread_mutex_create(&mCallbackMutex, APR_THREAD_MUTEX_UNNESTED, mPool()); #endif - mChainsMutex = NULL; - mCallbackMutex = NULL; - if(mPollset) - { -// lldebugs << "cleaning up pollset" << llendl; - apr_pollset_destroy(mPollset); - mPollset = NULL; - } - if(mCurrentPool) - { - apr_pool_destroy(mCurrentPool); - mCurrentPool = NULL; - } - mPool = NULL; } void LLPumpIO::rebuildPollset() @@ -885,21 +862,19 @@ void LLPumpIO::rebuildPollset() if(mCurrentPool && (0 == (++mCurrentPoolReallocCount % POLLSET_POOL_RECYCLE_COUNT))) { - apr_pool_destroy(mCurrentPool); - mCurrentPool = NULL; + mCurrentPool.destroy(); mCurrentPoolReallocCount = 0; } if(!mCurrentPool) { - apr_status_t status = apr_pool_create(&mCurrentPool, mPool); - (void)ll_apr_warn_status(status); + mCurrentPool.create(mPool); } // add all of the file descriptors run_it = mRunningChains.begin(); LLChainInfo::conditionals_t::iterator fd_it; LLChainInfo::conditionals_t::iterator fd_end; - apr_pollset_create(&mPollset, size, mCurrentPool, 0); + apr_pollset_create(&mPollset, size, mCurrentPool(), 0); for(; run_it != run_end; ++run_it) { fd_it = (*run_it).mDescriptors.begin(); @@ -1157,7 +1132,8 @@ bool LLPumpIO::handleChainError( LLPumpIO::LLChainInfo::LLChainInfo() : mInit(false), mLock(0), - mEOS(false) + mEOS(false), + mDescriptorsPool(new LLAPRPool(LLThread::tldata().mRootPool)) { LLMemType m1(LLMemType::MTYPE_IO_PUMP); mTimer.setTimerExpirySec(DEFAULT_CHAIN_EXPIRY_SECS); diff --git a/indra/llmessage/llpumpio.h b/indra/llmessage/llpumpio.h index 9303c9d7fc..75c35ae7ab 100644 --- a/indra/llmessage/llpumpio.h +++ b/indra/llmessage/llpumpio.h @@ -30,11 +30,12 @@ #define LL_LLPUMPIO_H #include +#include #if LL_LINUX // needed for PATH_MAX in APR. #include #endif -#include "apr_pools.h" +#include "llaprpool.h" #include "llbuffer.h" #include "llframetimer.h" #include "lliopipe.h" @@ -58,9 +59,8 @@ extern const F32 NEVER_CHAIN_EXPIRY_SECS; * pump() on a thread used for IO and call * respond() on a thread that is expected to do higher * level processing. You can call almost any other method from any - * thread - see notes for each method for details. In order for the - * threading abstraction to work, you need to call prime() - * with a valid apr pool. + * thread - see notes for each method for details. + * * A pump instance manages much of the state for the pipe, including * the list of pipes in the chain, the channel for each element in the * chain, the buffer, and if any pipe has marked the stream or process @@ -79,24 +79,13 @@ public: /** * @brief Constructor. */ - LLPumpIO(apr_pool_t* pool); + LLPumpIO(void); /** * @brief Destructor. */ ~LLPumpIO(); - /** - * @brief Prepare this pump for usage. - * - * If you fail to call this method prior to use, the pump will - * try to work, but will not come with any thread locking - * mechanisms. - * @param pool The apr pool to use. - * @return Returns true if the pump is primed. - */ - bool prime(apr_pool_t* pool); - /** * @brief Typedef for having a chain of pipes. */ @@ -368,6 +357,7 @@ protected: typedef std::pair pipe_conditional_t; typedef std::vector conditionals_t; conditionals_t mDescriptors; + boost::shared_ptr mDescriptorsPool; }; // All the running chains & info @@ -386,9 +376,9 @@ protected: callbacks_t mPendingCallbacks; callbacks_t mCallbacks; - // memory allocator for pollsets & mutexes. - apr_pool_t* mPool; - apr_pool_t* mCurrentPool; + // Memory pool for pollsets & mutexes. + LLAPRPool mPool; + LLAPRPool mCurrentPool; S32 mCurrentPoolReallocCount; #if LL_THREADS_APR @@ -400,8 +390,7 @@ protected: #endif protected: - void initialize(apr_pool_t* pool); - void cleanup(); + void initialize(); /** * @brief Given the internal state of the chains, rebuild the pollset diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index cb9d1c3731..83b6f7cf71 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -40,6 +40,7 @@ #include "llstring.h" #include "apr_env.h" #include "llapr.h" +#include "llscopedvolatileaprpool.h" static const U32 HTTP_STATUS_PIPE_ERROR = 499; /** @@ -210,27 +211,31 @@ void LLURLRequest::setCallback(LLURLRequestComplete* callback) // is called with use_proxy = FALSE void LLURLRequest::useProxy(bool use_proxy) { - static char *env_proxy; + static std::string env_proxy; - if (use_proxy && (env_proxy == NULL)) + if (use_proxy && env_proxy.empty()) { - apr_status_t status; - LLAPRPool pool; - status = apr_env_get(&env_proxy, "ALL_PROXY", pool.getAPRPool()); + char* env_proxy_str; + LLScopedVolatileAPRPool scoped_pool; + apr_status_t status = apr_env_get(&env_proxy_str, "ALL_PROXY", scoped_pool); if (status != APR_SUCCESS) { - status = apr_env_get(&env_proxy, "http_proxy", pool.getAPRPool()); + status = apr_env_get(&env_proxy_str, "http_proxy", scoped_pool); } if (status != APR_SUCCESS) { - use_proxy = FALSE; + use_proxy = false; } + else + { + // env_proxy_str is stored in the scoped_pool, so we have to make a copy. + env_proxy = env_proxy_str; + } } + lldebugs << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = \"" << env_proxy << "\"" << llendl; - lldebugs << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = " << (env_proxy ? env_proxy : "(null)") << llendl; - - if (env_proxy && use_proxy) + if (use_proxy) { mDetail->mCurlRequest->setoptString(CURLOPT_PROXY, env_proxy); } diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index 2f0d815be5..302cfc7ca2 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -97,8 +97,10 @@ std::string get_shared_secret(); class LLMessagePollInfo { public: + LLMessagePollInfo(void) : mPool(LLThread::tldata().mRootPool) { } apr_socket_t *mAPRSocketp; apr_pollfd_t mPollFD; + LLAPRPool mPool; }; namespace @@ -287,20 +289,13 @@ LLMessageSystem::LLMessageSystem(const std::string& filename, U32 port, } // LL_DEBUGS("Messaging") << << "*** port: " << mPort << llendl; - // - // Create the data structure that we can poll on - // - if (!gAPRPoolp) - { - LL_ERRS("Messaging") << "No APR pool before message system initialization!" << llendl; - ll_init_apr(); - } + mPollInfop = new LLMessagePollInfo; + apr_socket_t *aprSocketp = NULL; - apr_os_sock_put(&aprSocketp, (apr_os_sock_t*)&mSocket, gAPRPoolp); + apr_os_sock_put(&aprSocketp, (apr_os_sock_t*)&mSocket, mPollInfop->mPool()); - mPollInfop = new LLMessagePollInfo; mPollInfop->mAPRSocketp = aprSocketp; - mPollInfop->mPollFD.p = gAPRPoolp; + mPollInfop->mPollFD.p = mPollInfop->mPool(); mPollInfop->mPollFD.desc_type = APR_POLL_SOCKET; mPollInfop->mPollFD.reqevents = APR_POLLIN; mPollInfop->mPollFD.rtnevents = 0; diff --git a/indra/llmessage/tests/networkio.h b/indra/llmessage/tests/networkio.h index 2aff90ca1e..23e1c791f4 100644 --- a/indra/llmessage/tests/networkio.h +++ b/indra/llmessage/tests/networkio.h @@ -30,7 +30,6 @@ #define LL_NETWORKIO_H #include "llmemory.h" // LLSingleton -#include "llapr.h" #include "llares.h" #include "llpumpio.h" #include "llhttpclient.h" @@ -48,14 +47,8 @@ public: mServicePump(NULL), mDone(false) { - ll_init_apr(); - if (! gAPRPoolp) - { - throw std::runtime_error("Can't initialize APR"); - } - // Create IO Pump to use for HTTP Requests. - mServicePump = new LLPumpIO(gAPRPoolp); + mServicePump = new LLPumpIO; LLHTTPClient::setPump(*mServicePump); if (ll_init_ares() == NULL || !gAres->isInitialized()) { diff --git a/indra/llplugin/llplugininstance.cpp b/indra/llplugin/llplugininstance.cpp index c326961db4..9c9909a017 100644 --- a/indra/llplugin/llplugininstance.cpp +++ b/indra/llplugin/llplugininstance.cpp @@ -29,8 +29,7 @@ #include "linden_common.h" #include "llplugininstance.h" - -#include "llapr.h" +#include "llthread.h" // Needed for LLThread::tldata().mRootPool /** Virtual destructor. */ LLPluginInstanceMessageListener::~LLPluginInstanceMessageListener() @@ -48,6 +47,7 @@ const char *LLPluginInstance::PLUGIN_INIT_FUNCTION_NAME = "LLPluginInitEntryPoin * @param[in] owner Plugin instance. TODO:DOC is this a good description of what "owner" is? */ LLPluginInstance::LLPluginInstance(LLPluginInstanceMessageListener *owner) : + mDSOHandlePool(LLThread::tldata().mRootPool), mDSOHandle(NULL), mPluginUserData(NULL), mPluginSendMessageFunction(NULL) @@ -79,7 +79,7 @@ int LLPluginInstance::load(std::string &plugin_file) int result = apr_dso_load(&mDSOHandle, plugin_file.c_str(), - gAPRPoolp); + mDSOHandlePool()); if(result != APR_SUCCESS) { char buf[1024]; diff --git a/indra/llplugin/llplugininstance.h b/indra/llplugin/llplugininstance.h index 50531ca77f..1c3898e2e7 100644 --- a/indra/llplugin/llplugininstance.h +++ b/indra/llplugin/llplugininstance.h @@ -30,6 +30,7 @@ #include "llstring.h" #include "llapr.h" +#include "llaprpool.h" #include "apr_dso.h" @@ -88,6 +89,7 @@ private: static void staticReceiveMessage(const char *message_string, void **user_data); void receiveMessage(const char *message_string); + LLAPRPool mDSOHandlePool; apr_dso_handle_t *mDSOHandle; void *mPluginUserData; diff --git a/indra/llplugin/llpluginmessagepipe.cpp b/indra/llplugin/llpluginmessagepipe.cpp index 8d13e38ad5..dd47300b9c 100644 --- a/indra/llplugin/llpluginmessagepipe.cpp +++ b/indra/llplugin/llpluginmessagepipe.cpp @@ -92,8 +92,6 @@ void LLPluginMessagePipeOwner::killMessagePipe(void) } LLPluginMessagePipe::LLPluginMessagePipe(LLPluginMessagePipeOwner *owner, LLSocket::ptr_t socket): - mInputMutex(gAPRPoolp), - mOutputMutex(gAPRPoolp), mOwner(owner), mSocket(socket) { diff --git a/indra/llplugin/llpluginprocesschild.cpp b/indra/llplugin/llpluginprocesschild.cpp index 45a86476ac..2fa5dcdd01 100644 --- a/indra/llplugin/llpluginprocesschild.cpp +++ b/indra/llplugin/llpluginprocesschild.cpp @@ -40,7 +40,7 @@ LLPluginProcessChild::LLPluginProcessChild() { mState = STATE_UNINITIALIZED; mInstance = NULL; - mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP); + mSocket = LLSocket::create(LLSocket::STREAM_TCP); mSleepTime = PLUGIN_IDLE_SECONDS; // default: send idle messages at 100Hz mCPUElapsed = 0.0f; mBlockingRequest = false; diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index c002de0462..eaf7ec4bf3 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -33,6 +33,7 @@ #include "llpluginmessageclasses.h" #include "llapr.h" +#include "llscopedvolatileaprpool.h" //virtual LLPluginProcessParentOwner::~LLPluginProcessParentOwner() @@ -42,6 +43,7 @@ LLPluginProcessParentOwner::~LLPluginProcessParentOwner() bool LLPluginProcessParent::sUseReadThread = false; apr_pollset_t *LLPluginProcessParent::sPollSet = NULL; +LLAPRPool LLPluginProcessParent::sPollSetPool; bool LLPluginProcessParent::sPollsetNeedsRebuild = false; LLMutex *LLPluginProcessParent::sInstancesMutex; std::list LLPluginProcessParent::sInstances; @@ -52,7 +54,7 @@ class LLPluginProcessParentPollThread: public LLThread { public: LLPluginProcessParentPollThread() : - LLThread("LLPluginProcessParentPollThread", gAPRPoolp) + LLThread("LLPluginProcessParentPollThread") { } protected: @@ -77,12 +79,11 @@ protected: }; -LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner): - mIncomingQueueMutex(gAPRPoolp) +LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner* owner) { if(!sInstancesMutex) { - sInstancesMutex = new LLMutex(gAPRPoolp); + sInstancesMutex = new LLMutex; } mOwner = owner; @@ -95,6 +96,7 @@ LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner): mBlocked = false; mPolledInput = false; mPollFD.client_data = NULL; + mPollFDPool.create(); mPluginLaunchTimeout = 60.0f; mPluginLockupTimeout = 15.0f; @@ -169,44 +171,28 @@ void LLPluginProcessParent::init(const std::string &launcher_filename, const std bool LLPluginProcessParent::accept() { bool result = false; - apr_status_t status = APR_EGENERAL; - apr_socket_t *new_socket = NULL; - - status = apr_socket_accept( - &new_socket, - mListenSocket->getSocket(), - gAPRPoolp); + mSocket = LLSocket::create(status, mListenSocket); if(status == APR_SUCCESS) { // llinfos << "SUCCESS" << llendl; // Success. Create a message pipe on the new socket - - // we MUST create a new pool for the LLSocket, since it will take ownership of it and delete it in its destructor! - apr_pool_t* new_pool = NULL; - status = apr_pool_create(&new_pool, gAPRPoolp); - - mSocket = LLSocket::create(new_socket, new_pool); new LLPluginMessagePipe(this, mSocket); result = true; } - else if(APR_STATUS_IS_EAGAIN(status)) - { -// llinfos << "EAGAIN" << llendl; - - // No incoming connections. This is not an error. - status = APR_SUCCESS; - } else { -// llinfos << "Error:" << llendl; - ll_apr_warn_status(status); - - // Some other error. - errorState(); + mSocket.reset(); + // EAGAIN means "No incoming connections". This is not an error. + if (!APR_STATUS_IS_EAGAIN(status)) + { + // Some other error. + ll_apr_warn_status(status); + errorState(); + } } return result; @@ -272,10 +258,10 @@ void LLPluginProcessParent::idle(void) case STATE_INITIALIZED: { - apr_status_t status = APR_SUCCESS; + LLScopedVolatileAPRPool addr_pool; apr_sockaddr_t* addr = NULL; - mListenSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP); + mListenSocket = LLSocket::create(LLSocket::STREAM_TCP); mBoundPort = 0; // This code is based on parts of LLSocket::create() in lliosocket.cpp. @@ -286,7 +272,7 @@ void LLPluginProcessParent::idle(void) APR_INET, 0, // port 0 = ephemeral ("find me a port") 0, - gAPRPoolp); + addr_pool); if(ll_apr_warn_status(status)) { @@ -598,7 +584,7 @@ void LLPluginProcessParent::setMessagePipe(LLPluginMessagePipe *message_pipe) if(message_pipe != NULL) { // Set up the apr_pollfd_t - mPollFD.p = gAPRPoolp; + mPollFD.p = mPollFDPool(); mPollFD.desc_type = APR_POLL_SOCKET; mPollFD.reqevents = APR_POLLIN|APR_POLLERR|APR_POLLHUP; mPollFD.rtnevents = 0; @@ -645,6 +631,7 @@ void LLPluginProcessParent::updatePollset() // delete the existing pollset. apr_pollset_destroy(sPollSet); sPollSet = NULL; + sPollSetPool.destroy(); } std::list::iterator iter; @@ -667,12 +654,14 @@ void LLPluginProcessParent::updatePollset() { #ifdef APR_POLLSET_NOCOPY // The pollset doesn't exist yet. Create it now. - apr_status_t status = apr_pollset_create(&sPollSet, count, gAPRPoolp, APR_POLLSET_NOCOPY); + sPollSetPool.create(); + apr_status_t status = apr_pollset_create(&sPollSet, count, sPollSetPool(), APR_POLLSET_NOCOPY); if(status != APR_SUCCESS) { #endif // APR_POLLSET_NOCOPY LL_WARNS("PluginPoll") << "Couldn't create pollset. Falling back to non-pollset mode." << LL_ENDL; sPollSet = NULL; + sPollSetPool.destroy(); #ifdef APR_POLLSET_NOCOPY } else diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h index 32394809ef..6beeb64c7e 100644 --- a/indra/llplugin/llpluginprocessparent.h +++ b/indra/llplugin/llpluginprocessparent.h @@ -176,7 +176,9 @@ private: static bool sUseReadThread; apr_pollfd_t mPollFD; + LLAPRPool mPollFDPool; static apr_pollset_t *sPollSet; + static LLAPRPool sPollSetPool; static bool sPollsetNeedsRebuild; static LLMutex *sInstancesMutex; static std::list sInstances; diff --git a/indra/llplugin/llpluginsharedmemory.cpp b/indra/llplugin/llpluginsharedmemory.cpp index 63ff5085c6..e2ff645a9c 100644 --- a/indra/llplugin/llpluginsharedmemory.cpp +++ b/indra/llplugin/llpluginsharedmemory.cpp @@ -187,7 +187,8 @@ bool LLPluginSharedMemory::create(size_t size) mName += createName(); mSize = size; - apr_status_t status = apr_shm_create( &(mImpl->mAprSharedMemory), mSize, mName.c_str(), gAPRPoolp ); + mPool.create(); + apr_status_t status = apr_shm_create( &(mImpl->mAprSharedMemory), mSize, mName.c_str(), mPool()); if(ll_apr_warn_status(status)) { @@ -210,7 +211,7 @@ bool LLPluginSharedMemory::destroy(void) } mImpl->mAprSharedMemory = NULL; } - + mPool.destroy(); return true; } @@ -219,7 +220,8 @@ bool LLPluginSharedMemory::attach(const std::string &name, size_t size) mName = name; mSize = size; - apr_status_t status = apr_shm_attach( &(mImpl->mAprSharedMemory), mName.c_str(), gAPRPoolp ); + mPool.create(); + apr_status_t status = apr_shm_attach( &(mImpl->mAprSharedMemory), mName.c_str(), mPool() ); if(ll_apr_warn_status(status)) { @@ -241,6 +243,7 @@ bool LLPluginSharedMemory::detach(void) } mImpl->mAprSharedMemory = NULL; } + mPool.destroy(); return true; } diff --git a/indra/llplugin/llpluginsharedmemory.h b/indra/llplugin/llpluginsharedmemory.h index c6cd49cabb..84b7a58c32 100644 --- a/indra/llplugin/llpluginsharedmemory.h +++ b/indra/llplugin/llpluginsharedmemory.h @@ -28,6 +28,8 @@ #ifndef LL_LLPLUGINSHAREDMEMORY_H #define LL_LLPLUGINSHAREDMEMORY_H +#include "llaprpool.h" + class LLPluginSharedMemoryPlatformImpl; /** @@ -108,6 +110,7 @@ private: bool close(void); bool unlink(void); + LLAPRPool mPool; std::string mName; size_t mSize; void *mMappedAddress; diff --git a/indra/llplugin/slplugin/slplugin.cpp b/indra/llplugin/slplugin/slplugin.cpp index 516a58db88..ff86e4e135 100644 --- a/indra/llplugin/slplugin/slplugin.cpp +++ b/indra/llplugin/slplugin/slplugin.cpp @@ -176,8 +176,6 @@ int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdL int main(int argc, char **argv) #endif { - ll_init_apr(); - // Set up llerror logging { LLError::initForApplication("."); @@ -393,8 +391,6 @@ int main(int argc, char **argv) delete plugin; - ll_cleanup_apr(); - return 0; } diff --git a/indra/llvfs/lllfsthread.cpp b/indra/llvfs/lllfsthread.cpp index 3d3ed9f6d4..bf49b9668e 100644 --- a/indra/llvfs/lllfsthread.cpp +++ b/indra/llvfs/lllfsthread.cpp @@ -67,10 +67,6 @@ LLLFSThread::LLLFSThread(bool threaded) : LLQueuedThread("LFS", threaded), mPriorityCounter(PRIORITY_LOWBITS) { - if(!mLocalAPRFilePoolp) - { - mLocalAPRFilePoolp = new LLVolatileAPRPool() ; - } } LLLFSThread::~LLLFSThread() @@ -182,8 +178,7 @@ bool LLLFSThread::Request::processRequest() if (mOperation == FILE_READ) { llassert(mOffset >= 0); - LLAPRFile infile ; // auto-closes - infile.open(mFileName, LL_APR_RB, mThread->getLocalAPRFilePool()); + LLAPRFile infile(mFileName, LL_APR_RB); if (!infile.getFileHandle()) { llwarns << "LLLFS: Unable to read file: " << mFileName << llendl; @@ -205,8 +200,7 @@ bool LLLFSThread::Request::processRequest() apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY; if (mOffset < 0) flags |= APR_APPEND; - LLAPRFile outfile ; // auto-closes - outfile.open(mFileName, flags, mThread->getLocalAPRFilePool()); + LLAPRFile outfile(mFileName, flags); if (!outfile.getFileHandle()) { llwarns << "LLLFS: Unable to write file: " << mFileName << llendl; diff --git a/indra/llvfs/llvfs.cpp b/indra/llvfs/llvfs.cpp index c1fe21c57d..1a64623028 100644 --- a/indra/llvfs/llvfs.cpp +++ b/indra/llvfs/llvfs.cpp @@ -234,7 +234,7 @@ LLVFS::LLVFS(const std::string& index_filename, const std::string& data_filename mDataFP(NULL), mIndexFP(NULL) { - mDataMutex = new LLMutex(0); + mDataMutex = new LLMutex; S32 i; for (i = 0; i < VFSLOCK_COUNT; i++) @@ -2094,8 +2094,7 @@ void LLVFS::dumpFiles() std::string filename = id.asString() + extension; llinfos << " Writing " << filename << llendl; - LLAPRFile outfile; - outfile.open(filename, LL_APR_WB); + LLAPRFile outfile(filename, LL_APR_WB); outfile.write(&buffer[0], size); outfile.close(); diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h b/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h index 6bc272c009..77d6d19663 100644 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h +++ b/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h @@ -37,7 +37,6 @@ extern "C" { #include #include -#include "apr_pools.h" #include "apr_dso.h" } diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp index 2e4baaa9eb..93a10424dd 100644 --- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp +++ b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp @@ -28,16 +28,18 @@ #if LL_GSTREAMER010_ENABLED +#include "linden_common.h" + #include extern "C" { #include -#include "apr_pools.h" #include "apr_dso.h" } #include "llmediaimplgstreamertriviallogging.h" +#include "llaprpool.h" #define LL_GST_SYM(REQ, GSTSYM, RTN, ...) RTN (*ll##GSTSYM)(__VA_ARGS__) = NULL #include "llmediaimplgstreamer_syms_raw.inc" @@ -56,7 +58,7 @@ void ll_gst_debug_register_funcptr(GstDebugFuncPtr func, gchar* ptrname) } static bool sSymsGrabbed = false; -static apr_pool_t *sSymGSTDSOMemoryPool = NULL; +static LLAPRPool sSymGSTDSOMemoryPool; static apr_dso_handle_t *sSymGSTDSOHandleG = NULL; static apr_dso_handle_t *sSymGSTDSOHandleV = NULL; @@ -78,11 +80,11 @@ bool grab_gst_syms(std::string gst_dso_name, #define LL_GST_SYM(REQ, GSTSYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##GSTSYM, sSymGSTDSOHandle, #GSTSYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #GSTSYM); if (REQ) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #GSTSYM, (void*)ll##GSTSYM);}while(0) //attempt to load the shared libraries - apr_pool_create(&sSymGSTDSOMemoryPool, NULL); + sSymGSTDSOMemoryPool.create(); if ( APR_SUCCESS == (rv = apr_dso_load(&sSymGSTDSOHandle, gst_dso_name.c_str(), - sSymGSTDSOMemoryPool) )) + sSymGSTDSOMemoryPool()) )) { INFOMSG("Found DSO: %s", gst_dso_name.c_str()); #include "llmediaimplgstreamer_syms_raw.inc" @@ -96,7 +98,7 @@ bool grab_gst_syms(std::string gst_dso_name, if ( APR_SUCCESS == (rv = apr_dso_load(&sSymGSTDSOHandle, gst_dso_name_vid.c_str(), - sSymGSTDSOMemoryPool) )) + sSymGSTDSOMemoryPool()) )) { INFOMSG("Found DSO: %s", gst_dso_name_vid.c_str()); #include "llmediaimplgstreamer_syms_rawv.inc" @@ -150,8 +152,7 @@ void ungrab_gst_syms() if ( sSymGSTDSOMemoryPool ) { - apr_pool_destroy(sSymGSTDSOMemoryPool); - sSymGSTDSOMemoryPool = NULL; + sSymGSTDSOMemoryPool.destroy(); } // NULL-out all of the symbols we'd grabbed diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp index 91be3a89e9..94dfd80700 100644 --- a/indra/media_plugins/webkit/linux_volume_catcher.cpp +++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -65,7 +65,7 @@ extern "C" { #undef LL_PA_SYM static bool sSymsGrabbed = false; -static apr_pool_t *sSymPADSOMemoryPool = NULL; +static LLAPRPool sSymPADSOMemoryPool; static apr_dso_handle_t *sSymPADSOHandleG = NULL; bool grab_pa_syms(std::string pulse_dso_name) @@ -84,11 +84,11 @@ bool grab_pa_syms(std::string pulse_dso_name) #define LL_PA_SYM(REQUIRED, PASYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##PASYM, sSymPADSOHandle, #PASYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #PASYM); if (REQUIRED) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #PASYM, (void*)ll##PASYM);}while(0) //attempt to load the shared library - apr_pool_create(&sSymPADSOMemoryPool, NULL); + sSymPADSOMemoryPool.create(); if ( APR_SUCCESS == (rv = apr_dso_load(&sSymPADSOHandle, pulse_dso_name.c_str(), - sSymPADSOMemoryPool) )) + sSymPADSOMemoryPool()) )) { INFOMSG("Found DSO: %s", pulse_dso_name.c_str()); @@ -130,12 +130,8 @@ void ungrab_pa_syms() apr_dso_unload(sSymPADSOHandleG); sSymPADSOHandleG = NULL; } - - if ( sSymPADSOMemoryPool ) - { - apr_pool_destroy(sSymPADSOMemoryPool); - sSymPADSOMemoryPool = NULL; - } + + sSymPADSOMemoryPool.destroy(); // NULL-out all of the symbols we'd grabbed #define LL_PA_SYM(REQUIRED, PASYM, RTN, ...) do{ll##PASYM = NULL;}while(0) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index a23f809b71..1f76e2af40 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1026,7 +1026,7 @@ bool LLAppViewer::mainLoop() //------------------------------------------- // Create IO Pump to use for HTTP Requests. - gServicePump = new LLPumpIO(gAPRPoolp); + gServicePump = new LLPumpIO; LLHTTPClient::setPump(*gServicePump); LLCurl::setCAFile(gDirUtilp->getCAFile()); @@ -1387,16 +1387,16 @@ bool LLAppViewer::cleanup() } // *TODO - generalize this and move DSO wrangling to a helper class -brad - std::set::const_iterator i; - for(i = mPlugins.begin(); i != mPlugins.end(); ++i) + for(std::map >::iterator plugin = mPlugins.begin(); + plugin != mPlugins.end(); ++plugin) { int (*ll_plugin_stop_func)(void) = NULL; - apr_status_t rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll_plugin_stop_func, *i, "ll_plugin_stop"); + apr_status_t rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll_plugin_stop_func, plugin->first, "ll_plugin_stop"); ll_plugin_stop_func(); - rv = apr_dso_unload(*i); + rv = apr_dso_unload(plugin->first); } - mPlugins.clear(); + mPlugins.clear(); // Forget handles and destroy all memory pools. //flag all elements as needing to be destroyed immediately // to ensure shutdown order @@ -1828,7 +1828,7 @@ bool LLAppViewer::initThreads() if (LLFastTimer::sLog || LLFastTimer::sMetricLog) { - LLFastTimer::sLogLock = new LLMutex(NULL); + LLFastTimer::sLogLock = new LLMutex; mFastTimerLogThread = new LLFastTimerLogThread(LLFastTimer::sLogName); mFastTimerLogThread->start(); } @@ -2969,8 +2969,7 @@ void LLAppViewer::handleViewerCrash() else crash_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,ERROR_MARKER_FILE_NAME); llinfos << "Creating crash marker file " << crash_file_name << llendl; - LLAPRFile crash_file ; - crash_file.open(crash_file_name, LL_APR_W); + LLAPRFile crash_file(crash_file_name, LL_APR_W); if (crash_file.getFileHandle()) { LL_INFOS("MarkerFile") << "Created crash marker file " << crash_file_name << LL_ENDL; @@ -3034,11 +3033,10 @@ bool LLAppViewer::anotherInstanceRunning() LL_DEBUGS("MarkerFile") << "Checking marker file for lock..." << LL_ENDL; //Freeze case checks - if (LLAPRFile::isExist(marker_file, NULL, LL_APR_RB)) + if (LLAPRFile::isExist(marker_file, LL_APR_RB)) { // File exists, try opening with write permissions - LLAPRFile outfile ; - outfile.open(marker_file, LL_APR_WB); + LLAPRFile outfile(marker_file, LL_APR_WB); apr_file_t* fMarker = outfile.getFileHandle() ; if (!fMarker) { @@ -3077,25 +3075,25 @@ void LLAppViewer::initMarkerFile() std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME); std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME); - if (LLAPRFile::isExist(mMarkerFileName, NULL, LL_APR_RB) && !anotherInstanceRunning()) + if (LLAPRFile::isExist(mMarkerFileName, LL_APR_RB) && !anotherInstanceRunning()) { gLastExecEvent = LAST_EXEC_FROZE; LL_INFOS("MarkerFile") << "Exec marker found: program froze on previous execution" << LL_ENDL; } - if(LLAPRFile::isExist(logout_marker_file, NULL, LL_APR_RB)) + if(LLAPRFile::isExist(logout_marker_file, LL_APR_RB)) { gLastExecEvent = LAST_EXEC_LOGOUT_FROZE; LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL; LLAPRFile::remove(logout_marker_file); } - if(LLAPRFile::isExist(llerror_marker_file, NULL, LL_APR_RB)) + if(LLAPRFile::isExist(llerror_marker_file, LL_APR_RB)) { if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; else gLastExecEvent = LAST_EXEC_LLERROR_CRASH; LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL; LLAPRFile::remove(llerror_marker_file); } - if(LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB)) + if(LLAPRFile::isExist(error_marker_file, LL_APR_RB)) { if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; else gLastExecEvent = LAST_EXEC_OTHER_CRASH; @@ -3111,7 +3109,7 @@ void LLAppViewer::initMarkerFile() // Create the marker file for this execution & lock it apr_status_t s; - s = mMarkerFile.open(mMarkerFileName, LL_APR_W, TRUE); + s = mMarkerFile.open(mMarkerFileName, LL_APR_W, LLAPRFile::long_lived); if (s == APR_SUCCESS && mMarkerFile.getFileHandle()) { @@ -4327,8 +4325,7 @@ void LLAppViewer::sendLogoutRequest() gLogoutInProgress = TRUE; mLogoutMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LOGOUT_MARKER_FILE_NAME); - LLAPRFile outfile ; - outfile.open(mLogoutMarkerFileName, LL_APR_W); + LLAPRFile outfile(mLogoutMarkerFileName, LL_APR_W); mLogoutMarkerFile = outfile.getFileHandle() ; if (mLogoutMarkerFile) { @@ -4778,14 +4775,15 @@ void LLAppViewer::loadEventHostModule(S32 listen_port) } #endif // LL_WINDOWS - apr_dso_handle_t * eventhost_dso_handle = NULL; - apr_pool_t * eventhost_dso_memory_pool = NULL; + boost::shared_ptr eventhost_dso_memory_pool_ptr(new LLAPRPool); + LLAPRPool& eventhost_dso_memory_pool(*eventhost_dso_memory_pool_ptr); + apr_dso_handle_t* eventhost_dso_handle = NULL; //attempt to load the shared library - apr_pool_create(&eventhost_dso_memory_pool, NULL); + eventhost_dso_memory_pool.create(); apr_status_t rv = apr_dso_load(&eventhost_dso_handle, dso_path.c_str(), - eventhost_dso_memory_pool); + eventhost_dso_memory_pool()); llassert_always(! ll_apr_warn_status(rv, eventhost_dso_handle)); llassert_always(eventhost_dso_handle != NULL); @@ -4805,7 +4803,8 @@ void LLAppViewer::loadEventHostModule(S32 listen_port) llerrs << "problem loading eventhost plugin, status: " << status << llendl; } - mPlugins.insert(eventhost_dso_handle); + // Store the handle and link it to the pool that was used to allocate it. + mPlugins[eventhost_dso_handle] = eventhost_dso_memory_pool_ptr; } void LLAppViewer::launchUpdater() diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index a18e6cbb02..00b12d50ae 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -266,7 +266,7 @@ private: LLAllocator mAlloc; - std::set mPlugins; + std::map > mPlugins; U32 mAvailPhysicalMemInKB ; U32 mAvailVirtualMemInKB ; diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index 898cc1c0ba..d4c6131c80 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -110,6 +110,7 @@ int main( int argc, char **argv ) } delete viewer_app_ptr; viewer_app_ptr = NULL; + return 0; } diff --git a/indra/newview/llappviewerlinux_api_dbus.cpp b/indra/newview/llappviewerlinux_api_dbus.cpp index 32e7e0a83d..1ae469dfcf 100644 --- a/indra/newview/llappviewerlinux_api_dbus.cpp +++ b/indra/newview/llappviewerlinux_api_dbus.cpp @@ -27,11 +27,11 @@ #if LL_DBUS_ENABLED #include "linden_common.h" +#include "llaprpool.h" extern "C" { #include -#include "apr_pools.h" #include "apr_dso.h" } @@ -44,7 +44,7 @@ extern "C" { #undef LL_DBUS_SYM static bool sSymsGrabbed = false; -static apr_pool_t *sSymDBUSDSOMemoryPool = NULL; +static LLAPRPool sSymDBUSDSOMemoryPool; static apr_dso_handle_t *sSymDBUSDSOHandleG = NULL; bool grab_dbus_syms(std::string dbus_dso_name) @@ -63,11 +63,11 @@ bool grab_dbus_syms(std::string dbus_dso_name) #define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##DBUSSYM, sSymDBUSDSOHandle, #DBUSSYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #DBUSSYM); if (REQUIRED) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #DBUSSYM, (void*)ll##DBUSSYM);}while(0) //attempt to load the shared library - apr_pool_create(&sSymDBUSDSOMemoryPool, NULL); + sSymDBUSDSOMemoryPool.create(); if ( APR_SUCCESS == (rv = apr_dso_load(&sSymDBUSDSOHandle, dbus_dso_name.c_str(), - sSymDBUSDSOMemoryPool) )) + sSymDBUSDSOMemoryPool()) )) { INFOMSG("Found DSO: %s", dbus_dso_name.c_str()); @@ -109,11 +109,7 @@ void ungrab_dbus_syms() sSymDBUSDSOHandleG = NULL; } - if ( sSymDBUSDSOMemoryPool ) - { - apr_pool_destroy(sSymDBUSDSOMemoryPool); - sSymDBUSDSOMemoryPool = NULL; - } + sSymDBUSDSOMemoryPool.destroy(); // NULL-out all of the symbols we'd grabbed #define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) do{ll##DBUSSYM = NULL;}while(0) diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp index 1cd80986d8..13c8745eaf 100644 --- a/indra/newview/llappviewermacosx.cpp +++ b/indra/newview/llappviewermacosx.cpp @@ -113,6 +113,7 @@ int main( int argc, char **argv ) } delete viewer_app_ptr; viewer_app_ptr = NULL; + return 0; } diff --git a/indra/newview/llfloateranimpreview.cpp b/indra/newview/llfloateranimpreview.cpp index deebd69ec1..9b96332c10 100644 --- a/indra/newview/llfloateranimpreview.cpp +++ b/indra/newview/llfloateranimpreview.cpp @@ -223,8 +223,7 @@ BOOL LLFloaterAnimPreview::postBuild() // now load bvh file S32 file_size; - LLAPRFile infile ; - infile.open(mFilenameAndPath, LL_APR_RB, NULL, &file_size); + LLAPRFile infile(mFilenameAndPath, LL_APR_RB, &file_size); if (!infile.getFileHandle()) { diff --git a/indra/newview/llmainlooprepeater.cpp b/indra/newview/llmainlooprepeater.cpp index 5c020e6d98..d73048a28b 100644 --- a/indra/newview/llmainlooprepeater.cpp +++ b/indra/newview/llmainlooprepeater.cpp @@ -46,7 +46,7 @@ void LLMainLoopRepeater::start(void) { if(mQueue != 0) return; - mQueue = new LLThreadSafeQueue(gAPRPoolp, 1024); + mQueue = new LLThreadSafeQueue(1024); mMainLoopConnection = LLEventPumps::instance(). obtain("mainloop").listen(LLEventPump::inventName(), boost::bind(&LLMainLoopRepeater::onMainLoop, this, _1)); mRepeaterConnection = LLEventPumps::instance(). diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index f54214b95c..a47ea8581a 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -176,7 +176,7 @@ private: bool LLTextureCacheLocalFileWorker::doRead() { - S32 local_size = LLAPRFile::size(mFileName, mCache->getLocalAPRFilePool()); + S32 local_size = LLAPRFile::size(mFileName); if (local_size > 0 && mFileName.size() > 4) { @@ -250,7 +250,7 @@ bool LLTextureCacheLocalFileWorker::doRead() } mReadData = new U8[mDataSize]; - S32 bytes_read = LLAPRFile::readEx(mFileName, mReadData, mOffset, mDataSize, mCache->getLocalAPRFilePool()); + S32 bytes_read = LLAPRFile::readEx(mFileName, mReadData, mOffset, mDataSize); if (bytes_read != mDataSize) { @@ -331,7 +331,7 @@ bool LLTextureCacheRemoteWorker::doRead() // Is it a JPEG2000 file? { local_filename = filename + ".j2c"; - local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool()); + local_size = LLAPRFile::size(local_filename); if (local_size > 0) { mImageFormat = IMG_CODEC_J2C; @@ -341,7 +341,7 @@ bool LLTextureCacheRemoteWorker::doRead() if (local_size == 0) { local_filename = filename + ".jpg"; - local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool()); + local_size = LLAPRFile::size(local_filename); if (local_size > 0) { mImageFormat = IMG_CODEC_JPEG; @@ -352,7 +352,7 @@ bool LLTextureCacheRemoteWorker::doRead() if (local_size == 0) { local_filename = filename + ".tga"; - local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool()); + local_size = LLAPRFile::size(local_filename); if (local_size > 0) { mImageFormat = IMG_CODEC_TGA; @@ -378,8 +378,7 @@ bool LLTextureCacheRemoteWorker::doRead() } // Allocate read buffer mReadData = new U8[mDataSize]; - S32 bytes_read = LLAPRFile::readEx(local_filename, - mReadData, mOffset, mDataSize, mCache->getLocalAPRFilePool()); + S32 bytes_read = LLAPRFile::readEx(local_filename, mReadData, mOffset, mDataSize); if (bytes_read != mDataSize) { llwarns << "Error reading file from local cache: " << local_filename @@ -430,8 +429,7 @@ bool LLTextureCacheRemoteWorker::doRead() size = llmin(size, mDataSize); // Allocate the read buffer mReadData = new U8[size]; - S32 bytes_read = LLAPRFile::readEx(mCache->mHeaderDataFileName, - mReadData, offset, size, mCache->getLocalAPRFilePool()); + S32 bytes_read = LLAPRFile::readEx(mCache->mHeaderDataFileName, mReadData, offset, size); if (bytes_read != size) { llwarns << "LLTextureCacheWorker: " << mID @@ -457,7 +455,7 @@ bool LLTextureCacheRemoteWorker::doRead() if (!done && (mState == BODY)) { std::string filename = mCache->getTextureFileName(mID); - S32 filesize = LLAPRFile::size(filename, mCache->getLocalAPRFilePool()); + S32 filesize = LLAPRFile::size(filename); if (filesize && (filesize + TEXTURE_CACHE_ENTRY_SIZE) > mOffset) { @@ -499,8 +497,7 @@ bool LLTextureCacheRemoteWorker::doRead() // Read the data at last S32 bytes_read = LLAPRFile::readEx(filename, mReadData + data_offset, - file_offset, file_size, - mCache->getLocalAPRFilePool()); + file_offset, file_size); if (bytes_read != file_size) { llwarns << "LLTextureCacheWorker: " << mID @@ -601,13 +598,13 @@ bool LLTextureCacheRemoteWorker::doWrite() U8* padBuffer = new U8[TEXTURE_CACHE_ENTRY_SIZE]; memset(padBuffer, 0, TEXTURE_CACHE_ENTRY_SIZE); // Init with zeros memcpy(padBuffer, mWriteData, mDataSize); // Copy the write buffer - bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, padBuffer, offset, size, mCache->getLocalAPRFilePool()); + bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, padBuffer, offset, size); delete [] padBuffer; } else { // Write the header record (== first TEXTURE_CACHE_ENTRY_SIZE bytes of the raw file) in the header file - bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, mWriteData, offset, size, mCache->getLocalAPRFilePool()); + bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, mWriteData, offset, size); } if (bytes_written <= 0) @@ -642,8 +639,7 @@ bool LLTextureCacheRemoteWorker::doWrite() // llinfos << "Writing Body: " << filename << " Bytes: " << file_offset+file_size << llendl; S32 bytes_written = LLAPRFile::writeEx( filename, mWriteData + TEXTURE_CACHE_ENTRY_SIZE, - 0, file_size, - mCache->getLocalAPRFilePool()); + 0, file_size); if (bytes_written <= 0) { llwarns << "LLTextureCacheWorker: " << mID @@ -740,9 +736,6 @@ void LLTextureCacheWorker::endWork(S32 param, bool aborted) LLTextureCache::LLTextureCache(bool threaded) : LLWorkerThread("TextureCache", threaded), - mWorkersMutex(NULL), - mHeaderMutex(NULL), - mListMutex(NULL), mHeaderAPRFile(NULL), mReadOnly(TRUE), //do not allow to change the texture cache until setReadOnly() is called. mTexturesSizeTotal(0), @@ -846,7 +839,7 @@ BOOL LLTextureCache::isInLocal(const LLUUID& id) // Is it a JPEG2000 file? { local_filename = filename + ".j2c"; - local_size = LLAPRFile::size(local_filename, getLocalAPRFilePool()); + local_size = LLAPRFile::size(local_filename); if (local_size > 0) { return TRUE ; @@ -856,7 +849,7 @@ BOOL LLTextureCache::isInLocal(const LLUUID& id) // If not, is it a jpeg file? { local_filename = filename + ".jpg"; - local_size = LLAPRFile::size(local_filename, getLocalAPRFilePool()); + local_size = LLAPRFile::size(local_filename); if (local_size > 0) { return TRUE ; @@ -866,7 +859,7 @@ BOOL LLTextureCache::isInLocal(const LLUUID& id) // Hmm... What about a targa file? (used for UI texture mostly) { local_filename = filename + ".tga"; - local_size = LLAPRFile::size(local_filename, getLocalAPRFilePool()); + local_size = LLAPRFile::size(local_filename); if (local_size > 0) { return TRUE ; @@ -912,10 +905,10 @@ void LLTextureCache::purgeCache(ELLPath location) if(LLFile::isdir(mTexturesDirName)) { std::string file_name = gDirUtilp->getExpandedFilename(location, entries_filename); - LLAPRFile::remove(file_name, getLocalAPRFilePool()); + LLAPRFile::remove(file_name); file_name = gDirUtilp->getExpandedFilename(location, cache_filename); - LLAPRFile::remove(file_name, getLocalAPRFilePool()); + LLAPRFile::remove(file_name); purgeAllTextures(true); } @@ -991,7 +984,9 @@ LLAPRFile* LLTextureCache::openHeaderEntriesFile(bool readonly, S32 offset) { llassert_always(mHeaderAPRFile == NULL); apr_int32_t flags = readonly ? APR_READ|APR_BINARY : APR_READ|APR_WRITE|APR_BINARY; - mHeaderAPRFile = new LLAPRFile(mHeaderEntriesFileName, flags, getLocalAPRFilePool()); + // All code calling openHeaderEntriesFile, immediately calls closeHeaderEntriesFile, + // so this file is very short-lived. + mHeaderAPRFile = new LLAPRFile(mHeaderEntriesFileName, flags); if(offset > 0) { mHeaderAPRFile->seek(APR_SET, offset); @@ -1014,10 +1009,9 @@ void LLTextureCache::readEntriesHeader() { // mHeaderEntriesInfo initializes to default values so safe not to read it llassert_always(mHeaderAPRFile == NULL); - if (LLAPRFile::isExist(mHeaderEntriesFileName, getLocalAPRFilePool())) + if (LLAPRFile::isExist(mHeaderEntriesFileName)) { - LLAPRFile::readEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo), - getLocalAPRFilePool()); + LLAPRFile::readEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo)); } else //create an empty entries header. { @@ -1032,8 +1026,7 @@ void LLTextureCache::writeEntriesHeader() llassert_always(mHeaderAPRFile == NULL); if (!mReadOnly) { - LLAPRFile::writeEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo), - getLocalAPRFilePool()); + LLAPRFile::writeEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo)); } } @@ -1623,7 +1616,7 @@ void LLTextureCache::purgeTextures(bool validate) if (uuididx == validate_idx) { LL_DEBUGS("TextureCache") << "Validating: " << filename << "Size: " << entries[idx].mBodySize << LL_ENDL; - S32 bodysize = LLAPRFile::size(filename, getLocalAPRFilePool()); + S32 bodysize = LLAPRFile::size(filename); if (bodysize != entries[idx].mBodySize) { LL_WARNS("TextureCache") << "TEXTURE CACHE BODY HAS BAD SIZE: " << bodysize << " != " << entries[idx].mBodySize @@ -1858,7 +1851,7 @@ void LLTextureCache::removeCachedTexture(const LLUUID& id) mTexturesSizeMap.erase(id); } mHeaderIDMap.erase(id); - LLAPRFile::remove(getTextureFileName(id), getLocalAPRFilePool()); + LLAPRFile::remove(getTextureFileName(id)); } //called after mHeaderMutex is locked. @@ -1870,7 +1863,7 @@ void LLTextureCache::removeEntry(S32 idx, Entry& entry, std::string& filename) { if (entry.mBodySize == 0) // Always attempt to remove when mBodySize > 0. { - if (LLAPRFile::isExist(filename, getLocalAPRFilePool())) // Sanity check. Shouldn't exist when body size is 0. + if (LLAPRFile::isExist(filename)) // Sanity check. Shouldn't exist when body size is 0. { LL_WARNS("TextureCache") << "Entry has body size of zero but file " << filename << " exists. Deleting this file, too." << LL_ENDL; } @@ -1891,7 +1884,7 @@ void LLTextureCache::removeEntry(S32 idx, Entry& entry, std::string& filename) if (file_maybe_exists) { - LLAPRFile::remove(filename, getLocalAPRFilePool()); + LLAPRFile::remove(filename); } } diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h index 64e3a2658c..79f5ba5835 100644 --- a/indra/newview/lltexturecache.h +++ b/indra/newview/lltexturecache.h @@ -142,9 +142,6 @@ protected: std::string getTextureFileName(const LLUUID& id); void addCompleted(Responder* responder, bool success); -protected: - //void setFileAPRPool(apr_pool_t* pool) { mFileAPRPool = pool ; } - private: void setDirNames(ELLPath location); void readHeaderCache(); diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 18c3a3b87d..139b434aeb 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -674,7 +674,6 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher, mRetryAttempt(0), mActiveCount(0), mGetStatus(0), - mWorkMutex(NULL), mFirstPacket(0), mLastPacket(-1), mTotalPackets(0), @@ -1816,8 +1815,6 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image mDebugPause(FALSE), mPacketCount(0), mBadPacketCount(0), - mQueueMutex(getAPRPool()), - mNetworkQueueMutex(getAPRPool()), mTextureCache(cache), mImageDecodeThread(imagedecodethread), mTextureBandwidth(0), diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index fda291f3c1..6bee7556cd 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -736,8 +736,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, uuid = tid.makeAssetID(gAgent.getSecureSessionID()); // copy this file into the vfs for upload S32 file_size; - LLAPRFile infile ; - infile.open(filename, LL_APR_RB, NULL, &file_size); + LLAPRFile infile(filename, LL_APR_RB, &file_size); if (infile.getFileHandle()) { LLVFile file(gVFS, uuid, asset_type, LLVFile::WRITE); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index fd89044995..2cd9b09932 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -7190,8 +7190,7 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id ) // static void LLVOAvatar::dumpArchetypeXML( void* ) { - LLAPRFile outfile; - outfile.open(gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,"new archetype.xml"), LL_APR_WB ); + LLAPRFile outfile(gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER, "new archetype.xml"), LL_APR_WB); apr_file_t* file = outfile.getFileHandle() ; if (!file) { diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index a933500706..d25831b4f1 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -30,14 +30,14 @@ #include "llregionhandle.h" #include "llviewercontrol.h" -BOOL check_read(LLAPRFile* apr_file, void* src, S32 n_bytes) +static BOOL check_read(LLAPRFile& apr_file, void* src, S32 n_bytes) { - return apr_file->read(src, n_bytes) == n_bytes ; + return apr_file.read(src, n_bytes) == n_bytes ; } -BOOL check_write(LLAPRFile* apr_file, void* src, S32 n_bytes) +static BOOL check_write(LLAPRFile& apr_file, void* src, S32 n_bytes) { - return apr_file->write(src, n_bytes) == n_bytes ; + return apr_file.write(src, n_bytes) == n_bytes ; } @@ -70,7 +70,7 @@ LLVOCacheEntry::LLVOCacheEntry() mDP.assignBuffer(mBuffer, 0); } -LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file) +LLVOCacheEntry::LLVOCacheEntry(LLAPRFile& apr_file) { S32 size = -1; BOOL success; @@ -185,7 +185,7 @@ void LLVOCacheEntry::dump() const << llendl; } -BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const +BOOL LLVOCacheEntry::writeToFile(LLAPRFile& apr_file) const { BOOL success; success = check_write(apr_file, (void*)&mLocalID, sizeof(U32)); @@ -266,7 +266,6 @@ LLVOCache::LLVOCache(): mCacheSize(1) { mEnabled = gSavedSettings.getBOOL("ObjectCacheEnabled"); - mLocalAPRFilePoolp = new LLVolatileAPRPool() ; } LLVOCache::~LLVOCache() @@ -276,7 +275,6 @@ LLVOCache::~LLVOCache() writeCacheHeader(); clearCacheInMemory(); } - delete mLocalAPRFilePoolp; } void LLVOCache::setDirNames(ELLPath location) @@ -437,7 +435,7 @@ void LLVOCache::removeFromCache(HeaderEntryInfo* entry) std::string filename; getObjectCacheFilename(entry->mHandle, filename); - LLAPRFile::remove(filename, mLocalAPRFilePoolp); + LLAPRFile::remove(filename); entry->mTime = INVALID_TIME ; updateEntry(entry) ; //update the head file. } @@ -454,12 +452,12 @@ void LLVOCache::readCacheHeader() clearCacheInMemory(); bool success = true ; - if (LLAPRFile::isExist(mHeaderFileName, mLocalAPRFilePoolp)) + if (LLAPRFile::isExist(mHeaderFileName)) { - LLAPRFile apr_file(mHeaderFileName, APR_READ|APR_BINARY, mLocalAPRFilePoolp); + LLAPRFile apr_file(mHeaderFileName, APR_READ|APR_BINARY); //read the meta element - success = check_read(&apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)) ; + success = check_read(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)) ; if(success) { @@ -472,7 +470,7 @@ void LLVOCache::readCacheHeader() { entry = new HeaderEntryInfo() ; } - success = check_read(&apr_file, entry, sizeof(HeaderEntryInfo)); + success = check_read(apr_file, entry, sizeof(HeaderEntryInfo)); if(!success) //failed { @@ -541,17 +539,17 @@ void LLVOCache::writeCacheHeader() bool success = true ; { - LLAPRFile apr_file(mHeaderFileName, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); + LLAPRFile apr_file(mHeaderFileName, APR_CREATE|APR_WRITE|APR_BINARY); //write the meta element - success = check_write(&apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)) ; + success = check_write(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)) ; mNumEntries = 0 ; for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; success && iter != mHeaderEntryQueue.end(); ++iter) { (*iter)->mIndex = mNumEntries++ ; - success = check_write(&apr_file, (void*)*iter, sizeof(HeaderEntryInfo)); + success = check_write(apr_file, (void*)*iter, sizeof(HeaderEntryInfo)); } mNumEntries = mHeaderEntryQueue.size() ; @@ -562,7 +560,7 @@ void LLVOCache::writeCacheHeader() for(S32 i = mNumEntries ; success && i < MAX_NUM_OBJECT_ENTRIES ; i++) { //fill the cache with the default entry. - success = check_write(&apr_file, entry, sizeof(HeaderEntryInfo)) ; + success = check_write(apr_file, entry, sizeof(HeaderEntryInfo)) ; } delete entry ; @@ -579,10 +577,10 @@ void LLVOCache::writeCacheHeader() BOOL LLVOCache::updateEntry(const HeaderEntryInfo* entry) { - LLAPRFile apr_file(mHeaderFileName, APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); - apr_file.seek(APR_SET, entry->mIndex * sizeof(HeaderEntryInfo) + sizeof(HeaderMetaInfo)) ; + LLAPRFile apr_file(mHeaderFileName, APR_WRITE|APR_BINARY); + apr_file.seek(APR_SET, entry->mIndex * sizeof(HeaderEntryInfo) + sizeof(HeaderMetaInfo)); - return check_write(&apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ; + return check_write(apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ; } void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) @@ -605,10 +603,10 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca { std::string filename; getObjectCacheFilename(handle, filename); - LLAPRFile apr_file(filename, APR_READ|APR_BINARY, mLocalAPRFilePoolp); + LLAPRFile apr_file(filename, APR_READ|APR_BINARY); LLUUID cache_id ; - success = check_read(&apr_file, cache_id.mData, UUID_BYTES) ; + success = check_read(apr_file, cache_id.mData, UUID_BYTES) ; if(success) { @@ -621,11 +619,11 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca if(success) { S32 num_entries; - success = check_read(&apr_file, &num_entries, sizeof(S32)) ; + success = check_read(apr_file, &num_entries, sizeof(S32)) ; for (S32 i = 0; success && i < num_entries; i++) { - LLVOCacheEntry* entry = new LLVOCacheEntry(&apr_file); + LLVOCacheEntry* entry = new LLVOCacheEntry(apr_file); if (!entry->getLocalID()) { llwarns << "Aborting cache file load for " << filename << ", cache file corruption!" << llendl; @@ -724,19 +722,19 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: { std::string filename; getObjectCacheFilename(handle, filename); - LLAPRFile apr_file(filename, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); + LLAPRFile apr_file(filename, APR_CREATE|APR_WRITE|APR_BINARY); - success = check_write(&apr_file, (void*)id.mData, UUID_BYTES) ; + success = check_write(apr_file, (void*)id.mData, UUID_BYTES) ; if(success) { S32 num_entries = cache_entry_map.size() ; - success = check_write(&apr_file, &num_entries, sizeof(S32)); + success = check_write(apr_file, &num_entries, sizeof(S32)); for (LLVOCacheEntry::vocache_entry_map_t::const_iterator iter = cache_entry_map.begin(); success && iter != cache_entry_map.end(); ++iter) { - success = iter->second->writeToFile(&apr_file) ; + success = iter->second->writeToFile(apr_file) ; } } } diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h index 14e3b4c793..76456b9e98 100644 --- a/indra/newview/llvocache.h +++ b/indra/newview/llvocache.h @@ -41,7 +41,7 @@ class LLVOCacheEntry { public: LLVOCacheEntry(U32 local_id, U32 crc, LLDataPackerBinaryBuffer &dp); - LLVOCacheEntry(LLAPRFile* apr_file); + LLVOCacheEntry(LLAPRFile& apr_file); LLVOCacheEntry(); ~LLVOCacheEntry(); @@ -51,7 +51,7 @@ public: S32 getCRCChangeCount() const { return mCRCChangeCount; } void dump() const; - BOOL writeToFile(LLAPRFile* apr_file) const; + BOOL writeToFile(LLAPRFile& apr_file) const; void assignCRC(U32 crc, LLDataPackerBinaryBuffer &dp); LLDataPackerBinaryBuffer *getDP(U32 crc); void recordHit(); @@ -142,7 +142,6 @@ private: U32 mNumEntries; std::string mHeaderFileName ; std::string mObjectCacheDirName; - LLVolatileAPRPool* mLocalAPRFilePoolp ; header_entry_queue_t mHeaderEntryQueue; handle_entry_map_t mHandleEntryMap; diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 08e242af8e..828207ce1a 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -961,7 +961,7 @@ void LLVivoxVoiceClient::stateMachine() if(!mSocket) { - mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP); + mSocket = LLSocket::create(LLSocket::STREAM_TCP); } mConnected = mSocket->blockingConnect(mDaemonHost); diff --git a/indra/newview/llwatchdog.cpp b/indra/newview/llwatchdog.cpp index 1694126802..d982ca5020 100644 --- a/indra/newview/llwatchdog.cpp +++ b/indra/newview/llwatchdog.cpp @@ -178,8 +178,8 @@ void LLWatchdog::init(killer_event_callback func) mKillerCallback = func; if(!mSuspectsAccessMutex && !mTimer) { - mSuspectsAccessMutex = new LLMutex(NULL); - mTimer = new LLWatchdogTimerThread(); + mSuspectsAccessMutex = new LLMutex; + mTimer = new LLWatchdogTimerThread; mTimer->setSleepTime(WATCHDOG_SLEEP_TIME_USEC / 1000); mLastClockCount = LLTimer::getTotalTime(); diff --git a/indra/newview/tests/llworldmap_test.cpp b/indra/newview/tests/llworldmap_test.cpp index acc6e814bc..102294959a 100644 --- a/indra/newview/tests/llworldmap_test.cpp +++ b/indra/newview/tests/llworldmap_test.cpp @@ -27,7 +27,6 @@ // Dependencies #include "linden_common.h" -#include "llapr.h" #include "llsingleton.h" #include "lltrans.h" #include "lluistring.h" diff --git a/indra/test/lltemplatemessagebuilder_tut.cpp b/indra/test/lltemplatemessagebuilder_tut.cpp index 09beb53869..532f26ee60 100644 --- a/indra/test/lltemplatemessagebuilder_tut.cpp +++ b/indra/test/lltemplatemessagebuilder_tut.cpp @@ -29,7 +29,6 @@ #include "linden_common.h" #include "lltut.h" -#include "llapr.h" #include "llmessagetemplate.h" #include "llquaternion.h" #include "lltemplatemessagebuilder.h" @@ -53,7 +52,6 @@ namespace tut static bool init = false; if(! init) { - ll_init_apr(); const F32 circuit_heartbeat_interval=5; const F32 circuit_timeout=100; diff --git a/indra/test/message_tut.cpp b/indra/test/message_tut.cpp index d971b33475..9a6ccd4d68 100644 --- a/indra/test/message_tut.cpp +++ b/indra/test/message_tut.cpp @@ -29,7 +29,6 @@ #include "linden_common.h" #include "lltut.h" -#include "llapr.h" #include "llmessageconfig.h" #include "llsdserialize.h" #include "llversionserver.h" @@ -62,7 +61,6 @@ namespace tut static bool init = false; if(!init) { - ll_init_apr(); //init_prehash_data(); init = true; } diff --git a/indra/test/test.cpp b/indra/test/test.cpp index ffdb0cb976..45e8aef99a 100644 --- a/indra/test/test.cpp +++ b/indra/test/test.cpp @@ -37,8 +37,8 @@ #include "linden_common.h" #include "llerrorcontrol.h" #include "lltut.h" +#include "llaprpool.h" -#include "apr_pools.h" #include "apr_getopt.h" // the CTYPE_WORKAROUND is needed for linux dev stations that don't @@ -349,17 +349,12 @@ int main(int argc, char **argv) ctype_workaround(); #endif - apr_initialize(); - apr_pool_t* pool = NULL; - if(APR_SUCCESS != apr_pool_create(&pool, NULL)) - { - std::cerr << "Unable to initialize pool" << std::endl; - return 1; - } + LLAPRPool pool; + pool.create(); apr_getopt_t* os = NULL; - if(APR_SUCCESS != apr_getopt_init(&os, pool, argc, argv)) + if(APR_SUCCESS != apr_getopt_init(&os, pool(), argc, argv)) { - std::cerr << "Unable to pool" << std::endl; + std::cerr << "Unable to initialize the arguments for parsing by apr_getopt()." << std::endl; return 1; } @@ -477,8 +472,6 @@ int main(int argc, char **argv) s.close(); } - apr_terminate(); - int retval = (success ? 0 : 1); return retval; diff --git a/indra/test_apps/llplugintest/llmediaplugintest.cpp b/indra/test_apps/llplugintest/llmediaplugintest.cpp index 4a2272032b..fd46626ff1 100644 --- a/indra/test_apps/llplugintest/llmediaplugintest.cpp +++ b/indra/test_apps/llplugintest/llmediaplugintest.cpp @@ -27,7 +27,6 @@ #include "linden_common.h" #include "indra_constants.h" -#include "llapr.h" #include "llerrorcontrol.h" #include @@ -186,9 +185,6 @@ LLMediaPluginTest::LLMediaPluginTest( int app_window, int window_width, int wind std::cout << "Unable to read bookmarks from file: " << bookmarks_filename << std::endl; }; - // initialize linden lab APR module - ll_init_apr(); - // Set up llerror logging { LLError::initForApplication("."); diff --git a/indra/viewer_components/updater/llupdateinstaller.cpp b/indra/viewer_components/updater/llupdateinstaller.cpp index d450c068ad..6aa87d1be6 100644 --- a/indra/viewer_components/updater/llupdateinstaller.cpp +++ b/indra/viewer_components/updater/llupdateinstaller.cpp @@ -26,6 +26,7 @@ #include "linden_common.h" #include #include "llapr.h" +#include "llscopedvolatileaprpool.h" #include "llprocesslauncher.h" #include "llupdateinstaller.h" #include "lldir.h" @@ -45,7 +46,8 @@ namespace { { std::string scriptFile = gDirUtilp->getBaseFileName(path); std::string newPath = gDirUtilp->getExpandedFilename(LL_PATH_TEMP, scriptFile); - apr_status_t status = apr_file_copy(path.c_str(), newPath.c_str(), APR_FILE_SOURCE_PERMS, gAPRPoolp); + LLScopedVolatileAPRPool pool; + apr_status_t status = apr_file_copy(path.c_str(), newPath.c_str(), APR_FILE_SOURCE_PERMS, pool); if(status != APR_SUCCESS) throw RelocateError(); return newPath; -- cgit v1.2.3 From 1f0cc074823b299ed77b3d6e90e4e8f4ea60415f Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Wed, 23 Feb 2011 12:41:33 -0700 Subject: fix an assert error --- indra/llcommon/llmemory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index a931cd62ba..08fc1ddfe5 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -572,7 +572,7 @@ void LLPrivateMemoryPool::LLMemoryBlock::init(char* buffer, U32 buffer_size, U32 mSlotSize = slot_size ; mTotalSlots = buffer_size / mSlotSize ; - llassert_always(buffer_size / mSlotSize < 256) ; //max number is 256 + llassert_always(mTotalSlots <= 256) ; //max number is 256 mAllocatedSlots = 0 ; -- cgit v1.2.3 From d593f5c1d391d7406015e488d59c2b00beb7d8be Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Wed, 23 Feb 2011 14:35:53 -0700 Subject: fix a merge error --- indra/llcommon/llmemory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 08fc1ddfe5..1414ac7b9e 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -1271,7 +1271,7 @@ LLPrivateMemoryPool::LLPrivateMemoryPool(U32 max_size, bool threaded) : { if(threaded) { - mMutexp = new LLMutex(NULL) ; + mMutexp = new LLMutex ; } for(S32 i = 0 ; i < SUPER_ALLOCATION ; i++) -- cgit v1.2.3 From 108980f68c184341e83454bbd5e72a5803b33092 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Wed, 23 Feb 2011 17:53:08 -0700 Subject: add types to LLPrivateMemoryPool --- indra/llcommon/llmemory.cpp | 70 +++++++++++++++++++++++++++++---------------- indra/llcommon/llmemory.h | 23 +++++++++++---- indra/llimage/llimage.cpp | 4 +-- 3 files changed, 65 insertions(+), 32 deletions(-) (limited to 'indra') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 1414ac7b9e..062640f546 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -1263,13 +1263,16 @@ U16 LLPrivateMemoryPool::LLMemoryChunk::getPageLevel(U32 size) //-------------------------------------------------------------------- const U32 CHUNK_SIZE = 4 << 20 ; //4 MB const U32 LARGE_CHUNK_SIZE = 4 * CHUNK_SIZE ; //16 MB -LLPrivateMemoryPool::LLPrivateMemoryPool(U32 max_size, bool threaded) : - mMutexp(NULL), - mMaxPoolSize(max_size), +LLPrivateMemoryPool::LLPrivateMemoryPool(S32 type) : + mMutexp(NULL), mReservedPoolSize(0), - mHashFactor(1) + mHashFactor(1), + mType(type) { - if(threaded) + const U32 MAX_POOL_SIZE = 256 * 1024 * 1024 ; //256 MB + + mMaxPoolSize = MAX_POOL_SIZE ; + if(type == STATIC_THREADED || type == VOLATILE_THREADED) { mMutexp = new LLMutex ; } @@ -1735,22 +1738,35 @@ LLPrivateMemoryPoolManager* LLPrivateMemoryPoolManager::sInstance = NULL ; LLPrivateMemoryPoolManager::LLPrivateMemoryPoolManager() { + mPoolList.resize(LLPrivateMemoryPool::MAX_TYPES) ; + + for(S32 i = 0 ; i < LLPrivateMemoryPool::MAX_TYPES; i++) + { + mPoolList[i] = NULL ; + } } LLPrivateMemoryPoolManager::~LLPrivateMemoryPoolManager() { +#if 0 //all private pools should be released by their owners before reaching here. - llassert_always(mPoolList.empty()) ; + for(S32 i = 0 ; i < LLPrivateMemoryPool::MAX_TYPES; i++) + { + llassert_always(!mPoolList[i]) ; + } + mPoolList.clear() ; -#if 0 - if(!mPoolList.empty()) +#else + //forcefully release all memory + for(S32 i = 0 ; i < LLPrivateMemoryPool::MAX_TYPES; i++) { - for(std::set::iterator iter = mPoolList.begin(); iter != mPoolList.end(); ++iter) + if(mPoolList[i]) { - delete *iter; + delete mPoolList[i] ; + mPoolList[i] = NULL ; } - mPoolList.clear() ; } + mPoolList.clear() ; #endif } @@ -1774,18 +1790,23 @@ void LLPrivateMemoryPoolManager::destroyClass() } } -LLPrivateMemoryPool* LLPrivateMemoryPoolManager::newPool(U32 max_size, bool threaded) +LLPrivateMemoryPool* LLPrivateMemoryPoolManager::newPool(S32 type) { - LLPrivateMemoryPool* pool = new LLPrivateMemoryPool(max_size, threaded) ; - mPoolList.insert(pool) ; + if(!mPoolList[type]) + { + mPoolList[type] = new LLPrivateMemoryPool(type) ; + } - return pool ; + return mPoolList[type] ; } void LLPrivateMemoryPoolManager::deletePool(LLPrivateMemoryPool* pool) { - mPoolList.erase(pool) ; - delete pool; + if(pool->isEmpty()) + { + mPoolList[pool->getType()] = NULL ; + delete pool; + } } //debug @@ -1794,10 +1815,13 @@ void LLPrivateMemoryPoolManager::updateStatistics() mTotalReservedSize = 0 ; mTotalAllocatedSize = 0 ; - for(std::set::iterator iter = mPoolList.begin(); iter != mPoolList.end(); ++iter) + for(U32 i = 0; i < mPoolList.size(); i++) { - mTotalReservedSize += (*iter)->getTotalReservedSize() ; - mTotalAllocatedSize += (*iter)->getTotalAllocatedSize() ; + if(mPoolList[i]) + { + mTotalReservedSize += mPoolList[i]->getTotalReservedSize() ; + mTotalAllocatedSize += mPoolList[i]->getTotalAllocatedSize() ; + } } } @@ -1840,15 +1864,13 @@ void LLPrivateMemoryPoolTester::destroy() } } -void LLPrivateMemoryPoolTester::run(bool threaded) +void LLPrivateMemoryPoolTester::run(S32 type) { - const U32 max_pool_size = 1024 << 20 ; - if(sPool) { LLPrivateMemoryPoolManager::getInstance()->deletePool(sPool) ; } - sPool = LLPrivateMemoryPoolManager::getInstance()->newPool(max_pool_size, threaded) ; + sPool = LLPrivateMemoryPoolManager::getInstance()->newPool(type) ; //run the test correctnessTest() ; diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 4474df6f86..a5dbabec5a 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -231,7 +231,7 @@ public: } ; private: - LLPrivateMemoryPool(U32 max_size, bool threaded) ; + LLPrivateMemoryPool(S32 type) ; ~LLPrivateMemoryPool() ; public: @@ -241,7 +241,9 @@ public: void dump() ; U32 getTotalAllocatedSize() ; U32 getTotalReservedSize() {return mReservedPoolSize;} - + S32 getType() const {return mType; } + bool isEmpty() const {return !mNumOfChunks; } + private: void lock() ; void unlock() ; @@ -267,6 +269,15 @@ public: SUPER_ALLOCATION //allocation larger than 4MB. }; + enum + { + STATIC = 0 , //static pool(each alllocation stays for a long time) without threading support + VOLATILE, //Volatile pool(each allocation stays for a very short time) without threading support + STATIC_THREADED, //static pool with threading support + VOLATILE_THREADED, //volatile pool with threading support + MAX_TYPES + }; //pool types + private: LLMutex* mMutexp ; U32 mMaxPoolSize; @@ -276,6 +287,8 @@ private: std::vector mChunkHashList ; U16 mNumOfChunks ; U16 mHashFactor ; + + S32 mType ; }; class LL_COMMON_API LLPrivateMemoryPoolManager @@ -288,12 +301,12 @@ public: static LLPrivateMemoryPoolManager* getInstance() ; static void destroyClass() ; - LLPrivateMemoryPool* newPool(U32 max_size, bool threaded) ; + LLPrivateMemoryPool* newPool(S32 type) ; void deletePool(LLPrivateMemoryPool* pool) ; private: static LLPrivateMemoryPoolManager* sInstance ; - std::set mPoolList ; + std::vector mPoolList ; public: //debug and statistics info. @@ -316,7 +329,7 @@ public: static LLPrivateMemoryPoolTester* getInstance() ; static void destroy() ; - void run(bool threaded) ; + void run(S32 type) ; private: void correctnessTest() ; diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 706231307d..9298716022 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -106,11 +106,9 @@ LLImageBase::~LLImageBase() //static void LLImageBase::createPrivatePool() { - const U32 MAX_POOL_SIZE = 512 * 1024 * 1024 ; //512 MB - if(!sPrivatePoolp) { - sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(MAX_POOL_SIZE, true) ; + sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC_THREADED) ; } } -- cgit v1.2.3 From 844bf22d250833b000d306b9179580d6e032a632 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Wed, 23 Feb 2011 19:48:08 -0700 Subject: apply private pool to VBO --- indra/llrender/llrender.cpp | 19 ++++++++++++------- indra/llrender/llrender.h | 1 + indra/llrender/llvertexbuffer.cpp | 36 ++++++++++++++++++++++++------------ indra/llrender/llvertexbuffer.h | 5 ++++- indra/newview/llviewerwindow.cpp | 1 + 5 files changed, 42 insertions(+), 20 deletions(-) (limited to 'indra') diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 8eb160f4e7..efd0a11b88 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -754,13 +754,7 @@ LLRender::LLRender() mMode(LLRender::TRIANGLES), mCurrTextureUnitIndex(0), mMaxAnisotropy(0.f) -{ - mBuffer = new LLVertexBuffer(immediate_mask, 0); - mBuffer->allocateBuffer(4096, 0, TRUE); - mBuffer->getVertexStrider(mVerticesp); - mBuffer->getTexCoord0Strider(mTexcoordsp); - mBuffer->getColorStrider(mColorsp); - +{ mTexUnits.reserve(LL_NUM_TEXTURE_LAYERS); for (U32 i = 0; i < LL_NUM_TEXTURE_LAYERS; i++) { @@ -786,6 +780,17 @@ LLRender::~LLRender() shutdown(); } +void LLRender::init() +{ + llassert_always(mBuffer.isNull()) ; + + mBuffer = new LLVertexBuffer(immediate_mask, 0); + mBuffer->allocateBuffer(4096, 0, TRUE); + mBuffer->getVertexStrider(mVerticesp); + mBuffer->getTexCoord0Strider(mTexcoordsp); + mBuffer->getColorStrider(mColorsp); +} + void LLRender::shutdown() { for (U32 i = 0; i < mTexUnits.size(); i++) diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h index 2767aa64a8..611066a960 100644 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -271,6 +271,7 @@ public: LLRender(); ~LLRender(); + void init() ; void shutdown(); // Refreshes renderer state to the cached values diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 2417f88050..6b1fd78733 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -43,6 +43,7 @@ LLVBOPool LLVertexBuffer::sDynamicVBOPool; LLVBOPool LLVertexBuffer::sStreamIBOPool; LLVBOPool LLVertexBuffer::sDynamicIBOPool; +LLPrivateMemoryPool* LLVertexBuffer::sPrivatePoolp = NULL ; U32 LLVertexBuffer::sBindCount = 0; U32 LLVertexBuffer::sSetCount = 0; S32 LLVertexBuffer::sCount = 0; @@ -317,6 +318,11 @@ void LLVertexBuffer::initClass(bool use_vbo, bool no_vbo_mapping) LLGLNamePool::registerPool(&sDynamicIBOPool); LLGLNamePool::registerPool(&sStreamVBOPool); LLGLNamePool::registerPool(&sStreamIBOPool); + + if(!sPrivatePoolp) + { + sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC) ; + } } //static @@ -345,6 +351,12 @@ void LLVertexBuffer::cleanupClass() LLMemType mt2(LLMemType::MTYPE_VERTEX_CLEANUP_CLASS); unbind(); clientCopy(); // deletes GL buffers + + if(sPrivatePoolp) + { + LLPrivateMemoryPoolManager::getInstance()->deletePool(sPrivatePoolp) ; + sPrivatePoolp = NULL ; + } } void LLVertexBuffer::clientCopy(F64 max_time) @@ -532,7 +544,7 @@ void LLVertexBuffer::createGLBuffer() { static int gl_buffer_idx = 0; mGLBuffer = ++gl_buffer_idx; - mMappedData = new U8[size]; + mMappedData = (U8*)sPrivatePoolp->allocate(size); memset(mMappedData, 0, size); } } @@ -562,7 +574,7 @@ void LLVertexBuffer::createGLIndices() } else { - mMappedIndexData = new U8[size]; + mMappedIndexData = (U8*)sPrivatePoolp->allocate(size); memset(mMappedIndexData, 0, size); static int gl_buffer_idx = 0; mGLIndices = ++gl_buffer_idx; @@ -586,7 +598,7 @@ void LLVertexBuffer::destroyGLBuffer() } else { - delete [] mMappedData; + sPrivatePoolp->free(mMappedData) ; mMappedData = NULL; mEmpty = TRUE; } @@ -615,7 +627,7 @@ void LLVertexBuffer::destroyGLIndices() } else { - delete [] mMappedIndexData; + sPrivatePoolp->free(mMappedIndexData) ; mMappedIndexData = NULL; mEmpty = TRUE; } @@ -747,7 +759,7 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) if (!useVBOs()) { U8* old = mMappedData; - mMappedData = new U8[newsize]; + mMappedData = (U8*)sPrivatePoolp->allocate(newsize); if (old) { memcpy(mMappedData, old, llmin(newsize, oldsize)); @@ -756,7 +768,7 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) memset(mMappedData+oldsize, 0, newsize-oldsize); } - delete [] old; + sPrivatePoolp->free(old); } else { @@ -784,7 +796,7 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) { //delete old buffer, keep GL buffer for now U8* old = mMappedIndexData; - mMappedIndexData = new U8[new_index_size]; + mMappedIndexData = (U8*)sPrivatePoolp->allocate(new_index_size); if (old) { @@ -793,7 +805,7 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) { memset(mMappedIndexData+old_index_size, 0, new_index_size - old_index_size); } - delete [] old; + sPrivatePoolp->free(old); } else { @@ -840,8 +852,8 @@ void LLVertexBuffer::freeClientBuffer() { if(useVBOs() && sDisableVBOMapping && (mMappedData || mMappedIndexData)) { - delete[] mMappedData ; - delete[] mMappedIndexData ; + sPrivatePoolp->free(mMappedData) ; + sPrivatePoolp->free(mMappedIndexData) ; mMappedData = NULL ; mMappedIndexData = NULL ; } @@ -852,7 +864,7 @@ void LLVertexBuffer::allocateClientVertexBuffer() if(!mMappedData) { U32 size = getSize() ; - mMappedData = new U8[size]; + mMappedData = (U8*)sPrivatePoolp->allocate(size); memset(mMappedData, 0, size); } } @@ -862,7 +874,7 @@ void LLVertexBuffer::allocateClientIndexBuffer() if(!mMappedIndexData) { U32 size = getIndicesSize(); - mMappedIndexData = new U8[size]; + mMappedIndexData = (U8*)sPrivatePoolp->allocate(size); memset(mMappedIndexData, 0, size); } } diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index c51ce7ac4e..a4b0d5558e 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -69,7 +69,7 @@ protected: //============================================================================ // base class - +class LLPrivateMemoryPool ; class LLVertexBuffer : public LLRefCount { public: @@ -238,6 +238,9 @@ protected: std::vector mDirtyRegions; //vector of dirty regions to rebuild +private: + static LLPrivateMemoryPool* sPrivatePoolp ; + public: static S32 sCount; static S32 sGLCount; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index dfdf429455..8ce367efd2 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1489,6 +1489,7 @@ LLViewerWindow::LLViewerWindow( gSavedSettings.setBOOL("RenderVBOEnable", FALSE); } LLVertexBuffer::initClass(gSavedSettings.getBOOL("RenderVBOEnable"), gSavedSettings.getBOOL("RenderVBOMappingDisable")); + gGL.init() ; if (LLFeatureManager::getInstance()->isSafe() || (gSavedSettings.getS32("LastFeatureVersion") != LLFeatureManager::getInstance()->getVersion()) -- cgit v1.2.3 From ae65347e3391be56b8919349a269e0abe52cf656 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Wed, 23 Feb 2011 20:11:01 -0700 Subject: fix an exit crash. --- indra/llrender/llrender.cpp | 1 + indra/newview/llviewerwindow.cpp | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'indra') diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index efd0a11b88..fd899d7f87 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -800,6 +800,7 @@ void LLRender::shutdown() mTexUnits.clear(); delete mDummyTexUnit; mDummyTexUnit = NULL; + mBuffer = NULL ; } void LLRender::refreshState(void) diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 8ce367efd2..b8f70e1705 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1877,9 +1877,7 @@ void LLViewerWindow::shutdownGL() llinfos << "All textures and llimagegl images are destroyed!" << llendl ; llinfos << "Cleaning up select manager" << llendl; - LLSelectMgr::getInstance()->cleanup(); - - LLVertexBuffer::cleanupClass(); + LLSelectMgr::getInstance()->cleanup(); llinfos << "Stopping GL during shutdown" << llendl; if (!gNoRender) @@ -1889,6 +1887,10 @@ void LLViewerWindow::shutdownGL() } gGL.shutdown(); + + LLVertexBuffer::cleanupClass(); + + llinfos << "LLVertexBuffer cleaned." << llendl ; } // shutdownViews() and shutdownGL() need to be called first -- cgit v1.2.3 From fc106df53085f549acdbb2f8149ca75e400532fa Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Thu, 24 Feb 2011 19:47:55 -0700 Subject: fix the compiling error: "free" is defined and in use globally. --- indra/llcommon/llmemory.cpp | 20 ++++++++++---------- indra/llcommon/llmemory.h | 12 +++++++----- indra/llimage/llimage.cpp | 2 +- indra/llrender/llvertexbuffer.cpp | 12 ++++++------ 4 files changed, 24 insertions(+), 22 deletions(-) (limited to 'indra') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 062640f546..49e2cd9ac4 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -572,7 +572,7 @@ void LLPrivateMemoryPool::LLMemoryBlock::init(char* buffer, U32 buffer_size, U32 mSlotSize = slot_size ; mTotalSlots = buffer_size / mSlotSize ; - llassert_always(mTotalSlots <= 256) ; //max number is 256 + llassert_always(buffer_size / mSlotSize <= 256) ; //max number is 256 mAllocatedSlots = 0 ; @@ -669,7 +669,7 @@ char* LLPrivateMemoryPool::LLMemoryBlock::allocate() } //free a slot -void LLPrivateMemoryPool::LLMemoryBlock::free(void* addr) +void LLPrivateMemoryPool::LLMemoryBlock::freeMem(void* addr) { //bit index U32 idx = ((U32)addr - (U32)mBuffer - mDummySize * sizeof(U32)) / mSlotSize ; @@ -850,14 +850,14 @@ char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) return p ; } -void LLPrivateMemoryPool::LLMemoryChunk::free(void* addr) +void LLPrivateMemoryPool::LLMemoryChunk::freeMem(void* addr) { U32 blk_idx = getPageIndex((U32)addr) ; LLMemoryBlock* blk = (LLMemoryBlock*)(mMetaBuffer + blk_idx * sizeof(LLMemoryBlock)) ; blk = blk->mSelf ; bool was_full = blk->isFull() ; - blk->free(addr) ; + blk->freeMem(addr) ; mAlloatedSize -= blk->getSlotSize() ; if(blk->empty()) @@ -1349,7 +1349,7 @@ char* LLPrivateMemoryPool::allocate(U32 size) return p ; } -void LLPrivateMemoryPool::free(void* addr) +void LLPrivateMemoryPool::freeMem(void* addr) { if(!addr) { @@ -1366,7 +1366,7 @@ void LLPrivateMemoryPool::free(void* addr) } else { - chunk->free(addr) ; + chunk->freeMem(addr) ; if(chunk->empty()) { @@ -1929,7 +1929,7 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 if(p[i][k]) { llassert_always(*(U32*)p[i][k] == i && *((U32*)p[i][k] + 1) == k) ; - sPool->free(p[i][k]) ; + sPool->freeMem(p[i][k]) ; total_allocated_size -= min_size + k * stride ; p[i][k] = NULL ; } @@ -1950,7 +1950,7 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 if(p[i][j]) { llassert_always(*(U32*)p[i][j] == i && *((U32*)p[i][j] + 1) == j) ; - sPool->free(p[i][j]) ; + sPool->freeMem(p[i][j]) ; total_allocated_size -= min_size + j * stride ; p[i][j] = NULL ; } @@ -1984,7 +1984,7 @@ void LLPrivateMemoryPoolTester::testAndTime(U32 size, U32 times) //de-allocation for(U32 i = 0 ; i < times; i++) { - sPool->free(p[i]) ; + sPool->freeMem(p[i]) ; p[i] = NULL ; } llinfos << "time spent using customized memory pool: " << timer.getElapsedTimeF32() << llendl ; @@ -2019,7 +2019,7 @@ void LLPrivateMemoryPoolTester::correctnessTest() //edge case char* p = sPool->allocate(0) ; - sPool->free(p) ; + sPool->freeMem(p) ; //small sized // [8 bytes, 2KB), each asks for 256 allocations and deallocations diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index a5dbabec5a..001ff9c123 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -132,7 +132,7 @@ public: void setBuffer(char* buffer, U32 buffer_size) ; char* allocate() ; - void free(void* addr) ; + void freeMem(void* addr) ; bool empty() {return !mAllocatedSlots;} bool isFull() {return mAllocatedSlots == mTotalSlots;} @@ -180,7 +180,7 @@ public: bool empty() ; char* allocate(U32 size) ; - void free(void* addr) ; + void freeMem(void* addr) ; const char* getBuffer() const {return mBuffer;} U32 getBufferSize() const {return mBufferSize;} @@ -236,7 +236,7 @@ private: public: char *allocate(U32 size) ; - void free(void* addr) ; + void freeMem(void* addr) ; void dump() ; U32 getTotalAllocatedSize() ; @@ -339,6 +339,7 @@ private: void test(U32 min_size, U32 max_size, U32 stride, U32 times, bool random_deletion, bool output_statistics) ; void testAndTime(U32 size, U32 times) ; +#if 0 public: void* operator new(size_t size) { @@ -346,7 +347,7 @@ public: } void operator delete(void* addr) { - sPool->free(addr) ; + sPool->freeMem(addr) ; } void* operator new[](size_t size) { @@ -354,8 +355,9 @@ public: } void operator delete[](void* addr) { - sPool->free(addr) ; + sPool->freeMem(addr) ; } +#endif private: static LLPrivateMemoryPoolTester* sInstance; diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 9298716022..eefcf0a9fb 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -140,7 +140,7 @@ void LLImageBase::deleteMemory(void* p) { if(sPrivatePoolp) { - sPrivatePoolp->free(p) ; + sPrivatePoolp->freeMem(p) ; } else { diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 6b1fd78733..fd2a04373b 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -598,7 +598,7 @@ void LLVertexBuffer::destroyGLBuffer() } else { - sPrivatePoolp->free(mMappedData) ; + sPrivatePoolp->freeMem(mMappedData) ; mMappedData = NULL; mEmpty = TRUE; } @@ -627,7 +627,7 @@ void LLVertexBuffer::destroyGLIndices() } else { - sPrivatePoolp->free(mMappedIndexData) ; + sPrivatePoolp->freeMem(mMappedIndexData) ; mMappedIndexData = NULL; mEmpty = TRUE; } @@ -768,7 +768,7 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) memset(mMappedData+oldsize, 0, newsize-oldsize); } - sPrivatePoolp->free(old); + sPrivatePoolp->freeMem(old); } else { @@ -805,7 +805,7 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) { memset(mMappedIndexData+old_index_size, 0, new_index_size - old_index_size); } - sPrivatePoolp->free(old); + sPrivatePoolp->freeMem(old); } else { @@ -852,8 +852,8 @@ void LLVertexBuffer::freeClientBuffer() { if(useVBOs() && sDisableVBOMapping && (mMappedData || mMappedIndexData)) { - sPrivatePoolp->free(mMappedData) ; - sPrivatePoolp->free(mMappedIndexData) ; + sPrivatePoolp->freeMem(mMappedData) ; + sPrivatePoolp->freeMem(mMappedIndexData) ; mMappedData = NULL ; mMappedIndexData = NULL ; } -- cgit v1.2.3 From a40ee94cd6768445fdaeffd18bf4392e1398d42b Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Mon, 4 Apr 2011 10:00:29 -0600 Subject: fix the bug for mac and linux of continuously adjusting memory. --- indra/llcommon/llmemory.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 49e2cd9ac4..62db7e3385 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -140,10 +140,10 @@ void* LLMemory::tryToAlloc(void* address, U32 size) llerrs << "error happens when free some memory reservation." << llendl ; } } -#else -#endif - return address ; +#else + return 0x01 ; //skip checking +#endif } //static -- cgit v1.2.3 From 17854c4e8702febaa8fe4adfbc678f9abaaa52c7 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Mon, 4 Apr 2011 14:40:07 -0600 Subject: fix an issue on mac and linux, also fix an assertion. --- indra/llcommon/llmemory.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 62db7e3385..dfc00b5e0a 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -142,7 +142,7 @@ void* LLMemory::tryToAlloc(void* address, U32 size) } return address ; #else - return 0x01 ; //skip checking + return (void*)0x01 ; //skip checking #endif } @@ -1079,6 +1079,8 @@ LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::createNe if(new_free_blk_size > 0) //blk still has free space { LLMemoryBlock* next_blk = blk + (buffer_size / mMinBlockSize) ; + next_blk->mPrev = NULL ; + next_blk->mNext = NULL ; next_blk->setBuffer(blk->getBuffer() + buffer_size, new_free_blk_size) ; addToFreeSpace(next_blk) ; } -- cgit v1.2.3 From 1213e5d3548a111a39b6556c6178fc4bc655d367 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Mon, 4 Apr 2011 14:40:32 -0600 Subject: fix a crash inherited from viewer-development --- indra/llmessage/llavatarnamecache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index 767001b633..f6a1aca71b 100644 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -561,7 +561,7 @@ void LLAvatarNameCache::eraseUnrefreshed() const LLAvatarName& av_name = cur->second; if (av_name.mExpires < max_unrefreshed) { - const LLUUID& agent_id = it->first; + const LLUUID& agent_id = cur->first; LL_DEBUGS("AvNameCache") << agent_id << " user '" << av_name.mUsername << "' " << "expired " << now - av_name.mExpires << " secs ago" -- cgit v1.2.3 From b594d3b04d3095f15750436910debdd5a602a872 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Tue, 10 May 2011 21:02:20 -0600 Subject: add debug mode to track the memory allocation/deallocation. --- indra/llcommon/llmemory.cpp | 117 ++++++++++++++++++++++++++++++++++---- indra/llcommon/llmemory.h | 24 +++++++- indra/llimage/llimage.cpp | 36 ++---------- indra/llimage/llimage.h | 3 +- indra/llimage/llimagedxt.cpp | 2 +- indra/llimage/llimagej2c.cpp | 4 +- indra/llrender/llvertexbuffer.cpp | 24 ++++---- indra/newview/lltexturecache.cpp | 30 +++++----- indra/newview/lltexturefetch.cpp | 14 ++--- 9 files changed, 173 insertions(+), 81 deletions(-) (limited to 'indra') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index dfc00b5e0a..8f65107e47 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -57,6 +57,10 @@ U32 LLMemory::sAllocatedPageSizeInKB = 0 ; U32 LLMemory::sMaxHeapSizeInKB = U32_MAX ; BOOL LLMemory::sEnableMemoryFailurePrevention = FALSE; +#if __DEBUG_PRIVATE_MEM__ +LLPrivateMemoryPoolManager::mem_allocation_info_t LLPrivateMemoryPoolManager::sMemAllocationTracker; +#endif + //static void LLMemory::initClass() { @@ -1431,8 +1435,14 @@ S32 LLPrivateMemoryPool::getChunkIndex(U32 size) void LLPrivateMemoryPool::destroyPool() { lock() ; - if(mNumOfChunks > 0) + +#if 0 + if(mNumOfChunks > 0) { + //Warn: + //should crash here because there is memory leaking if reach here. + // + for(U32 i = 0 ; i < mHashFactor; i++) { while(mChunkHashList[i]) @@ -1441,11 +1451,19 @@ void LLPrivateMemoryPool::destroyPool() } } } - mChunkHashList.clear() ; - mHashFactor = 1 ; + llassert_always(mNumOfChunks == 0) ; llassert_always(mReservedPoolSize == 0) ; +#endif + + if(mNumOfChunks > 0) + { + llwarns << "There is some memory not freed when destroy the memory pool!" << llendl ; + } + mNumOfChunks = 0 ; + mChunkHashList.clear() ; + mHashFactor = 1 ; for(S32 i = 0 ; i < SUPER_ALLOCATION ; i++) { mChunkList[i] = NULL ; @@ -1750,6 +1768,21 @@ LLPrivateMemoryPoolManager::LLPrivateMemoryPoolManager() LLPrivateMemoryPoolManager::~LLPrivateMemoryPoolManager() { + +#if __DEBUG_PRIVATE_MEM__ + if(!sMemAllocationTracker.empty()) + { + llwarns << "there is potential memory leaking here. The list of not freed memory blocks are from: " <second << llendl ; + } + sMemAllocationTracker.clear() ; + } +#endif + #if 0 //all private pools should be released by their owners before reaching here. for(S32 i = 0 ; i < LLPrivateMemoryPool::MAX_TYPES; i++) @@ -1827,6 +1860,70 @@ void LLPrivateMemoryPoolManager::updateStatistics() } } +#if __DEBUG_PRIVATE_MEM__ +//static +char* LLPrivateMemoryPoolManager::allocate(LLPrivateMemoryPool* poolp, U32 size, const char* function, const int line) +{ + char* p ; + + if(!poolp) + { + p = new char[size] ; + } + else + { + p = poolp->allocate(size) ; + } + + if(p) + { + char num[16] ; + sprintf(num, " line: %d ", line) ; + std::string str(function) ; + str += num; + + sMemAllocationTracker[p] = str ; + } + + return p ; +} +#else +//static +char* LLPrivateMemoryPoolManager::allocate(LLPrivateMemoryPool* poolp, U32 size) +{ + if(!poolp) + { + return new char[size] ; + } + else + { + return poolp->allocate(size) ; + } +} +#endif + +//static +void LLPrivateMemoryPoolManager::freeMem(LLPrivateMemoryPool* poolp, void* addr) +{ + if(!addr) + { + return ; + } + +#if __DEBUG_PRIVATE_MEM__ + sMemAllocationTracker.erase((char*)addr) ; +#endif + + if(poolp) + { + poolp->freeMem(addr) ; + } + else + { + delete[] addr ; + } +} + //-------------------------------------------------------------------- //class LLPrivateMemoryPoolTester //-------------------------------------------------------------------- @@ -1915,7 +2012,7 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 for(j = 0 ; j < levels; j++) { size = min_size + j * stride ; - p[i][j] = sPool->allocate(size) ; + p[i][j] = ALLOCATE_MEM(sPool, size) ; total_allocated_size+= size ; @@ -1931,7 +2028,7 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 if(p[i][k]) { llassert_always(*(U32*)p[i][k] == i && *((U32*)p[i][k] + 1) == k) ; - sPool->freeMem(p[i][k]) ; + FREE_MEM(sPool, p[i][k]) ; total_allocated_size -= min_size + k * stride ; p[i][k] = NULL ; } @@ -1952,7 +2049,7 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 if(p[i][j]) { llassert_always(*(U32*)p[i][j] == i && *((U32*)p[i][j] + 1) == j) ; - sPool->freeMem(p[i][j]) ; + FREE_MEM(sPool, p[i][j]) ; total_allocated_size -= min_size + j * stride ; p[i][j] = NULL ; } @@ -1977,7 +2074,7 @@ void LLPrivateMemoryPoolTester::testAndTime(U32 size, U32 times) //allocation for(U32 i = 0 ; i < times; i++) { - p[i] = sPool->allocate(size) ; + p[i] = ALLOCATE_MEM(sPool, size) ; if(!p[i]) { llerrs << "allocation failed" << llendl ; @@ -1986,7 +2083,7 @@ void LLPrivateMemoryPoolTester::testAndTime(U32 size, U32 times) //de-allocation for(U32 i = 0 ; i < times; i++) { - sPool->freeMem(p[i]) ; + FREE_MEM(sPool, p[i]) ; p[i] = NULL ; } llinfos << "time spent using customized memory pool: " << timer.getElapsedTimeF32() << llendl ; @@ -2020,8 +2117,8 @@ void LLPrivateMemoryPoolTester::correctnessTest() //to see if allocation is right. //edge case - char* p = sPool->allocate(0) ; - sPool->freeMem(p) ; + char* p = ALLOCATE_MEM(sPool, 0) ; + FREE_MEM(sPool, p) ; //small sized // [8 bytes, 2KB), each asks for 256 allocations and deallocations diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 001ff9c123..d50ae99823 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -34,6 +34,10 @@ extern S32 gDACount; extern void* ll_allocate (size_t size); extern void ll_release (void *p); +#ifndef __DEBUG_PRIVATE_MEM__ +#define __DEBUG_PRIVATE_MEM__ 0 +#endif + class LL_COMMON_API LLMemory { public: @@ -234,7 +238,6 @@ private: LLPrivateMemoryPool(S32 type) ; ~LLPrivateMemoryPool() ; -public: char *allocate(U32 size) ; void freeMem(void* addr) ; @@ -314,8 +317,27 @@ public: U32 mTotalReservedSize ; U32 mTotalAllocatedSize ; + +public: +#if __DEBUG_PRIVATE_MEM__ + static char* allocate(LLPrivateMemoryPool* poolp, U32 size, const char* function, const int line) ; + + typedef std::map mem_allocation_info_t ; + static mem_allocation_info_t sMemAllocationTracker; +#else + static char* allocate(LLPrivateMemoryPool* poolp, U32 size) ; +#endif + static void freeMem(LLPrivateMemoryPool* poolp, void* addr) ; }; +//------------------------------------------------------------------------------------- +#if __DEBUG_PRIVATE_MEM__ +#define ALLOCATE_MEM(poolp, size) LLPrivateMemoryPoolManager::allocate((poolp), (size), __FUNCTION__, __LINE__) +#else +#define ALLOCATE_MEM(poolp, size) LLPrivateMemoryPoolManager::allocate((poolp), (size)) +#endif +#define FREE_MEM(poolp, addr) LLPrivateMemoryPoolManager::freeMem((poolp), (addr)) +//------------------------------------------------------------------------------------- // //the below singleton is used to test the private memory pool. // diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index eefcf0a9fb..cfa4123b1e 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -122,32 +122,6 @@ void LLImageBase::destroyPrivatePool() } } -//static -char* LLImageBase::allocateMemory(S32 size) -{ - if(sPrivatePoolp) - { - return sPrivatePoolp->allocate(size) ; - } - else - { - return new char[size]; - } -} - -//static -void LLImageBase::deleteMemory(void* p) -{ - if(sPrivatePoolp) - { - sPrivatePoolp->freeMem(p) ; - } - else - { - delete[] (char*)p ; - } -} - // virtual void LLImageBase::dump() { @@ -181,7 +155,7 @@ void LLImageBase::sanityCheck() // virtual void LLImageBase::deleteData() { - deleteMemory(mData) ; + FREE_MEM(sPrivatePoolp, mData) ; mData = NULL; mDataSize = 0; } @@ -218,7 +192,7 @@ U8* LLImageBase::allocateData(S32 size) { deleteData(); // virtual mBadBufferAllocation = false ; - mData = (U8*)allocateMemory(size); + mData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size); if (!mData) { llwarns << "allocate image data: " << size << llendl; @@ -236,7 +210,7 @@ U8* LLImageBase::allocateData(S32 size) U8* LLImageBase::reallocateData(S32 size) { LLMemType mt1(mMemType); - U8 *new_datap = (U8*)allocateMemory(size); + U8 *new_datap = (U8*)ALLOCATE_MEM(sPrivatePoolp, size); if (!new_datap) { llwarns << "Out of memory in LLImageBase::reallocateData" << llendl; @@ -246,7 +220,7 @@ U8* LLImageBase::reallocateData(S32 size) { S32 bytes = llmin(mDataSize, size); memcpy(new_datap, mData, bytes); /* Flawfinder: ignore */ - deleteMemory(mData) ; + FREE_MEM(sPrivatePoolp, mData) ; } mData = new_datap; mDataSize = size; @@ -1601,7 +1575,7 @@ void LLImageFormatted::appendData(U8 *data, S32 size) S32 newsize = cursize + size; reallocateData(newsize); memcpy(getData() + cursize, data, size); - deleteMemory(data); + FREE_MEM(LLImageBase::getPrivatePool(), data); } } } diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index ab20ccda9e..10621623ad 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -140,8 +140,7 @@ public: static void createPrivatePool() ; static void destroyPrivatePool() ; - static char* allocateMemory(S32 size) ; - static void deleteMemory(void* p) ; + static LLPrivateMemoryPool* getPrivatePool() {return sPrivatePoolp;} private: U8 *mData; diff --git a/indra/llimage/llimagedxt.cpp b/indra/llimage/llimagedxt.cpp index 81be09a412..2867f5e6f0 100644 --- a/indra/llimage/llimagedxt.cpp +++ b/indra/llimage/llimagedxt.cpp @@ -429,7 +429,7 @@ bool LLImageDXT::convertToDXR() S32 nmips = calcNumMips(width,height); S32 total_bytes = getDataSize(); U8* olddata = getData(); - U8* newdata = (U8*)allocateMemory(total_bytes); + U8* newdata = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), total_bytes); if (!newdata) { llerrs << "Out of memory in LLImageDXT::convertToDXR()" << llendl; diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 1bdcba6eb5..78e5d58f14 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -372,14 +372,14 @@ BOOL LLImageJ2C::loadAndValidate(const std::string &filename) } else { - U8 *data = (U8*)allocateMemory(file_size); + U8 *data = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), file_size); apr_size_t bytes_read = file_size; apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read infile.close() ; if (s != APR_SUCCESS || (S32)bytes_read != file_size) { - deleteMemory(data); + FREE_MEM(LLImageBase::getPrivatePool(), data); setLastError("Unable to read entire file"); res = FALSE; } diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index fd2a04373b..67417aea43 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -544,7 +544,7 @@ void LLVertexBuffer::createGLBuffer() { static int gl_buffer_idx = 0; mGLBuffer = ++gl_buffer_idx; - mMappedData = (U8*)sPrivatePoolp->allocate(size); + mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size); memset(mMappedData, 0, size); } } @@ -574,7 +574,7 @@ void LLVertexBuffer::createGLIndices() } else { - mMappedIndexData = (U8*)sPrivatePoolp->allocate(size); + mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size); memset(mMappedIndexData, 0, size); static int gl_buffer_idx = 0; mGLIndices = ++gl_buffer_idx; @@ -598,7 +598,7 @@ void LLVertexBuffer::destroyGLBuffer() } else { - sPrivatePoolp->freeMem(mMappedData) ; + FREE_MEM(sPrivatePoolp, mMappedData) ; mMappedData = NULL; mEmpty = TRUE; } @@ -627,7 +627,7 @@ void LLVertexBuffer::destroyGLIndices() } else { - sPrivatePoolp->freeMem(mMappedIndexData) ; + FREE_MEM(sPrivatePoolp, mMappedIndexData) ; mMappedIndexData = NULL; mEmpty = TRUE; } @@ -759,7 +759,7 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) if (!useVBOs()) { U8* old = mMappedData; - mMappedData = (U8*)sPrivatePoolp->allocate(newsize); + mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, newsize); if (old) { memcpy(mMappedData, old, llmin(newsize, oldsize)); @@ -768,7 +768,7 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) memset(mMappedData+oldsize, 0, newsize-oldsize); } - sPrivatePoolp->freeMem(old); + FREE_MEM(sPrivatePoolp, old); } else { @@ -796,7 +796,7 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) { //delete old buffer, keep GL buffer for now U8* old = mMappedIndexData; - mMappedIndexData = (U8*)sPrivatePoolp->allocate(new_index_size); + mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, new_index_size); if (old) { @@ -805,7 +805,7 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) { memset(mMappedIndexData+old_index_size, 0, new_index_size - old_index_size); } - sPrivatePoolp->freeMem(old); + FREE_MEM(sPrivatePoolp, old); } else { @@ -852,8 +852,8 @@ void LLVertexBuffer::freeClientBuffer() { if(useVBOs() && sDisableVBOMapping && (mMappedData || mMappedIndexData)) { - sPrivatePoolp->freeMem(mMappedData) ; - sPrivatePoolp->freeMem(mMappedIndexData) ; + FREE_MEM(sPrivatePoolp, mMappedData) ; + FREE_MEM(sPrivatePoolp, mMappedIndexData) ; mMappedData = NULL ; mMappedIndexData = NULL ; } @@ -864,7 +864,7 @@ void LLVertexBuffer::allocateClientVertexBuffer() if(!mMappedData) { U32 size = getSize() ; - mMappedData = (U8*)sPrivatePoolp->allocate(size); + mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size); memset(mMappedData, 0, size); } } @@ -874,7 +874,7 @@ void LLVertexBuffer::allocateClientIndexBuffer() if(!mMappedIndexData) { U32 size = getIndicesSize(); - mMappedIndexData = (U8*)sPrivatePoolp->allocate(size); + mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size); memset(mMappedIndexData, 0, size); } } diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 11dff69e0c..b6e396a96f 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -113,7 +113,7 @@ public: ~LLTextureCacheWorker() { llassert_always(!haveWork()); - LLImageBase::deleteMemory(mReadData); + FREE_MEM(LLImageBase::getPrivatePool(), mReadData); } // override this interface @@ -215,7 +215,7 @@ bool LLTextureCacheLocalFileWorker::doRead() mDataSize = 0; return true; } - mReadData = (U8*)LLImageBase::allocateMemory(mDataSize); + mReadData = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mDataSize); mBytesRead = -1; mBytesToRead = mDataSize; setPriority(LLWorkerThread::PRIORITY_LOW | mPriority); @@ -233,7 +233,7 @@ bool LLTextureCacheLocalFileWorker::doRead() // << " Bytes: " << mDataSize << " Offset: " << mOffset // << " / " << mDataSize << llendl; mDataSize = 0; // failed - LLImageBase::deleteMemory(mReadData); + FREE_MEM(LLImageBase::getPrivatePool(), mReadData); mReadData = NULL; } return true; @@ -248,7 +248,7 @@ bool LLTextureCacheLocalFileWorker::doRead() { mDataSize = local_size; } - mReadData = (U8*)LLImageBase::allocateMemory(mDataSize); + mReadData = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mDataSize); S32 bytes_read = LLAPRFile::readEx(mFileName, mReadData, mOffset, mDataSize); @@ -258,7 +258,7 @@ bool LLTextureCacheLocalFileWorker::doRead() // << " Bytes: " << mDataSize << " Offset: " << mOffset // << " / " << mDataSize << llendl; mDataSize = 0; - LLImageBase::deleteMemory(mReadData); + FREE_MEM(LLImageBase::getPrivatePool(), mReadData); mReadData = NULL; } else @@ -377,7 +377,7 @@ bool LLTextureCacheRemoteWorker::doRead() mDataSize = local_size; } // Allocate read buffer - mReadData = (U8*)LLImageBase::allocateMemory(mDataSize); + mReadData = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mDataSize); S32 bytes_read = LLAPRFile::readEx(local_filename, mReadData, mOffset, mDataSize); if (bytes_read != mDataSize) { @@ -385,7 +385,7 @@ bool LLTextureCacheRemoteWorker::doRead() << " Bytes: " << mDataSize << " Offset: " << mOffset << " / " << mDataSize << llendl; mDataSize = 0; - LLImageBase::deleteMemory(mReadData); + FREE_MEM(LLImageBase::getPrivatePool(), mReadData); mReadData = NULL; } else @@ -428,14 +428,14 @@ bool LLTextureCacheRemoteWorker::doRead() S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset; size = llmin(size, mDataSize); // Allocate the read buffer - mReadData = (U8*)LLImageBase::allocateMemory(size); + mReadData = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), size); S32 bytes_read = LLAPRFile::readEx(mCache->mHeaderDataFileName, mReadData, offset, size); if (bytes_read != size) { llwarns << "LLTextureCacheWorker: " << mID << " incorrect number of bytes read from header: " << bytes_read << " / " << size << llendl; - LLImageBase::deleteMemory(mReadData); + FREE_MEM(LLImageBase::getPrivatePool(), mReadData); mReadData = NULL; mDataSize = -1; // failed done = true; @@ -465,7 +465,7 @@ bool LLTextureCacheRemoteWorker::doRead() S32 data_offset, file_size, file_offset; // Reserve the whole data buffer first - U8* data = (U8*)LLImageBase::allocateMemory(mDataSize); + U8* data = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mDataSize); // Set the data file pointers taking the read offset into account. 2 cases: if (mOffset < TEXTURE_CACHE_ENTRY_SIZE) @@ -478,7 +478,7 @@ bool LLTextureCacheRemoteWorker::doRead() // Copy the raw data we've been holding from the header cache into the new sized buffer llassert_always(mReadData); memcpy(data, mReadData, data_offset); - LLImageBase::deleteMemory(mReadData); + FREE_MEM(LLImageBase::getPrivatePool(), mReadData); mReadData = NULL; } else @@ -503,7 +503,7 @@ bool LLTextureCacheRemoteWorker::doRead() llwarns << "LLTextureCacheWorker: " << mID << " incorrect number of bytes read from body: " << bytes_read << " / " << file_size << llendl; - LLImageBase::deleteMemory(mReadData); + FREE_MEM(LLImageBase::getPrivatePool(), mReadData); mReadData = NULL; mDataSize = -1; // failed done = true; @@ -595,11 +595,11 @@ bool LLTextureCacheRemoteWorker::doWrite() { // We need to write a full record in the header cache so, if the amount of data is smaller // than a record, we need to transfer the data to a buffer padded with 0 and write that - U8* padBuffer = (U8*)LLImageBase::allocateMemory(TEXTURE_CACHE_ENTRY_SIZE); + U8* padBuffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), TEXTURE_CACHE_ENTRY_SIZE); memset(padBuffer, 0, TEXTURE_CACHE_ENTRY_SIZE); // Init with zeros memcpy(padBuffer, mWriteData, mDataSize); // Copy the write buffer bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, padBuffer, offset, size); - LLImageBase::deleteMemory(padBuffer); + FREE_MEM(LLImageBase::getPrivatePool(), padBuffer); } else { @@ -694,7 +694,7 @@ void LLTextureCacheWorker::finishWork(S32 param, bool completed) } else { - LLImageBase::deleteMemory(mReadData); + FREE_MEM(LLImageBase::getPrivatePool(), mReadData); mReadData = NULL; } } diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 806f130486..e9be45ffd0 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -816,7 +816,7 @@ void LLTextureFetchWorker::setImagePriority(F32 priority) void LLTextureFetchWorker::resetFormattedData() { - LLImageBase::deleteMemory(mBuffer); + FREE_MEM(LLImageBase::getPrivatePool(), mBuffer); mBuffer = NULL; mBufferSize = 0; if (mFormattedImage.notNull()) @@ -887,7 +887,7 @@ bool LLTextureFetchWorker::doWork(S32 param) mSentRequest = UNSENT; mDecoded = FALSE; mWritten = FALSE; - LLImageBase::deleteMemory(mBuffer); + FREE_MEM(LLImageBase::getPrivatePool(), mBuffer); mBuffer = NULL; mBufferSize = 0; mHaveAllData = FALSE; @@ -1283,7 +1283,7 @@ bool LLTextureFetchWorker::doWork(S32 param) llassert_always(mBufferSize == cur_size + mRequestedSize); if(!mBufferSize)//no data received. { - LLImageBase::deleteMemory(mBuffer); + FREE_MEM(LLImageBase::getPrivatePool(), mBuffer); mBuffer = NULL; //abort. @@ -1311,7 +1311,7 @@ bool LLTextureFetchWorker::doWork(S32 param) mFileSize = mBufferSize + 1 ; //flag the file is not fully loaded. } - U8* buffer = (U8*)LLImageBase::allocateMemory(mBufferSize); + U8* buffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mBufferSize); if (cur_size > 0) { memcpy(buffer, mFormattedImage->getData(), cur_size); @@ -1320,7 +1320,7 @@ bool LLTextureFetchWorker::doWork(S32 param) // NOTE: setData releases current data and owns new data (buffer) mFormattedImage->setData(buffer, mBufferSize); // delete temp data - LLImageBase::deleteMemory(mBuffer); // Note: not 'buffer' (assigned in setData()) + FREE_MEM(LLImageBase::getPrivatePool(), mBuffer); // Note: not 'buffer' (assigned in setData()) mBuffer = NULL; mBufferSize = 0; mLoadedDiscard = mRequestedDiscard; @@ -1617,7 +1617,7 @@ bool LLTextureFetchWorker::processSimulatorPackets() if (buffer_size > cur_size) { /// We have new data - U8* buffer = (U8*)LLImageBase::allocateMemory(buffer_size); + U8* buffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), buffer_size); S32 offset = 0; if (cur_size > 0 && mFirstPacket > 0) { @@ -1669,7 +1669,7 @@ S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels, if (data_size > 0) { // *TODO: set the formatted image data here directly to avoid the copy - mBuffer = (U8*)LLImageBase::allocateMemory(data_size); + mBuffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), data_size); buffer->readAfter(channels.in(), NULL, mBuffer, data_size); mBufferSize += data_size; if (data_size < mRequestedSize && mRequestedDiscard == 0) -- cgit v1.2.3 From cce2a3b7a46e3d1c2992995f3a3979f8ce59b664 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Tue, 10 May 2011 21:04:41 -0600 Subject: release memory held by LLWorld when destroy it. --- indra/newview/llworld.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'indra') diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 9db6d5e08c..127318d06c 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -131,6 +131,12 @@ void LLWorld::destroyClass() LLVOCache::getInstance()->destroyClass() ; } LLViewerPartSim::getInstance()->destroyClass(); + + mDefaultWaterTexturep = NULL ; + for (S32 i = 0; i < 8; i++) + { + mEdgeWaterObjects[i] = NULL; + } } -- cgit v1.2.3 From 39f033a013278206fa6a93273965bd11066ee492 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Tue, 10 May 2011 21:13:20 -0600 Subject: fix a linux compiling error. --- indra/llcommon/llmemory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 8f65107e47..2d190fe660 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -1920,7 +1920,7 @@ void LLPrivateMemoryPoolManager::freeMem(LLPrivateMemoryPool* poolp, void* addr } else { - delete[] addr ; + delete[] (char*)addr ; } } -- cgit v1.2.3 From d696977c705929b944359f4a5bbb7501645f62bc Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Wed, 11 May 2011 14:23:15 -0600 Subject: fix a crash --- indra/llcommon/llmemory.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'indra') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 2d190fe660..4143f630c8 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -1629,6 +1629,10 @@ void LLPrivateMemoryPool::addToHashTable(LLMemoryChunk* chunk) { mChunkHashList[start_key] = chunk ; } + if(start_key == end_key) + { + return ; //done + } if(!need_rehash) { -- cgit v1.2.3 From d31e6735370711088f01cff448aa22f71c4c10c4 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Wed, 11 May 2011 14:41:23 -0600 Subject: fix a crash --- indra/llcommon/llmemory.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'indra') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 4143f630c8..629e76f341 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -1687,6 +1687,10 @@ void LLPrivateMemoryPool::removeFromHashTable(LLMemoryChunk* chunk) mChunkHashList[start_key] = chunk->mHashNext ; chunk->mHashNext = NULL ; + if(start_key == end_key) + { + return ; //done + } if(mChunkHashList[end_key] != chunk) { -- cgit v1.2.3 From 76eca5d0bce3e303f6d77b0d16f114320830ac6a Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Tue, 19 Jul 2011 23:17:55 -0600 Subject: fix for memory alignment to 16 bytes. --- indra/llcommon/llmemory.cpp | 98 ++++++++++++++++++++++++++++----------------- indra/llcommon/llmemory.h | 7 +++- 2 files changed, 66 insertions(+), 39 deletions(-) (limited to 'indra') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index ed28974163..6e804a94b0 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -62,7 +62,7 @@ LLPrivateMemoryPoolManager::mem_allocation_info_t LLPrivateMemoryPoolManager::sM #endif #ifndef _USE_PRIVATE_MEM_POOL_ -#define _USE_PRIVATE_MEM_POOL_ 0 +#define _USE_PRIVATE_MEM_POOL_ 1 #endif //static @@ -535,6 +535,9 @@ const char* LLMemTracker::getNextLine() //-------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------- +//minimum slot size and minimal slot size interval +const U32 ATOMIC_MEM_SLOT = 16 ; //bytes + //minimum block sizes (page size) for small allocation, medium allocation, large allocation const U32 MIN_BLOCK_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {2 << 10, 4 << 10, 16 << 10} ; // @@ -542,14 +545,30 @@ const U32 MIN_BLOCK_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {2 << 10, 4 < const U32 MAX_BLOCK_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {64 << 10, 1 << 20, 4 << 20} ; //minimum slot sizes for small allocation, medium allocation, large allocation -const U32 MIN_SLOT_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {8, 2 << 10, 512 << 10}; +const U32 MIN_SLOT_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {ATOMIC_MEM_SLOT, 2 << 10, 512 << 10}; //maximum slot sizes for small allocation, medium allocation, large allocation -const U32 MAX_SLOT_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {(2 << 10) - 8, (512 - 2) << 10, 4 << 20}; +const U32 MAX_SLOT_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {(2 << 10) - ATOMIC_MEM_SLOT, (512 - 2) << 10, 4 << 20}; //size of a block with multiple slots can not exceed CUT_OFF_SIZE const U32 CUT_OFF_SIZE = (64 << 10) ; //64 KB +//max number of slots in a block +const U32 MAX_NUM_SLOTS_IN_A_BLOCK = llmin(MIN_BLOCK_SIZES[0] / ATOMIC_MEM_SLOT, ATOMIC_MEM_SLOT * 8) ; + +//------------------------------------------------------------- +//align val to be integer times of ATOMIC_MEM_SLOT +U32 align(U32 val) +{ + U32 aligned = (val / ATOMIC_MEM_SLOT) * ATOMIC_MEM_SLOT ; + if(aligned < val) + { + aligned += ATOMIC_MEM_SLOT ; + } + + return aligned ; +} + //------------------------------------------------------------- //class LLPrivateMemoryPool::LLMemoryBlock //------------------------------------------------------------- @@ -575,35 +594,36 @@ void LLPrivateMemoryPool::LLMemoryBlock::init(char* buffer, U32 buffer_size, U32 mSlotSize = slot_size ; mTotalSlots = buffer_size / mSlotSize ; - llassert_always(buffer_size / mSlotSize <= 256) ; //max number is 256 + llassert_always(buffer_size / mSlotSize <= MAX_NUM_SLOTS_IN_A_BLOCK) ; //max number is 128 mAllocatedSlots = 0 ; + mDummySize = 0 ; //init the bit map. - //mark free bits - S32 usage_bit_len = (mTotalSlots + 31) / 32 ; - mDummySize = usage_bit_len - 1 ; //if the mTotalSlots more than 32, needs extra space for bit map - if(mDummySize > 0) //reserve extra space from mBuffer to store bitmap if needed. + //mark free bits + if(mTotalSlots > 32) //reserve extra space from mBuffer to store bitmap if needed. { - mTotalSlots -= (mDummySize * sizeof(mUsageBits) + mSlotSize - 1) / mSlotSize ; - usage_bit_len = (mTotalSlots + 31) / 32 ; - mDummySize = usage_bit_len - 1 ;//number of 32bits reserved from mBuffer for bitmap + mDummySize = ATOMIC_MEM_SLOT ; + mTotalSlots -= (mDummySize + mSlotSize - 1) / mSlotSize ; + mUsageBits = 0 ; - if(mDummySize > 0) + S32 usage_bit_len = (mTotalSlots + 31) / 32 ; + + for(S32 i = 0 ; i < usage_bit_len - 1 ; i++) { - mUsageBits = 0 ; - for(S32 i = 0 ; i < mDummySize ; i++) - { - *((U32*)mBuffer + i) = 0 ; - } - if(mTotalSlots & 31) - { - *((U32*)mBuffer + mDummySize - 1) = (0xffffffff << (mTotalSlots & 31)) ; - } + *((U32*)mBuffer + i) = 0 ; } - } - - if(mDummySize < 1)//no extra bitmap space reserved + for(S32 i = usage_bit_len - 1 ; i < mDummySize / sizeof(U32) ; i++) + { + *((U32*)mBuffer + i) = 0xffffffff ; + } + + if(mTotalSlots & 31) + { + *((U32*)mBuffer + usage_bit_len - 2) = (0xffffffff << (mTotalSlots & 31)) ; + } + } + else//no extra bitmap space reserved { mUsageBits = 0 ; if(mTotalSlots & 31) @@ -642,7 +662,7 @@ char* LLPrivateMemoryPool::LLMemoryBlock::allocate() } else if(mDummySize > 0)//go to extra space { - for(S32 i = 0 ; i < mDummySize; i++) + for(S32 i = 0 ; i < mDummySize / sizeof(U32); i++) { if(*((U32*)mBuffer + i) != 0xffffffff) { @@ -668,14 +688,14 @@ char* LLPrivateMemoryPool::LLMemoryBlock::allocate() mAllocatedSlots++ ; - return mBuffer + mDummySize * sizeof(U32) + (k * 32 + idx) * mSlotSize ; + return mBuffer + mDummySize + (k * 32 + idx) * mSlotSize ; } //free a slot void LLPrivateMemoryPool::LLMemoryBlock::freeMem(void* addr) { //bit index - U32 idx = ((U32)addr - (U32)mBuffer - mDummySize * sizeof(U32)) / mSlotSize ; + U32 idx = ((U32)addr - (U32)mBuffer - mDummySize) / mSlotSize ; U32* bits = &mUsageBits ; if(idx >= 32) @@ -699,7 +719,7 @@ void LLPrivateMemoryPool::LLMemoryBlock::freeMem(void* addr) //for debug use: reset the entire bitmap. void LLPrivateMemoryPool::LLMemoryBlock::resetBitMap() { - for(S32 i = 0 ; i < mDummySize ; i++) + for(S32 i = 0 ; i < mDummySize / sizeof(U32) ; i++) { *((U32*)mBuffer + i) = 0 ; } @@ -742,7 +762,10 @@ void LLPrivateMemoryPool::LLMemoryChunk::init(char* buffer, U32 buffer_size, U32 //data buffer, which can be used for allocation mDataBuffer = (char*)mFreeSpaceList + sizeof(LLMemoryBlock*) * mPartitionLevels ; - + + //alignmnet + mDataBuffer = mBuffer + align(mDataBuffer - mBuffer) ; + //init for(U32 i = 0 ; i < mBlockLevels; i++) { @@ -1306,7 +1329,7 @@ char* LLPrivateMemoryPool::allocate(U32 size) //if the asked size larger than MAX_BLOCK_SIZE, fetch from heap directly, the pool does not manage it if(size >= CHUNK_SIZE) { - return new char[size] ; + return (char*)malloc(size) ; } char* p = NULL ; @@ -1367,7 +1390,7 @@ void LLPrivateMemoryPool::freeMem(void* addr) if(!chunk) { - delete[] (char*)addr ; //release from heap + free(addr) ; //release from heap } else { @@ -1503,7 +1526,7 @@ LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::addChunk(S32 chunk_inde checkSize(preferred_size + overhead) ; mReservedPoolSize += preferred_size + overhead ; - char* buffer = new(std::nothrow) char[preferred_size + overhead] ; + char* buffer = (char*)malloc(preferred_size + overhead) ; if(!buffer) { return NULL ; @@ -1571,7 +1594,7 @@ void LLPrivateMemoryPool::removeChunk(LLMemoryChunk* chunk) mReservedPoolSize -= chunk->getBufferSize() ; //release memory - delete[] chunk->getBuffer() ; + free(chunk->getBuffer()) ; } U16 LLPrivateMemoryPool::findHashKey(const char* addr) @@ -1875,7 +1898,7 @@ char* LLPrivateMemoryPoolManager::allocate(LLPrivateMemoryPool* poolp, U32 size, if(!poolp) { - p = new char[size] ; + p = (char*)malloc(size) ; } else { @@ -1901,7 +1924,7 @@ char* LLPrivateMemoryPoolManager::allocate(LLPrivateMemoryPool* poolp, U32 size) #if _USE_PRIVATE_MEM_POOL_ if(!poolp) { - return new char[size] ; + return (char*)malloc(size) ; } else { @@ -1932,7 +1955,7 @@ void LLPrivateMemoryPoolManager::freeMem(LLPrivateMemoryPool* poolp, void* addr } else { - delete[] (char*)addr ; + free(addr) ; } #else free(addr) ; @@ -1942,6 +1965,7 @@ void LLPrivateMemoryPoolManager::freeMem(LLPrivateMemoryPool* poolp, void* addr //-------------------------------------------------------------------- //class LLPrivateMemoryPoolTester //-------------------------------------------------------------------- +#if 0 LLPrivateMemoryPoolTester* LLPrivateMemoryPoolTester::sInstance = NULL ; LLPrivateMemoryPool* LLPrivateMemoryPoolTester::sPool = NULL ; LLPrivateMemoryPoolTester::LLPrivateMemoryPoolTester() @@ -2168,5 +2192,5 @@ void LLPrivateMemoryPoolTester::fragmentationtest() //every time when asking for a new chunk during correctness test, and performance test, //print out the chunk usage statistices. } - +#endif //-------------------------------------------------------------------- diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index d3b824c6e9..26488423a3 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -226,7 +226,7 @@ public: U32 mUsageBits ; U8 mTotalSlots ; U8 mAllocatedSlots ; - U8 mDummySize ; //size of extra U32 reserved for mUsageBits. + U8 mDummySize ; //size of extra bytes reserved for mUsageBits. public: LLMemoryBlock* mPrev ; @@ -256,7 +256,7 @@ public: char* allocate(U32 size) ; void freeMem(void* addr) ; - const char* getBuffer() const {return mBuffer;} + char* getBuffer() const {return mBuffer;} U32 getBufferSize() const {return mBufferSize;} U32 getAllocatedSize() const {return mAlloatedSize;} @@ -408,9 +408,11 @@ public: #endif #define FREE_MEM(poolp, addr) LLPrivateMemoryPoolManager::freeMem((poolp), (addr)) //------------------------------------------------------------------------------------- + // //the below singleton is used to test the private memory pool. // +#if 0 class LL_COMMON_API LLPrivateMemoryPoolTester { private: @@ -481,6 +483,7 @@ void LLPrivateMemoryPoolTester::operator delete[](void* addr) sPool->free(addr) ; } #endif +#endif // LLRefCount moved to llrefcount.h // LLPointer moved to llpointer.h -- cgit v1.2.3 From 5ee90d78488690e49a8195ce2a08034f73b637ee Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Wed, 20 Jul 2011 10:24:44 -0600 Subject: fix a merge error --- indra/llcommon/llmemory.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 6e804a94b0..eb55bdae84 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -110,7 +110,10 @@ void LLMemory::updateMemoryInfo() sAllocatedMemInKB = (U32)(counters.WorkingSetSize / 1024) ; sAllocatedPageSizeInKB = (U32)(counters.PagefileUsage / 1024) ; - sMaxPhysicalMemInKB = llmin(LLMemoryInfo::getAvailableMemoryKB() + sAllocatedMemInKB, sMaxHeapSizeInKB); + + U32 avail_phys, avail_virtual; + LLMemoryInfo::getAvailableMemoryKB(avail_phys, avail_virtual) ; + sMaxPhysicalMemInKB = llmin(avail_phys + sAllocatedMemInKB, sMaxHeapSizeInKB); if(sMaxPhysicalMemInKB > sAllocatedMemInKB) { -- cgit v1.2.3 From 58f0afa1552f74f3f5f523c68f1ebd72b33966af Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Wed, 20 Jul 2011 11:18:05 -0600 Subject: fix a typo and trun off "MemoryFailurePreventionEnabled" --- indra/newview/app_settings/settings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra') diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 72792d1b04..8ff5341297 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -5556,7 +5556,7 @@ Value 1 - MemeoyFailurePreventionEnabled + MemoryFailurePreventionEnabled Comment If set, the viewer will quit to avoid crash when memory failure happens @@ -5565,7 +5565,7 @@ Type Boolean Value - 1 + 0 MemoryLogFrequency -- cgit v1.2.3 From f7861eaf4e50ca2b868179ced6258f9d936a2b9c Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Wed, 20 Jul 2011 11:21:08 -0600 Subject: fix a typo. --- indra/newview/llappviewer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index b7f4cb92cd..86b34ac327 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1069,7 +1069,7 @@ void LLAppViewer::initMaxHeapSize() //F32 max_heap_size_gb = llmin(1.6f, (F32)gSavedSettings.getF32("MaxHeapSize")) ; F32 max_heap_size_gb = gSavedSettings.getF32("MaxHeapSize") ; - BOOL enable_mem_failure_prevention = (BOOL)gSavedSettings.getBOOL("MemeoyFailurePreventionEnabled") ; + BOOL enable_mem_failure_prevention = (BOOL)gSavedSettings.getBOOL("MemoryFailurePreventionEnabled") ; LLMemory::initMaxHeapSizeGB(max_heap_size_gb, enable_mem_failure_prevention) ; } -- cgit v1.2.3 From 48d949150cd445ce1e801a7a8ee67597a965f14b Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Wed, 20 Jul 2011 16:05:19 -0600 Subject: add a debug setting "MemoryPrivatePoolEnabled" to turn on/off private memory pool. --- indra/llcommon/llmemory.cpp | 51 +++++++++++++++++---------------- indra/llcommon/llmemory.h | 6 ++-- indra/newview/app_settings/settings.xml | 13 ++++++++- indra/newview/llappviewer.cpp | 2 ++ 4 files changed, 45 insertions(+), 27 deletions(-) (limited to 'indra') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index eb55bdae84..0d36009fc4 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -61,10 +61,6 @@ BOOL LLMemory::sEnableMemoryFailurePrevention = FALSE; LLPrivateMemoryPoolManager::mem_allocation_info_t LLPrivateMemoryPoolManager::sMemAllocationTracker; #endif -#ifndef _USE_PRIVATE_MEM_POOL_ -#define _USE_PRIVATE_MEM_POOL_ 1 -#endif - //static void LLMemory::initClass() { @@ -1386,7 +1382,7 @@ void LLPrivateMemoryPool::freeMem(void* addr) { return ; } - + lock() ; LLMemoryChunk* chunk = findChunk((char*)addr) ; @@ -1789,7 +1785,7 @@ bool LLPrivateMemoryPool::fillHashTable(U16 start, U16 end, LLMemoryChunk* chunk //-------------------------------------------------------------------- LLPrivateMemoryPoolManager* LLPrivateMemoryPoolManager::sInstance = NULL ; -LLPrivateMemoryPoolManager::LLPrivateMemoryPoolManager() +LLPrivateMemoryPoolManager::LLPrivateMemoryPoolManager(BOOL enabled) { mPoolList.resize(LLPrivateMemoryPool::MAX_TYPES) ; @@ -1797,6 +1793,8 @@ LLPrivateMemoryPoolManager::LLPrivateMemoryPoolManager() { mPoolList[i] = NULL ; } + + mPrivatePoolEnabled = enabled ; } LLPrivateMemoryPoolManager::~LLPrivateMemoryPoolManager() @@ -1838,13 +1836,21 @@ LLPrivateMemoryPoolManager::~LLPrivateMemoryPoolManager() #endif } +//static +void LLPrivateMemoryPoolManager::initClass(BOOL enabled) +{ + llassert_always(!sInstance) ; + + sInstance = new LLPrivateMemoryPoolManager(enabled) ; +} + //static LLPrivateMemoryPoolManager* LLPrivateMemoryPoolManager::getInstance() { - if(!sInstance) - { - sInstance = new LLPrivateMemoryPoolManager() ; - } + //if(!sInstance) + //{ + // sInstance = new LLPrivateMemoryPoolManager(FALSE) ; + //} return sInstance ; } @@ -1860,6 +1866,11 @@ void LLPrivateMemoryPoolManager::destroyClass() LLPrivateMemoryPool* LLPrivateMemoryPoolManager::newPool(S32 type) { + if(!mPrivatePoolEnabled) + { + return NULL ; + } + if(!mPoolList[type]) { mPoolList[type] = new LLPrivateMemoryPool(type) ; @@ -1870,7 +1881,7 @@ LLPrivateMemoryPool* LLPrivateMemoryPoolManager::newPool(S32 type) void LLPrivateMemoryPoolManager::deletePool(LLPrivateMemoryPool* pool) { - if(pool->isEmpty()) + if(pool && pool->isEmpty()) { mPoolList[pool->getType()] = NULL ; delete pool; @@ -1907,7 +1918,7 @@ char* LLPrivateMemoryPoolManager::allocate(LLPrivateMemoryPool* poolp, U32 size, { p = poolp->allocate(size) ; } - + if(p) { char num[16] ; @@ -1924,18 +1935,14 @@ char* LLPrivateMemoryPoolManager::allocate(LLPrivateMemoryPool* poolp, U32 size, //static char* LLPrivateMemoryPoolManager::allocate(LLPrivateMemoryPool* poolp, U32 size) { -#if _USE_PRIVATE_MEM_POOL_ - if(!poolp) + if(poolp) { - return (char*)malloc(size) ; + return poolp->allocate(size) ; } else { - return poolp->allocate(size) ; + return (char*)malloc(size) ; } -#else - return (char*)malloc(size) ; -#endif } #endif @@ -1951,7 +1958,6 @@ void LLPrivateMemoryPoolManager::freeMem(LLPrivateMemoryPool* poolp, void* addr sMemAllocationTracker.erase((char*)addr) ; #endif -#if _USE_PRIVATE_MEM_POOL_ if(poolp) { poolp->freeMem(addr) ; @@ -1959,10 +1965,7 @@ void LLPrivateMemoryPoolManager::freeMem(LLPrivateMemoryPool* poolp, void* addr else { free(addr) ; - } -#else - free(addr) ; -#endif + } } //-------------------------------------------------------------------- diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 26488423a3..f9099da612 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -367,11 +367,12 @@ private: class LL_COMMON_API LLPrivateMemoryPoolManager { private: - LLPrivateMemoryPoolManager() ; + LLPrivateMemoryPoolManager(BOOL enabled) ; ~LLPrivateMemoryPoolManager() ; -public: +public: static LLPrivateMemoryPoolManager* getInstance() ; + static void initClass(BOOL enabled) ; static void destroyClass() ; LLPrivateMemoryPool* newPool(S32 type) ; @@ -380,6 +381,7 @@ public: private: static LLPrivateMemoryPoolManager* sInstance ; std::vector mPoolList ; + BOOL mPrivatePoolEnabled; public: //debug and statistics info. diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 8ff5341297..9c065537e5 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -5561,7 +5561,7 @@ Comment If set, the viewer will quit to avoid crash when memory failure happens Persist - 0 + 1 Type Boolean Value @@ -5578,6 +5578,17 @@ Value 600.0 + MemoryPrivatePoolEnabled + + Comment + Enable the private memory pool management + Persist + 1 + Type + Boolean + Value + 0 + MemProfiling Comment diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 86b34ac327..156c76e84c 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -686,6 +686,8 @@ bool LLAppViewer::init() //set the max heap size. initMaxHeapSize() ; + LLPrivateMemoryPoolManager::initClass((BOOL)gSavedSettings.getBOOL("MemoryPrivatePoolEnabled")) ; + // write Google Breakpad minidump files to our log directory std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); logdir += gDirUtilp->getDirDelimiter(); -- cgit v1.2.3 From a0f3b2a9cc0022605b4da6705bc3dc9578977f48 Mon Sep 17 00:00:00 2001 From: Vadim ProductEngine Date: Mon, 22 Aug 2011 18:04:27 +0300 Subject: STORM-1566 FIXED Sidebar tabs didn't detach by drag-n-drop. The regression was introduced in the fix of EXP-856 (changeset 9e650f2750b5). --- indra/newview/llsidetray.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'indra') diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp index 651897a217..a7c4057846 100644 --- a/indra/newview/llsidetray.cpp +++ b/indra/newview/llsidetray.cpp @@ -496,7 +496,7 @@ public: LLSideTray* side_tray = LLSideTray::getInstance(); // Check if the tab we are dragging is docked. - if (!side_tray->isTabAttached(getName())) return FALSE; + if (!side_tray->isTabAttached(mTabName)) return FALSE; // Same value is hardcoded in LLDragHandle::handleHover(). const S32 undock_threshold = 12; @@ -505,7 +505,7 @@ public: if (delta_x <= -undock_threshold || delta_x >= undock_threshold || delta_y <= -undock_threshold || delta_y >= undock_threshold) { - LLSideTrayTab* tab = side_tray->getTab(getName()); + LLSideTrayTab* tab = side_tray->getTab(mTabName); if (!tab) return FALSE; tab->setDocked(false); @@ -544,7 +544,12 @@ protected: , mDragLastScreenX(0) , mDragLastScreenY(0) , mBadgeDriver(NULL) - {} + { + // Find out the tab name to use in handleHover(). + size_t pos = getName().find("_button"); + llassert(pos != std::string::npos); + mTabName = getName().substr(0, pos); + } friend class LLUICtrlFactory; @@ -562,6 +567,7 @@ private: S32 mDragLastScreenX; S32 mDragLastScreenY; + std::string mTabName; LLSideTrayTabBadgeDriver* mBadgeDriver; }; @@ -679,6 +685,7 @@ LLSideTrayTab* LLSideTray::getTab(const std::string& name) bool LLSideTray::isTabAttached(const std::string& name) { LLSideTrayTab* tab = getTab(name); + llassert(tab); if (!tab) return false; return std::find(mTabs.begin(), mTabs.end(), tab) != mTabs.end(); -- cgit v1.2.3 From 541e26d947e19cf087e068ab3f1bd46fb1d8fd4f Mon Sep 17 00:00:00 2001 From: Jonathan Yap Date: Tue, 23 Aug 2011 07:55:34 -0400 Subject: STORM-1567 Mute button for llDialog popup Updating patch to current version of viewer-development --- indra/newview/lltoastnotifypanel.cpp | 26 ++++++++++++++++++++++ indra/newview/llviewermessage.cpp | 25 ++++++++++++++++----- .../newview/skins/default/xui/en/notifications.xml | 4 ++++ 3 files changed, 50 insertions(+), 5 deletions(-) (limited to 'indra') diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp index fa91f129b8..ea047a1878 100644 --- a/indra/newview/lltoastnotifypanel.cpp +++ b/indra/newview/lltoastnotifypanel.cpp @@ -305,10 +305,17 @@ void LLToastNotifyPanel::updateButtonsLayout(const std::vectorgetRect().getWidth(); LLButton* ignore_btn = NULL; + LLButton* mute_btn = NULL; for (std::vector::const_iterator it = buttons.begin(); it != buttons.end(); it++) { + if (-2 == it->first) + { + mute_btn = it->second; + continue; + } if (it->first == -1) { ignore_btn = it->second; @@ -328,6 +335,8 @@ void LLToastNotifyPanel::updateButtonsLayout(const std::vectoraddChild(btn, -1); } + + U32 ignore_btn_width = 0; if (mIsScriptDialog && ignore_btn != NULL) { LLRect ignore_btn_rect(ignore_btn->getRect()); @@ -337,11 +346,28 @@ void LLToastNotifyPanel::updateButtonsLayout(const std::vectorsetRect(ignore_btn_rect); + ignore_btn_width = ignore_btn_rect.getWidth(); mControlPanel->addChild(ignore_btn, -1); } + + if (mIsScriptDialog && mute_btn != NULL) + { + LLRect mute_btn_rect(mute_btn->getRect()); + S32 buttons_per_row = max_width / BUTTON_WIDTH; //assume that h_pad far less than BUTTON_WIDTH + S32 mute_btn_left = buttons_per_row * BUTTON_WIDTH + (buttons_per_row - 1) * h_pad - mute_btn_rect.getWidth() - ignore_btn_width - (h_pad / 2); + if (mute_btn_left + mute_btn_rect.getWidth() > max_width) // make sure that the mute button is in panel + { + mute_btn_left = max_width - mute_btn_rect.getWidth() - 2 * HPAD; + } + mute_btn_rect.setOriginAndSize(mute_btn_left, BOTTOM_PAD,// always move mute button at the bottom + mute_btn_rect.getWidth(), mute_btn_rect.getHeight()); + mute_btn->setRect(mute_btn_rect); + mControlPanel->addChild(mute_btn); + } } void LLToastNotifyPanel::adjustPanelForScriptNotice(S32 button_panel_width, S32 button_panel_height) diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 321d02aaf1..8471de3004 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -6544,8 +6544,22 @@ bool callback_script_dialog(const LLSD& notification, const LLSD& response) rtn_text = LLNotification::getSelectedOptionName(response); } - // Didn't click "Ignore" - if (button_idx != -1) + // Button -2 = Mute + // Button -1 = Ignore - no processing needed for this button + // Buttons 0 and above = dialog choices + + if (-2 == button_idx) + { + std::string object_name = notification["payload"]["object_name"].asString(); + LLUUID object_id = notification["payload"]["object_id"].asUUID(); + LLMute mute(object_id, object_name, LLMute::OBJECT); + if (LLMuteList::getInstance()->add(mute)) + { + LLPanelBlockedList::showPanelAndSelect(object_id); + } + } + + if (0 <= button_idx) { LLMessageSystem* msg = gMessageSystem; msg->newMessage("ScriptDialogReply"); @@ -6588,12 +6602,12 @@ void process_script_dialog(LLMessageSystem* msg, void**) std::string message; std::string first_name; std::string last_name; - std::string title; + std::string object_name; S32 chat_channel; msg->getString("Data", "FirstName", first_name); msg->getString("Data", "LastName", last_name); - msg->getString("Data", "ObjectName", title); + msg->getString("Data", "ObjectName", object_name); msg->getString("Data", "Message", message); msg->getS32("Data", "ChatChannel", chat_channel); @@ -6604,6 +6618,7 @@ void process_script_dialog(LLMessageSystem* msg, void**) payload["sender"] = msg->getSender().getIPandPort(); payload["object_id"] = object_id; payload["chat_channel"] = chat_channel; + payload["object_name"] = object_name; // build up custom form S32 button_count = msg->getNumberOfBlocks("Buttons"); @@ -6622,7 +6637,7 @@ void process_script_dialog(LLMessageSystem* msg, void**) } LLSD args; - args["TITLE"] = title; + args["TITLE"] = object_name; args["MESSAGE"] = message; LLNotificationPtr notification; if (!first_name.empty()) diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index c9ccd44b83..43e01a1080 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -6275,6 +6275,10 @@ Grant this request? [GROUPNAME]'s '<nolink>[TITLE]</nolink>' [MESSAGE]
+