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