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