// MemBlocks.cpp #include "StdAfx.h" #include "Common/MyCom.h" #include "StreamUtils.h" #include "MemBlocks.h" bool CMemBlockManager::AllocateSpace(size_t numBlocks) { FreeSpace(); if (_blockSize < sizeof(void *) || numBlocks < 1) return false; size_t totalSize = numBlocks * _blockSize; if (totalSize / _blockSize != numBlocks) return false; _data = ::MidAlloc(totalSize); if (_data == 0) return false; Byte *p = (Byte *)_data; for (size_t i = 0; i + 1 < numBlocks; i++, p += _blockSize) *(Byte **)p = (p + _blockSize); *(Byte **)p = 0; _headFree = _data; return true; } void CMemBlockManager::FreeSpace() { ::MidFree(_data); _data = 0; _headFree= 0; } void *CMemBlockManager::AllocateBlock() { if (_headFree == 0) return 0; void *p = _headFree; _headFree = *(void **)_headFree; return p; } void CMemBlockManager::FreeBlock(void *p) { if (p == 0) return; *(void **)p = _headFree; _headFree = p; } bool CMemBlockManagerMt::AllocateSpace(size_t numBlocks, size_t numNoLockBlocks) { if (numNoLockBlocks > numBlocks) return false; if (!CMemBlockManager::AllocateSpace(numBlocks)) return false; size_t numLockBlocks = numBlocks - numNoLockBlocks; return Semaphore.Create((LONG)numLockBlocks, (LONG)numLockBlocks); } bool CMemBlockManagerMt::AllocateSpaceAlways(size_t desiredNumberOfBlocks, size_t numNoLockBlocks) { if (numNoLockBlocks > desiredNumberOfBlocks) return false; for (;;) { if (AllocateSpace(desiredNumberOfBlocks, numNoLockBlocks)) return true; if (desiredNumberOfBlocks == numNoLockBlocks) return false; desiredNumberOfBlocks = numNoLockBlocks + ((desiredNumberOfBlocks - numNoLockBlocks) >> 1); } } void CMemBlockManagerMt::FreeSpace() { Semaphore.Close(); CMemBlockManager::FreeSpace(); } void *CMemBlockManagerMt::AllocateBlock() { // Semaphore.Lock(); NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); return CMemBlockManager::AllocateBlock(); } void CMemBlockManagerMt::FreeBlock(void *p, bool lockMode) { if (p == 0) return; { NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); CMemBlockManager::FreeBlock(p); } if (lockMode) Semaphore.Release(); } void CMemBlocks::Free(CMemBlockManagerMt *manager) { while(Blocks.Size() > 0) { manager->FreeBlock(Blocks.Back()); Blocks.DeleteBack(); } TotalSize = 0; } void CMemBlocks::FreeOpt(CMemBlockManagerMt *manager) { Free(manager); Blocks.Free(); // to reduce memory usage } HRESULT CMemBlocks::WriteToStream(size_t blockSize, ISequentialOutStream *outStream) const { UInt64 totalSize = TotalSize; for (int blockIndex = 0; totalSize > 0; blockIndex++) { UInt32 curSize = (UInt32)blockSize; if (totalSize < curSize) curSize = (UInt32)totalSize; UInt32 processedSize; if (blockIndex >= Blocks.Size()) return E_FAIL; RINOK(WriteStream(outStream, Blocks[blockIndex], curSize, &processedSize)); if (processedSize != curSize) return E_FAIL; totalSize -= processedSize; } return S_OK; } void CMemLockBlocks::FreeBlock(int index, CMemBlockManagerMt *memManager) { memManager->FreeBlock(Blocks[index], LockMode); Blocks[index] = 0; } void CMemLockBlocks::Free(CMemBlockManagerMt *memManager) { while (Blocks.Size() > 0) { FreeBlock(Blocks.Size() - 1, memManager); Blocks.DeleteBack(); } TotalSize = 0; } bool CMemLockBlocks::SwitchToNoLockMode(CMemBlockManagerMt *memManager) { if (LockMode) { if (Blocks.Size() > 0) if (!memManager->ReleaseLockedBlocks(Blocks.Size())) return false; LockMode = false; } return true; } void CMemLockBlocks::Detach(CMemLockBlocks &blocks, CMemBlockManagerMt *memManager) { blocks.Free(memManager); blocks.LockMode = LockMode; UInt64 totalSize = 0; size_t blockSize = memManager->GetBlockSize(); for (int i = 0; i < Blocks.Size(); i++) { if (totalSize < TotalSize) blocks.Blocks.Add(Blocks[i]); else FreeBlock(i, memManager); Blocks[i] = 0; totalSize += blockSize; } blocks.TotalSize = TotalSize; Free(memManager); }