rlm@1
|
1 // MemBlocks.cpp
|
rlm@1
|
2
|
rlm@1
|
3 #include "StdAfx.h"
|
rlm@1
|
4
|
rlm@1
|
5 #include "Common/MyCom.h"
|
rlm@1
|
6
|
rlm@1
|
7 #include "StreamUtils.h"
|
rlm@1
|
8 #include "MemBlocks.h"
|
rlm@1
|
9
|
rlm@1
|
10 bool CMemBlockManager::AllocateSpace(size_t numBlocks)
|
rlm@1
|
11 {
|
rlm@1
|
12 FreeSpace();
|
rlm@1
|
13 if (_blockSize < sizeof(void *) || numBlocks < 1)
|
rlm@1
|
14 return false;
|
rlm@1
|
15 size_t totalSize = numBlocks * _blockSize;
|
rlm@1
|
16 if (totalSize / _blockSize != numBlocks)
|
rlm@1
|
17 return false;
|
rlm@1
|
18 _data = ::MidAlloc(totalSize);
|
rlm@1
|
19 if (_data == 0)
|
rlm@1
|
20 return false;
|
rlm@1
|
21 Byte *p = (Byte *)_data;
|
rlm@1
|
22 for (size_t i = 0; i + 1 < numBlocks; i++, p += _blockSize)
|
rlm@1
|
23 *(Byte **)p = (p + _blockSize);
|
rlm@1
|
24 *(Byte **)p = 0;
|
rlm@1
|
25 _headFree = _data;
|
rlm@1
|
26 return true;
|
rlm@1
|
27 }
|
rlm@1
|
28
|
rlm@1
|
29 void CMemBlockManager::FreeSpace()
|
rlm@1
|
30 {
|
rlm@1
|
31 ::MidFree(_data);
|
rlm@1
|
32 _data = 0;
|
rlm@1
|
33 _headFree= 0;
|
rlm@1
|
34 }
|
rlm@1
|
35
|
rlm@1
|
36 void *CMemBlockManager::AllocateBlock()
|
rlm@1
|
37 {
|
rlm@1
|
38 if (_headFree == 0)
|
rlm@1
|
39 return 0;
|
rlm@1
|
40 void *p = _headFree;
|
rlm@1
|
41 _headFree = *(void **)_headFree;
|
rlm@1
|
42 return p;
|
rlm@1
|
43 }
|
rlm@1
|
44
|
rlm@1
|
45 void CMemBlockManager::FreeBlock(void *p)
|
rlm@1
|
46 {
|
rlm@1
|
47 if (p == 0)
|
rlm@1
|
48 return;
|
rlm@1
|
49 *(void **)p = _headFree;
|
rlm@1
|
50 _headFree = p;
|
rlm@1
|
51 }
|
rlm@1
|
52
|
rlm@1
|
53
|
rlm@1
|
54 HRes CMemBlockManagerMt::AllocateSpace(size_t numBlocks, size_t numNoLockBlocks)
|
rlm@1
|
55 {
|
rlm@1
|
56 if (numNoLockBlocks > numBlocks)
|
rlm@1
|
57 return E_INVALIDARG;
|
rlm@1
|
58 if (!CMemBlockManager::AllocateSpace(numBlocks))
|
rlm@1
|
59 return E_OUTOFMEMORY;
|
rlm@1
|
60 size_t numLockBlocks = numBlocks - numNoLockBlocks;
|
rlm@1
|
61 Semaphore.Close();
|
rlm@1
|
62 return Semaphore.Create((LONG)numLockBlocks, (LONG)numLockBlocks);
|
rlm@1
|
63 }
|
rlm@1
|
64
|
rlm@1
|
65 HRes CMemBlockManagerMt::AllocateSpaceAlways(size_t desiredNumberOfBlocks, size_t numNoLockBlocks)
|
rlm@1
|
66 {
|
rlm@1
|
67 if (numNoLockBlocks > desiredNumberOfBlocks)
|
rlm@1
|
68 return E_INVALIDARG;
|
rlm@1
|
69 for (;;)
|
rlm@1
|
70 {
|
rlm@1
|
71 if (AllocateSpace(desiredNumberOfBlocks, numNoLockBlocks) == 0)
|
rlm@1
|
72 return 0;
|
rlm@1
|
73 if (desiredNumberOfBlocks == numNoLockBlocks)
|
rlm@1
|
74 return E_OUTOFMEMORY;
|
rlm@1
|
75 desiredNumberOfBlocks = numNoLockBlocks + ((desiredNumberOfBlocks - numNoLockBlocks) >> 1);
|
rlm@1
|
76 }
|
rlm@1
|
77 }
|
rlm@1
|
78
|
rlm@1
|
79 void CMemBlockManagerMt::FreeSpace()
|
rlm@1
|
80 {
|
rlm@1
|
81 Semaphore.Close();
|
rlm@1
|
82 CMemBlockManager::FreeSpace();
|
rlm@1
|
83 }
|
rlm@1
|
84
|
rlm@1
|
85 void *CMemBlockManagerMt::AllocateBlock()
|
rlm@1
|
86 {
|
rlm@1
|
87 // Semaphore.Lock();
|
rlm@1
|
88 NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection);
|
rlm@1
|
89 return CMemBlockManager::AllocateBlock();
|
rlm@1
|
90 }
|
rlm@1
|
91
|
rlm@1
|
92 void CMemBlockManagerMt::FreeBlock(void *p, bool lockMode)
|
rlm@1
|
93 {
|
rlm@1
|
94 if (p == 0)
|
rlm@1
|
95 return;
|
rlm@1
|
96 {
|
rlm@1
|
97 NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection);
|
rlm@1
|
98 CMemBlockManager::FreeBlock(p);
|
rlm@1
|
99 }
|
rlm@1
|
100 if (lockMode)
|
rlm@1
|
101 Semaphore.Release();
|
rlm@1
|
102 }
|
rlm@1
|
103
|
rlm@1
|
104 void CMemBlocks::Free(CMemBlockManagerMt *manager)
|
rlm@1
|
105 {
|
rlm@1
|
106 while(Blocks.Size() > 0)
|
rlm@1
|
107 {
|
rlm@1
|
108 manager->FreeBlock(Blocks.Back());
|
rlm@1
|
109 Blocks.DeleteBack();
|
rlm@1
|
110 }
|
rlm@1
|
111 TotalSize = 0;
|
rlm@1
|
112 }
|
rlm@1
|
113
|
rlm@1
|
114 void CMemBlocks::FreeOpt(CMemBlockManagerMt *manager)
|
rlm@1
|
115 {
|
rlm@1
|
116 Free(manager);
|
rlm@1
|
117 Blocks.ClearAndFree();
|
rlm@1
|
118 }
|
rlm@1
|
119
|
rlm@1
|
120 HRESULT CMemBlocks::WriteToStream(size_t blockSize, ISequentialOutStream *outStream) const
|
rlm@1
|
121 {
|
rlm@1
|
122 UInt64 totalSize = TotalSize;
|
rlm@1
|
123 for (int blockIndex = 0; totalSize > 0; blockIndex++)
|
rlm@1
|
124 {
|
rlm@1
|
125 UInt32 curSize = (UInt32)blockSize;
|
rlm@1
|
126 if (totalSize < curSize)
|
rlm@1
|
127 curSize = (UInt32)totalSize;
|
rlm@1
|
128 if (blockIndex >= Blocks.Size())
|
rlm@1
|
129 return E_FAIL;
|
rlm@1
|
130 RINOK(WriteStream(outStream, Blocks[blockIndex], curSize));
|
rlm@1
|
131 totalSize -= curSize;
|
rlm@1
|
132 }
|
rlm@1
|
133 return S_OK;
|
rlm@1
|
134 }
|
rlm@1
|
135
|
rlm@1
|
136
|
rlm@1
|
137 void CMemLockBlocks::FreeBlock(int index, CMemBlockManagerMt *memManager)
|
rlm@1
|
138 {
|
rlm@1
|
139 memManager->FreeBlock(Blocks[index], LockMode);
|
rlm@1
|
140 Blocks[index] = 0;
|
rlm@1
|
141 }
|
rlm@1
|
142
|
rlm@1
|
143 void CMemLockBlocks::Free(CMemBlockManagerMt *memManager)
|
rlm@1
|
144 {
|
rlm@1
|
145 while (Blocks.Size() > 0)
|
rlm@1
|
146 {
|
rlm@1
|
147 FreeBlock(Blocks.Size() - 1, memManager);
|
rlm@1
|
148 Blocks.DeleteBack();
|
rlm@1
|
149 }
|
rlm@1
|
150 TotalSize = 0;
|
rlm@1
|
151 }
|
rlm@1
|
152
|
rlm@1
|
153 HRes CMemLockBlocks::SwitchToNoLockMode(CMemBlockManagerMt *memManager)
|
rlm@1
|
154 {
|
rlm@1
|
155 if (LockMode)
|
rlm@1
|
156 {
|
rlm@1
|
157 if (Blocks.Size() > 0)
|
rlm@1
|
158 {
|
rlm@1
|
159 RINOK(memManager->ReleaseLockedBlocks(Blocks.Size()));
|
rlm@1
|
160 }
|
rlm@1
|
161 LockMode = false;
|
rlm@1
|
162 }
|
rlm@1
|
163 return 0;
|
rlm@1
|
164 }
|
rlm@1
|
165
|
rlm@1
|
166 void CMemLockBlocks::Detach(CMemLockBlocks &blocks, CMemBlockManagerMt *memManager)
|
rlm@1
|
167 {
|
rlm@1
|
168 blocks.Free(memManager);
|
rlm@1
|
169 blocks.LockMode = LockMode;
|
rlm@1
|
170 UInt64 totalSize = 0;
|
rlm@1
|
171 size_t blockSize = memManager->GetBlockSize();
|
rlm@1
|
172 for (int i = 0; i < Blocks.Size(); i++)
|
rlm@1
|
173 {
|
rlm@1
|
174 if (totalSize < TotalSize)
|
rlm@1
|
175 blocks.Blocks.Add(Blocks[i]);
|
rlm@1
|
176 else
|
rlm@1
|
177 FreeBlock(i, memManager);
|
rlm@1
|
178 Blocks[i] = 0;
|
rlm@1
|
179 totalSize += blockSize;
|
rlm@1
|
180 }
|
rlm@1
|
181 blocks.TotalSize = TotalSize;
|
rlm@1
|
182 Free(memManager);
|
rlm@1
|
183 }
|