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