0022650: Exception in Primitive Array during Redisplay of Presentable Object
[occt.git] / src / NCollection / NCollection_IncAllocator.cxx
CommitLineData
7fd59977 1// File: NCollection_IncAllocator.cxx
2// Created: 12.04.02 21:16:26
3// Author: Alexander GRIGORIEV
4// Copyright: Open Cascade 2002
5
6#include <NCollection_IncAllocator.hxx>
23be7421
M
7#include <NCollection_DataMap.hxx>
8#include <NCollection_Map.hxx>
9#include <Standard_Mutex.hxx>
7fd59977 10#include <Standard_OutOfMemory.hxx>
11#include <stdio.h>
12
13IMPLEMENT_STANDARD_HANDLE (NCollection_IncAllocator,NCollection_BaseAllocator)
14IMPLEMENT_STANDARD_RTTIEXT (NCollection_IncAllocator,NCollection_BaseAllocator)
15
16#define IMEM_SIZE(_size) ((((_size) - 1)/sizeof(aligned_t)) + 1)
17#define IMEM_FREE(p_bl) ((unsigned int)(p_bl->p_end_block - p_bl->p_free_space))
18#define IMEM_ALIGN(_addr) (sizeof(aligned_t)* IMEM_SIZE((unsigned long)(_addr)))
19
20#define MaxLookup 16
21
23be7421
M
22static Standard_Boolean IS_DEBUG = Standard_False;
23
24//=======================================================================
25/**
26 * Static data map (address -> AllocatorID)
27 */
28//=======================================================================
29static NCollection_DataMap<Standard_Address, Standard_Size>& StorageIDMap()
30{
31 static NCollection_DataMap<Standard_Address, Standard_Size> TheMap;
32 return TheMap;
33}
34
35//=======================================================================
36/**
37 * Static map (AllocatorID)
38 */
39//=======================================================================
40static NCollection_Map<Standard_Size>& StorageIDSet()
41{
42 static NCollection_Map<Standard_Size> TheMap;
43 return TheMap;
44}
45
46//=======================================================================
47//function : IncAllocator_SetDebugFlag
48//purpose : Turn on/off debugging of memory allocation
49//=======================================================================
50
51Standard_EXPORT void IncAllocator_SetDebugFlag(const Standard_Boolean theDebug)
52{
53 IS_DEBUG = theDebug;
54}
55
56//=======================================================================
57/**
58 * Static value of the current allocation ID. It provides unique
59 * numbering of allocators.
60 */
61//=======================================================================
62static Standard_Size CurrentID = 0;
63static Standard_Size CATCH_ID = 0;
64
65//=======================================================================
66//function : Debug_Create
67//purpose : Store the allocator address in the internal maps
68//=======================================================================
69
70static void Debug_Create(Standard_Address theAlloc)
71{
72 static Standard_Mutex aMutex;
73 Standard_Boolean isReentrant = Standard::IsReentrant();
74 if (isReentrant)
75 aMutex.Lock();
76 StorageIDMap().Bind(theAlloc, ++CurrentID);
77 StorageIDSet().Add(CurrentID);
78 if (isReentrant)
79 aMutex.Unlock();
80 if (CurrentID == CATCH_ID)
81 {
82 // Place for break point for creation of investigated allocator
83 int a = 1;
84 }
85}
86
87//=======================================================================
88//function : Debug_Destroy
89//purpose : Forget the allocator address from the internal maps
90//=======================================================================
91
92static void Debug_Destroy(Standard_Address theAlloc)
93{
94 static Standard_Mutex aMutex;
95 Standard_Boolean isReentrant = Standard::IsReentrant();
96 if (isReentrant)
97 aMutex.Lock();
98 if (StorageIDMap().IsBound(theAlloc))
99 {
100 Standard_Size anID = StorageIDMap()(theAlloc);
101 StorageIDSet().Remove(anID);
102 StorageIDMap().UnBind(theAlloc);
103 }
104 if (isReentrant)
105 aMutex.Unlock();
106}
107
108//=======================================================================
109//function : IncAllocator_PrintAlive
110//purpose : Outputs the alive numbers to the file inc_alive.d
111//=======================================================================
112
113Standard_EXPORT void IncAllocator_PrintAlive()
114{
115 if (!StorageIDSet().IsEmpty())
116 {
117 FILE * ff = fopen("inc_alive.d", "wt");
118 if (ff == NULL)
119 {
120 cout << "failure writing file inc_alive.d" << endl;
121 }
122 else
123 {
124 fprintf(ff, "Alive IncAllocators (number, size in Kb)\n");
125 NCollection_DataMap<Standard_Address, Standard_Size>::Iterator
126 itMap(StorageIDMap());
127 Standard_Size aTotSize = 0;
128 Standard_Integer nbAlloc = 0;
129 for (; itMap.More(); itMap.Next())
130 {
131 NCollection_IncAllocator* anAlloc =
132 static_cast<NCollection_IncAllocator*>(itMap.Key());
133 Standard_Size anID = itMap.Value();
134 Standard_Size aSize = anAlloc->GetMemSize();
135 aTotSize += aSize;
136 nbAlloc++;
137 fprintf(ff, "%-8d %8.1f\n", anID, double(aSize)/1024);
138 }
139 fprintf(ff, "Total:\n%-8d %8.1f\n", nbAlloc, double(aTotSize)/1024);
140 fclose(ff);
141 }
142 }
143}
144
7fd59977 145//=======================================================================
146//function : NCollection_IncAllocator()
147//purpose : Constructor
148//=======================================================================
149
150NCollection_IncAllocator::NCollection_IncAllocator (const size_t theBlockSize)
151{
152#ifdef ALLOC_TRACK_USAGE
153 printf ("\n..NCollection_IncAllocator: Created (%x)\n",this);
154#endif
23be7421
M
155#ifdef DEB
156 if (IS_DEBUG)
157 Debug_Create(this);
158#endif
7fd59977 159 const size_t aSize = IMEM_SIZE(sizeof(IBlock)) +
160 IMEM_SIZE((theBlockSize > 2*sizeof(IBlock)) ? theBlockSize : 24600);
161 IBlock * const aBlock = (IBlock *) malloc (aSize * sizeof(aligned_t));
162 myFirstBlock = aBlock;
163 mySize = aSize;
23be7421 164 myMemSize = aSize * sizeof(aligned_t);
7fd59977 165 if (aBlock == NULL)
166 Standard_OutOfMemory::Raise("NCollection_IncAllocator: out of memory");
167 aBlock -> p_free_space = (aligned_t *) IMEM_ALIGN (&aBlock[1]);
168 aBlock -> p_end_block = ((aligned_t *) aBlock) + aSize;
169 aBlock -> p_next = NULL;
170}
171
172//=======================================================================
173//function : ~NCollection_IncAllocator
174//purpose : Destructor
175//=======================================================================
176
177NCollection_IncAllocator::~NCollection_IncAllocator ()
178{
23be7421
M
179#ifdef DEB
180 if (IS_DEBUG)
181 Debug_Destroy(this);
182#endif
7fd59977 183 Clean();
184 free (myFirstBlock);
185}
186
187//=======================================================================
188//function : Allocate
189//purpose : allocate a memory
190//remark : returns NULL if allocation fails
191//=======================================================================
192
193void * NCollection_IncAllocator::Allocate (const size_t aSize)
194{
195 aligned_t * aResult = NULL;
196 const size_t cSize = aSize ? IMEM_SIZE(aSize) : 0;
197
198 if (cSize > mySize) {
199 /* If the requested size exceeds normal allocation size, allocate
200 a separate block and place it as the head of the list */
201 aResult = (aligned_t *) allocateNewBlock (cSize+1);
202 if (aResult)
203 myFirstBlock -> p_free_space = myFirstBlock -> p_end_block;
204 } else
205 if (cSize <= IMEM_FREE(myFirstBlock)) {
206 /* If the requested size fits into the free space in the 1st block */
207 aResult = myFirstBlock -> allocateInBlock (cSize);
208 } else {
209 /* Search for a block in the list with enough free space */
210 int aMaxLookup = MaxLookup; /* limit the number of blocks to query */
211 IBlock * aCurrentBlock = myFirstBlock -> p_next;
212 while (aCurrentBlock && aMaxLookup--) {
213 if (cSize <= IMEM_FREE(aCurrentBlock)) {
214 aResult = aCurrentBlock -> allocateInBlock (cSize);
215 break;
216 }
217 aCurrentBlock = aCurrentBlock -> p_next;
218 }
219 if (aResult == NULL) {
220 /* There is no available block with enough free space. Create a new
221 one and place it in the head of the list */
222 aResult = (aligned_t *) allocateNewBlock (mySize);
223 if (aResult)
224 myFirstBlock -> p_free_space = aResult + cSize;
225 }
226 }
227 return aResult;
228}
229
230//=======================================================================
231//function : Reallocate
232//purpose :
233//=======================================================================
234
235void * NCollection_IncAllocator::Reallocate (void * theAddress,
236 const size_t oldSize,
237 const size_t newSize)
238{
239// Check that the dummy parameters are OK
240 if (theAddress == NULL || oldSize == 0)
241 return Allocate (newSize);
242 const size_t cOldSize = IMEM_SIZE(oldSize);
243 const size_t cNewSize = newSize ? IMEM_SIZE(newSize) : 0;
244 aligned_t * anAddress = (aligned_t *) theAddress;
245
246// We check only the LAST allocation to do the real extension/contraction
247 if (anAddress + cOldSize == myFirstBlock -> p_free_space) {
248 myFirstBlock -> p_free_space = anAddress;
249// If the new size fits into the memory block => OK
250// This also includes any case of contraction
251 if (cNewSize <= IMEM_FREE(myFirstBlock)) {
252 myFirstBlock -> p_free_space += cNewSize;
253 return anAddress;
254 }
255 }
256// In case of contraction of non-terminating allocation, do nothing
257 else if (cOldSize >= cNewSize)
258 return anAddress;
259// Extension of non-terminated allocation if there is enough room in the
260// current memory block
261 if (cNewSize <= IMEM_FREE(myFirstBlock)) {
262 aligned_t * aResult = myFirstBlock -> allocateInBlock (cNewSize);
263 if (aResult)
264 for (unsigned i = 0; i < cOldSize; i++)
265 aResult[i] = anAddress[i];
266 return aResult;
267 }
268
269// This is either of the cases:
270// - extension of non-terminating allocation, or
271// - extension of terminating allocation when the new size is too big
272// In both cases create a new memory block, allocate memory and copy there
273// the reallocated memory.
274 aligned_t * aResult = (aligned_t *) allocateNewBlock (mySize);
275 if (aResult) {
276 myFirstBlock -> p_free_space = aResult + cNewSize;
277 for (unsigned i = 0; i < cOldSize; i++)
278 aResult[i] = anAddress[i];
279 }
280 return aResult;
281}
282
283//=======================================================================
284//function : Free
285//purpose :
286//=======================================================================
287
288void NCollection_IncAllocator::Free (void *)
289{}
290
291//=======================================================================
292//function : Clean
293//purpose :
294//=======================================================================
295
296void NCollection_IncAllocator::Clean ()
297{
298#ifdef ALLOC_TRACK_USAGE
299 printf ("\n..NCollection_IncAllocator: Memory size to clean:%8.1f kB (%x)\n",
300 double(GetMemSize())/1024, this);
301#endif
302 IBlock * aBlock = myFirstBlock;
303 if (aBlock) {
304 aBlock -> p_free_space = (aligned_t *) &aBlock[1];
305 aBlock = aBlock -> p_next;
306 while (aBlock) {
307 IBlock * aNext = aBlock -> p_next;
308 free (aBlock);
309 aBlock = aNext;
310 }
311 myFirstBlock -> p_next = NULL;
312 }
23be7421 313 myMemSize = 0;
7fd59977 314}
315
316//=======================================================================
317//function : Reset
318//purpose :
319//=======================================================================
320
321void NCollection_IncAllocator::Reset (const Standard_Boolean doReleaseMem)
322{
323 if (doReleaseMem)
324 Clean();
325 else {
326 Standard_Integer aBlockCount(0);
327 IBlock * aBlock = myFirstBlock;
328 while (aBlock)
329 if (aBlockCount++ < MaxLookup) {
330 aBlock -> p_free_space = (aligned_t *) &aBlock[1];
331 if (aBlockCount < MaxLookup)
332 aBlock = aBlock -> p_next;
333 else {
334 IBlock * aNext = aBlock -> p_next;
335 aBlock -> p_next = NULL;
336 aBlock = aNext;
337 }
338 } else {
339 IBlock * aNext = aBlock -> p_next;
23be7421 340 myMemSize -= (aBlock -> p_end_block - (aligned_t *) aBlock) * sizeof (aligned_t);
7fd59977 341 free (aBlock);
342 aBlock = aNext;
343 }
344 }
345}
346
347//=======================================================================
348//function : GetMemSize
349//purpose : diagnostic utility
350//=======================================================================
351
352size_t NCollection_IncAllocator::GetMemSize () const
353{
23be7421
M
354// size_t aResult = 0;
355// IBlock * aBlock = myFirstBlock;
356// while (aBlock) {
357// aResult += (aBlock -> p_end_block - (aligned_t *) aBlock);
358// aBlock = aBlock -> p_next;
359// }
360// return aResult * sizeof (aligned_t);
361 return myMemSize;
7fd59977 362}
363
364//=======================================================================
365//function : allocateNewBlock
366//purpose :
367//=======================================================================
368
369void * NCollection_IncAllocator::allocateNewBlock (const size_t cSize)
370{
371 aligned_t * aResult = 0L;
372 const size_t aSz = cSize + IMEM_SIZE(sizeof(IBlock));
373 IBlock * aBlock = (IBlock *) malloc (aSz * sizeof(aligned_t));
374 if (aBlock) {
375 aBlock -> p_end_block = ((aligned_t *)aBlock) + aSz;
376 aBlock -> p_next = myFirstBlock;
377 myFirstBlock = aBlock;
378 aResult = (aligned_t *) IMEM_ALIGN(&aBlock[1]);
23be7421 379 myMemSize += aSz * sizeof(aligned_t);
7fd59977 380 }
381 else
382 Standard_OutOfMemory::Raise("NCollection_IncAllocator: out of memory");
383 return aResult;
384}