Scippy

SCIP

Solving Constraint Integer Programs

memory.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the library */
4 /* BMS --- Block Memory Shell */
5 /* */
6 /* Copyright (C) 2002-2014 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* BMS is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with BMS; see the file COPYING. If not email to achterberg@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file memory.c
17  * @brief memory allocation routines
18  * @author Tobias Achterberg
19  */
20 
21 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <assert.h>
26 #include <string.h>
27 
28 #ifdef WITH_SCIPDEF
29 #include "scip/def.h"
30 #include "scip/pub_message.h"
31 #endif
32 
33 #include "blockmemshell/memory.h"
34 
35 /*#define CHECKMEM*/
36 
37 
38 /* if we are included in SCIP, use SCIP's message output methods */
39 #ifdef SCIPdebugMessage
40 #define debugMessage SCIPdebugMessage
41 #define errorMessage SCIPerrorMessage
42 #else
43 #define debugMessage while( FALSE ) printf
44 #define errorMessage printf
45 #define printErrorHeader(f,l) printf("[%s:%d] ERROR: ", f, l)
46 #define printError printf
47 #endif
48 
49 #define warningMessage printf
50 #define printInfo printf
51 
52 /* define some macros (if not already defined) */
53 #ifndef FALSE
54 #define FALSE 0
55 #define TRUE 1
56 #endif
57 #ifndef MAX
58 #define MAX(x,y) ((x) >= (y) ? (x) : (y))
59 #define MIN(x,y) ((x) <= (y) ? (x) : (y))
60 #endif
61 
62 
63 
64 
65 /*************************************************************************************
66  * Standard Memory Management
67  *
68  * In debug mode, these methods extend malloc() and free() by logging all currently
69  * allocated memory elements in an allocation list. This can be used as a simple leak
70  * detection.
71  *************************************************************************************/
72 #if !defined(NDEBUG) && defined(NPARASCIP)
73 
74 typedef struct Memlist MEMLIST; /**< memory list for debugging purposes */
75 
76 /** memory list for debugging purposes */
77 struct Memlist
78 {
79  const void* ptr; /**< pointer to allocated memory */
80  size_t size; /**< size of memory element */
81  char* filename; /**< source file where the allocation was performed */
82  int line; /**< line number in source file where the allocation was performed */
83  MEMLIST* next; /**< next entry in the memory list */
84 };
85 
86 static MEMLIST* memlist = NULL; /**< global memory list for debugging purposes */
87 static long long memused = 0; /**< number of allocated bytes */
88 
89 #ifdef CHECKMEM
90 /** checks, whether the number of allocated bytes match the entries in the memory list */
91 static
92 void checkMemlist(
93  void
94  )
95 {
96  MEMLIST* list = memlist;
97  long long used = 0;
98 
99  while( list != NULL )
100  {
101  used += list->size;
102  list = list->next;
103  }
104  assert(used == memused);
105 }
106 #else
107 #define checkMemlist() /**/
108 #endif
109 
110 /** adds entry to list of allocated memory */
111 static
112 void addMemlistEntry(
113  const void* ptr, /**< pointer to allocated memory */
114  size_t size, /**< size of memory element */
115  const char* filename, /**< source file where the allocation was performed */
116  int line /**< line number in source file where the allocation was performed */
117  )
118 {
119  MEMLIST* list;
120 
121  assert(ptr != NULL && size > 0);
122 
123  list = (MEMLIST*)malloc(sizeof(MEMLIST));
124  assert(list != NULL);
125 
126  list->ptr = ptr;
127  list->size = size;
128  list->filename = strdup(filename);
129  assert(list->filename != NULL);
130  list->line = line;
131  list->next = memlist;
132  memlist = list;
133  memused += (long long)size;
134  checkMemlist();
135 }
136 
137 /** removes entry from the list of allocated memory */
138 static
139 void removeMemlistEntry(
140  const void* ptr, /**< pointer to allocated memory */
141  const char* filename, /**< source file where the deallocation was performed */
142  int line /**< line number in source file where the deallocation was performed */
143  )
144 {
145  MEMLIST* list;
146  MEMLIST** listptr;
147 
148  assert(ptr != NULL);
149 
150  list = memlist;
151  listptr = &memlist;
152  while( list != NULL && ptr != list->ptr )
153  {
154  listptr = &(list->next);
155  list = list->next;
156  }
157  if( list != NULL )
158  {
159  assert(ptr == list->ptr);
160 
161  *listptr = list->next;
162  memused -= (long long)list->size;
163  free(list->filename);
164  free(list);
165  }
166  else
167  {
168  printErrorHeader(filename, line);
169  printError("Tried to free unknown pointer <%p>\n", ptr);
170  }
171  checkMemlist();
172 }
173 
174 /** returns the size of an allocated memory element */
176  const void* ptr /**< pointer to allocated memory */
177  )
178 {
179  MEMLIST* list;
180 
181  list = memlist;
182  while( list != NULL && ptr != list->ptr )
183  list = list->next;
184  if( list != NULL )
185  return list->size;
186  else
187  return 0;
188 }
189 
190 /** outputs information about currently allocated memory to the screen */
192  void
193  )
194 {
195  MEMLIST* list;
196  long long used;
197 
198  printInfo("Allocated memory:\n");
199  list = memlist;
200  used = 0;
201  while( list != NULL )
202  {
203  printInfo("%12p %8lld %s:%d\n", list->ptr, (long long)(list->size), list->filename, list->line);
204  used += (long long)list->size;
205  list = list->next;
206  }
207  printInfo("Total: %8lld\n", memused);
208  if( used != memused )
209  {
210  errorMessage("Used memory in list sums up to %lld instead of %lld\n", used, memused);
211  }
212  checkMemlist();
213 }
214 
215 /** displays a warning message on the screen, if allocated memory exists */
217  void
218  )
219 {
220  if( memlist != NULL || memused > 0 )
221  {
222  warningMessage("Memory list not empty.\n");
224  }
225 }
226 
227 /** returns total number of allocated bytes */
228 long long BMSgetMemoryUsed_call(
229  void
230  )
231 {
232  return memused;
233 }
234 
235 #else
236 
237 /* these methods are implemented even in optimized mode, such that a program, that includes memory.h in debug mode
238  * but links the optimized version compiles
239  */
240 
241 /** returns the size of an allocated memory element */
243  const void* ptr /**< pointer to allocated memory */
244  )
245 {
246  return 0;
247 }
248 
249 /** outputs information about currently allocated memory to the screen */
251  void
252  )
253 {
254 #ifdef NPARASCIP
255  printInfo("optimized version of memory shell linked - no memory diagnostics available\n");
256 #endif
257 }
258 
259 /** displays a warning message on the screen, if allocated memory exists */
261  void
262  )
263 {
264 #ifdef NPARASCIP
265  printInfo("optimized version of memory shell linked - no memory leakage check available\n");
266 #endif
267 }
268 
269 /** returns total number of allocated bytes */
271  void
272  )
273 {
274  return 0;
275 }
276 
277 #endif
278 
279 /** allocates memory and initializes it with 0; returns NULL if memory allocation failed */
281  size_t num, /**< number of memory element to allocate */
282  size_t size, /**< size of one memory element to allocate */
283  const char* filename, /**< source file where the allocation is performed */
284  int line /**< line number in source file where the allocation is performed */
285  )
286 {
287  void* ptr;
288 
289  debugMessage("calloc %lld elements of %lld bytes [%s:%d]\n", (long long) num, (long long)size, filename, line);
290 
291  num = MAX(num, 1);
292  size = MAX(size, 1);
293  ptr = calloc(num, size);
294 
295  if( ptr == NULL )
296  {
297  printErrorHeader(filename, line);
298  printError("Insufficient memory for allocation of %lld bytes\n", ((long long) num) * ((long long) size));
299  }
300 #if !defined(NDEBUG) && defined(NPARASCIP)
301  else
302  addMemlistEntry(ptr, num*size, filename, line);
303 #endif
304 
305  return ptr;
306 }
307 
308 /** allocates memory; returns NULL if memory allocation failed */
310  size_t size, /**< size of memory element to allocate */
311  const char* filename, /**< source file where the allocation is performed */
312  int line /**< line number in source file where the allocation is performed */
313  )
314 {
315  void* ptr;
316 
317  debugMessage("malloc %lld bytes [%s:%d]\n", (long long)size, filename, line);
318 
319  size = MAX(size, 1);
320  ptr = malloc(size);
321 
322  if( ptr == NULL )
323  {
324  printErrorHeader(filename, line);
325  printError("Insufficient memory for allocation of %lld bytes\n", (long long) size);
326  }
327 #if !defined(NDEBUG) && defined(NPARASCIP)
328  else
329  addMemlistEntry(ptr, size, filename, line);
330 #endif
331 
332  return ptr;
333 }
334 
335 /** allocates memory; returns NULL if memory allocation failed */
337  void* ptr, /**< pointer to memory to reallocate */
338  size_t size, /**< new size of memory element */
339  const char* filename, /**< source file where the reallocation is performed */
340  int line /**< line number in source file where the reallocation is performed */
341  )
342 {
343  void* newptr;
344 
345 #if !defined(NDEBUG) && defined(NPARASCIP)
346  if( ptr != NULL )
347  removeMemlistEntry(ptr, filename, line);
348 #endif
349 
350  size = MAX(size, 1);
351  newptr = realloc(ptr, size);
352 
353  if( newptr == NULL )
354  {
355  printErrorHeader(filename, line);
356  printError("Insufficient memory for reallocation of %lld bytes\n", (long long) size);
357  }
358 #if !defined(NDEBUG) && defined(NPARASCIP)
359  else
360  addMemlistEntry(newptr, size, filename, line);
361 #endif
362 
363  /* fprintf(stderr, "mem: %p %d\n", newptr, (int)size); */
364 
365  return newptr;
366 }
367 
368 /** clears a memory element (i.e. fills it with zeros) */
370  void* ptr, /**< pointer to memory element */
371  size_t size /**< size of memory element */
372  )
373 {
374  if( size > 0 )
375  {
376  assert(ptr != NULL);
377  memset(ptr, 0, size);
378  }
379 }
380 
381 /** copies the contents of one memory element into another memory element */
383  void* ptr, /**< pointer to target memory element */
384  const void* source, /**< pointer to source memory element */
385  size_t size /**< size of memory element to copy */
386  )
387 {
388  if( size > 0 )
389  {
390  assert(ptr != NULL);
391  assert(source != NULL);
392  memcpy(ptr, source, size);
393  }
394 }
395 
396 /** moves the contents of one memory element into another memory element, should be used if both elements overlap,
397  * otherwise BMScopyMemory is faster
398  */
400  void* ptr, /**< pointer to target memory element */
401  const void* source, /**< pointer to source memory element */
402  size_t size /**< size of memory element to copy */
403  )
404 {
405  if( size > 0 )
406  {
407  assert(ptr != NULL);
408  assert(source != NULL);
409  memmove(ptr, source, size);
410  }
411 }
412 
413 /** allocates memory and copies the contents of the given memory element into the new memory element */
415  const void* source, /**< pointer to source memory element */
416  size_t size, /**< size of memory element to copy */
417  const char* filename, /**< source file where the duplication is performed */
418  int line /**< line number in source file where the duplication is performed */
419  )
420 {
421  void* ptr;
422 
423  assert(source != NULL || size == 0);
424 
425  ptr = BMSallocMemory_call(size, filename, line);
426  if( ptr != NULL )
427  BMScopyMemory_call(ptr, source, size);
428 
429  return ptr;
430 }
431 
432 /** frees an allocated memory element */
434  void* ptr, /**< pointer to memory element */
435  const char* filename, /**< source file where the deallocation is performed */
436  int line /**< line number in source file where the deallocation is performed */
437  )
438 {
439  if( ptr != NULL )
440  {
441 #if !defined(NDEBUG) && defined(NPARASCIP)
442  removeMemlistEntry(ptr, filename, line);
443 #endif
444  free(ptr);
445  }
446  else
447  {
448  printErrorHeader(filename, line);
449  printError("Tried to free null pointer\n");
450  }
451 }
452 
453 
454 
455 
456 /********************************************************************
457  * Chunk Memory Management
458  *
459  * Efficient memory management for multiple objects of the same size
460  ********************************************************************/
461 
462 /*
463  * block memory methods for faster memory access
464  */
465 
466 #define CHUNKLENGTH_MIN 1024 /**< minimal size of a chunk (in bytes) */
467 #define CHUNKLENGTH_MAX 1048576 /**< maximal size of a chunk (in bytes) */
468 #define STORESIZE_MAX 8192 /**< maximal number of elements in one chunk */
469 #define GARBAGE_SIZE 256 /**< size of lazy free list to start garbage collection */
470 #define ALIGNMENT (sizeof(FREELIST)) /**< minimal alignment of chunks */
471 
472 typedef struct Freelist FREELIST; /**< linked list of free memory elements */
473 typedef struct Chunk CHUNK; /**< chunk of memory elements */
474 
475 /** linked list of free memory elements */
476 struct Freelist
477 {
478  FREELIST* next; /**< pointer to the next free element */
479 };
480 
481 /** chunk of memory elements */
482 struct Chunk
483 {
484  void* store; /**< data storage */
485  void* storeend; /**< points to the first byte in memory not belonging to the chunk */
486  FREELIST* eagerfree; /**< eager free list */
487  CHUNK* nexteager; /**< next chunk, that has a non-empty eager free list */
488  CHUNK* preveager; /**< previous chunk, that has a non-empty eager free list */
489  BMS_CHKMEM* chkmem; /**< chunk memory collection, this chunk belongs to */
490  int elemsize; /**< size of each element in the chunk */
491  int storesize; /**< number of elements in this chunk */
492  int eagerfreesize; /**< number of elements in the eager free list */
493  int arraypos; /**< position of chunk in the chunk header's chunkarray */
494 }; /* the chunk data structure must be aligned, because the storage is allocated directly behind the chunk header! */
495 
496 /** collection of memory chunks of the same element size */
497 struct BMS_ChkMem
498 {
499  FREELIST* lazyfree; /**< lazy free list of unused memory elements of all chunks of this chunk block */
500  CHUNK** chunks; /**< array with the chunks of the chunk header */
501  CHUNK* firsteager; /**< first chunk with a non-empty eager free list */
502  BMS_CHKMEM* nextchkmem; /**< next chunk block in the block memory's hash list */
503  int elemsize; /**< size of each memory element in the chunk memory */
504  int chunkssize; /**< size of the chunks array */
505  int nchunks; /**< number of chunks in this chunk block (used slots of the chunk array) */
506  int lastchunksize; /**< number of elements in the last allocated chunk */
507  int storesize; /**< total number of elements in this chunk block */
508  int lazyfreesize; /**< number of elements in the lazy free list of the chunk block */
509  int eagerfreesize; /**< total number of elements of all eager free lists of the block's chunks */
510  int initchunksize; /**< number of elements in the first chunk */
511  int garbagefactor; /**< garbage collector is called, if at least garbagefactor * avg. chunksize
512  * elements are free (-1: disable garbage collection) */
513 #ifndef NDEBUG
514  char* filename; /**< source file, where this chunk block was created */
515  int line; /**< source line, where this chunk block was created */
516  int ngarbagecalls; /**< number of times, the garbage collector was called */
517  int ngarbagefrees; /**< number of chunks, the garbage collector freed */
518 #endif
519 };
520 
521 
522 /** aligns the given byte size corresponding to the minimal alignment */
523 static
525  size_t* size /**< pointer to the size to align */
526  )
527 {
528  if( *size < ALIGNMENT )
529  *size = ALIGNMENT;
530  else
531  *size = ((*size + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT;
532 }
533 
534 /** aligns the given byte size corresponding to the minimal alignment for chunk and block memory */
536  size_t* size /**< pointer to the size to align */
537  )
538 {
539  assert(ALIGNMENT == sizeof(void*));
540  alignSize(size);
541 }
542 
543 /** checks whether the given size meets the alignment conditions for chunk and block memory */
545  size_t size /**< size to check for alignment */
546  )
547 {
548  assert(ALIGNMENT == sizeof(void*));
549  return( size >= ALIGNMENT && size % ALIGNMENT == 0 );
550 }
551 
552 #ifndef NDEBUG
553 /** checks, if the given pointer belongs to the given chunk */
554 static
556  const CHUNK* chunk, /**< memory chunk */
557  const void* ptr /**< pointer */
558  )
559 {
560  assert(chunk != NULL);
561  assert(chunk->store <= chunk->storeend);
562 
563  return (ptr >= (void*)(chunk->store) && ptr < (void*)(chunk->storeend));
564 }
565 #endif
566 
567 /** given a pointer, finds the chunk this pointer points to in the chunk array of the given chunk block;
568  * binary search is used;
569  * returns NULL if the pointer does not belong to the chunk block
570  */
571 static
573  const BMS_CHKMEM* chkmem, /**< chunk block */
574  const void* ptr /**< pointer */
575  )
576 {
577  CHUNK* chunk;
578  int left;
579  int right;
580  int middle;
581 
582  assert(chkmem != NULL);
583  assert(ptr != NULL);
584 
585  /* binary search for the chunk containing the ptr */
586  left = 0;
587  right = chkmem->nchunks-1;
588  while( left <= right )
589  {
590  middle = (left+right)/2;
591  assert(0 <= middle && middle < chkmem->nchunks);
592  chunk = chkmem->chunks[middle];
593  assert(chunk != NULL);
594  if( ptr < chunk->store )
595  right = middle-1;
596  else if( ptr >= chunk->storeend )
597  left = middle+1;
598  else
599  return chunk;
600  }
601 
602  /* ptr was not found in chunk */
603  return NULL;
604 }
605 
606 /** checks, if a pointer belongs to a chunk of the given chunk block */
607 static
609  const BMS_CHKMEM* chkmem, /**< chunk block */
610  const void* ptr /**< pointer */
611  )
612 {
613  assert(chkmem != NULL);
614 
615  return (findChunk(chkmem, ptr) != NULL);
616 }
617 
618 
619 
620 /*
621  * debugging methods
622  */
623 
624 #ifdef CHECKMEM
625 /** sanity check for a memory chunk */
626 static
627 void checkChunk(
628  const CHUNK* chunk /**< memory chunk */
629  )
630 {
631  FREELIST* eager;
632  int eagerfreesize;
633 
634  assert(chunk != NULL);
635  assert(chunk->store != NULL);
636  assert(chunk->storeend == (void*)((char*)(chunk->store) + chunk->elemsize * chunk->storesize));
637  assert(chunk->chkmem != NULL);
638  assert(chunk->chkmem->elemsize == chunk->elemsize);
639 
640  if( chunk->eagerfree == NULL )
641  assert(chunk->nexteager == NULL && chunk->preveager == NULL);
642  else if( chunk->preveager == NULL )
643  assert(chunk->chkmem->firsteager == chunk);
644 
645  if( chunk->nexteager != NULL )
646  assert(chunk->nexteager->preveager == chunk);
647  if( chunk->preveager != NULL )
648  assert(chunk->preveager->nexteager == chunk);
649 
650  eagerfreesize = 0;
651  eager = chunk->eagerfree;
652  while( eager != NULL )
653  {
654  assert(isPtrInChunk(chunk, eager));
655  eagerfreesize++;
656  eager = eager->next;
657  }
658  assert(chunk->eagerfreesize == eagerfreesize);
659 }
660 
661 /** sanity check for a chunk block */
662 static
663 void checkChkmem(
664  const BMS_CHKMEM* chkmem /**< chunk block */
665  )
666 {
667  CHUNK* chunk;
668  FREELIST* lazy;
669  int nchunks;
670  int storesize;
671  int lazyfreesize;
672  int eagerfreesize;
673  int i;
674 
675  assert(chkmem != NULL);
676  assert(chkmem->chunks != NULL || chkmem->chunkssize == 0);
677  assert(chkmem->nchunks <= chkmem->chunkssize);
678 
679  nchunks = 0;
680  storesize = 0;
681  lazyfreesize = 0;
682  eagerfreesize = 0;
683 
684  for( i = 0; i < chkmem->nchunks; ++i )
685  {
686  chunk = chkmem->chunks[i];
687  assert(chunk != NULL);
688 
689  checkChunk(chunk);
690  nchunks++;
691  storesize += chunk->storesize;
692  eagerfreesize += chunk->eagerfreesize;
693  }
694  assert(chkmem->nchunks == nchunks);
695  assert(chkmem->storesize == storesize);
696  assert(chkmem->eagerfreesize == eagerfreesize);
697 
698  assert((chkmem->eagerfreesize == 0) ^ (chkmem->firsteager != NULL));
699 
700  if( chkmem->firsteager != NULL )
701  assert(chkmem->firsteager->preveager == NULL);
702 
703  lazy = chkmem->lazyfree;
704  while( lazy != NULL )
705  {
706  chunk = findChunk(chkmem, lazy);
707  assert(chunk != NULL);
708  assert(chunk->chkmem == chkmem);
709  lazyfreesize++;
710  lazy = lazy->next;
711  }
712  assert(chkmem->lazyfreesize == lazyfreesize);
713 }
714 #else
715 #define checkChunk(chunk) /**/
716 #define checkChkmem(chkmem) /**/
717 #endif
718 
719 
720 /** links chunk to the block's chunk array, sort it by store pointer;
721  * returns TRUE if successful, FALSE otherwise
722  */
723 static
725  BMS_CHKMEM* chkmem, /**< chunk block */
726  CHUNK* chunk /**< memory chunk */
727  )
728 {
729  CHUNK* curchunk;
730  int left;
731  int right;
732  int middle;
733  int i;
734 
735  assert(chkmem != NULL);
736  assert(chkmem->nchunks <= chkmem->chunkssize);
737  assert(chunk != NULL);
738  assert(chunk->store != NULL);
739 
740  debugMessage("linking chunk %p to chunk block %p [elemsize:%d, %d chunks]\n",
741  (void*)chunk, (void*)chkmem, chkmem->elemsize, chkmem->nchunks);
742 
743  /* binary search for the position to insert the chunk */
744  left = -1;
745  right = chkmem->nchunks;
746  while( left < right-1 )
747  {
748  middle = (left+right)/2;
749  assert(0 <= middle && middle < chkmem->nchunks);
750  assert(left < middle && middle < right);
751  curchunk = chkmem->chunks[middle];
752  assert(curchunk != NULL);
753  if( chunk->store < curchunk->store )
754  right = middle;
755  else
756  {
757  assert(chunk->store >= curchunk->storeend);
758  left = middle;
759  }
760  }
761  assert(-1 <= left && left < chkmem->nchunks);
762  assert(0 <= right && right <= chkmem->nchunks);
763  assert(left+1 == right);
764  assert(left == -1 || chkmem->chunks[left]->storeend <= chunk->store);
765  assert(right == chkmem->nchunks || chunk->storeend <= chkmem->chunks[right]->store);
766 
767  /* ensure, that chunk array can store the additional chunk */
768  if( chkmem->nchunks == chkmem->chunkssize )
769  {
770  chkmem->chunkssize = 2*(chkmem->nchunks+1);
771  BMSreallocMemoryArray(&chkmem->chunks, chkmem->chunkssize);
772  if( chkmem->chunks == NULL )
773  return FALSE;
774  }
775  assert(chkmem->nchunks < chkmem->chunkssize);
776  assert(chkmem->chunks != NULL);
777 
778  /* move all chunks from 'right' to end one position to the right */
779  for( i = chkmem->nchunks; i > right; --i )
780  {
781  chkmem->chunks[i] = chkmem->chunks[i-1];
782  chkmem->chunks[i]->arraypos = i;
783  }
784 
785  /* insert chunk at position 'right' */
786  chunk->arraypos = right;
787  chkmem->chunks[right] = chunk;
788  chkmem->nchunks++;
789  chkmem->storesize += chunk->storesize;
790 
791  return TRUE;
792 }
793 
794 /** unlinks chunk from the chunk block's chunk list */
795 static
797  CHUNK* chunk /**< memory chunk */
798  )
799 {
800  BMS_CHKMEM* chkmem;
801  int i;
802 
803  assert(chunk != NULL);
804  assert(chunk->eagerfree == NULL);
805  assert(chunk->nexteager == NULL);
806  assert(chunk->preveager == NULL);
807 
808  chkmem = chunk->chkmem;
809  assert(chkmem != NULL);
810  assert(chkmem->elemsize == chunk->elemsize);
811  assert(0 <= chunk->arraypos && chunk->arraypos < chkmem->nchunks);
812  assert(chkmem->chunks[chunk->arraypos] == chunk);
813 
814  debugMessage("unlinking chunk %p from chunk block %p [elemsize:%d, %d chunks]\n",
815  (void*)chunk, (void*)chkmem, chkmem->elemsize, chkmem->nchunks);
816 
817  /* remove the chunk from the chunks of the chunk block */
818  for( i = chunk->arraypos; i < chkmem->nchunks-1; ++i )
819  {
820  chkmem->chunks[i] = chkmem->chunks[i+1];
821  chkmem->chunks[i]->arraypos = i;
822  }
823  chkmem->nchunks--;
824  chkmem->storesize -= chunk->storesize;
825 }
826 
827 /** links chunk to the chunk block's eager chunk list */
828 static
830  BMS_CHKMEM* chkmem, /**< chunk block */
831  CHUNK* chunk /**< memory chunk */
832  )
833 {
834  assert(chunk->chkmem == chkmem);
835  assert(chunk->nexteager == NULL);
836  assert(chunk->preveager == NULL);
837 
838  chunk->nexteager = chkmem->firsteager;
839  chunk->preveager = NULL;
840  if( chkmem->firsteager != NULL )
841  {
842  assert(chkmem->firsteager->preveager == NULL);
843  chkmem->firsteager->preveager = chunk;
844  }
845  chkmem->firsteager = chunk;
846 }
847 
848 /** unlinks chunk from the chunk block's eager chunk list */
849 static
851  CHUNK* chunk /**< memory chunk */
852  )
853 {
854  assert(chunk != NULL);
855  assert(chunk->eagerfreesize == 0 || chunk->eagerfreesize == chunk->storesize);
856 
857  if( chunk->nexteager != NULL )
858  chunk->nexteager->preveager = chunk->preveager;
859  if( chunk->preveager != NULL )
860  chunk->preveager->nexteager = chunk->nexteager;
861  else
862  {
863  assert(chunk->chkmem->firsteager == chunk);
864  chunk->chkmem->firsteager = chunk->nexteager;
865  }
866  chunk->nexteager = NULL;
867  chunk->preveager = NULL;
868  chunk->eagerfree = NULL;
869 }
870 
871 /** creates a new memory chunk in the given chunk block and adds memory elements to the lazy free list;
872  * returns TRUE if successful, FALSE otherwise
873  */
874 static
876  BMS_CHKMEM* chkmem /**< chunk block */
877  )
878 {
879  CHUNK *newchunk;
880  FREELIST *freelist;
881  int i;
882  int storesize;
883  int retval;
884 
885  assert(chkmem != NULL);
886 
887  debugMessage("creating new chunk in chunk block %p [elemsize: %d]\n", (void*)chkmem, chkmem->elemsize);
888 
889  /* calculate store size */
890  if( chkmem->nchunks == 0 )
891  storesize = chkmem->initchunksize;
892  else
893  storesize = 2 * chkmem->lastchunksize;
894  assert(storesize > 0);
895  storesize = MAX(storesize, CHUNKLENGTH_MIN / chkmem->elemsize);
896  storesize = MIN(storesize, CHUNKLENGTH_MAX / chkmem->elemsize);
897  storesize = MIN(storesize, STORESIZE_MAX);
898  storesize = MAX(storesize, 1);
899  chkmem->lastchunksize = storesize;
900 
901  /* create new chunk */
902  assert(BMSisAligned(sizeof(CHUNK)));
903  assert( chkmem->elemsize < INT_MAX / storesize );
904  assert( sizeof(CHUNK) < UINT_MAX - (size_t)(storesize * chkmem->elemsize) ); /*lint !e571 !e647*/
905  BMSallocMemorySize(&newchunk, sizeof(CHUNK) + storesize * chkmem->elemsize);
906  if( newchunk == NULL )
907  return FALSE;
908 
909  /* the store is allocated directly behind the chunk header */
910  newchunk->store = (void*) ((char*) newchunk + sizeof(CHUNK));
911  newchunk->storeend = (void*) ((char*) newchunk->store + storesize * chkmem->elemsize);
912  newchunk->eagerfree = NULL;
913  newchunk->nexteager = NULL;
914  newchunk->preveager = NULL;
915  newchunk->chkmem = chkmem;
916  newchunk->elemsize = chkmem->elemsize;
917  newchunk->storesize = storesize;
918  newchunk->eagerfreesize = 0;
919  newchunk->arraypos = -1;
920 
921  debugMessage("allocated new chunk %p: %d elements with size %lld\n",
922  (void*)newchunk, newchunk->storesize, (long long)(newchunk->elemsize));
923 
924  /* add new memory to the lazy free list */
925  for( i = 0; i < newchunk->storesize - 1; ++i )
926  {
927  freelist = (FREELIST*) ((char*) (newchunk->store) + i * chkmem->elemsize); /*lint !e826*/
928  freelist->next = (FREELIST*) ((char*) (newchunk->store) + (i + 1) * chkmem->elemsize); /*lint !e826*/
929  }
930 
931  freelist = (FREELIST*) ((char*) (newchunk->store) + (newchunk->storesize - 1) * chkmem->elemsize); /*lint !e826*/
932  freelist->next = chkmem->lazyfree;
933  chkmem->lazyfree = (FREELIST*) (newchunk->store);
934  chkmem->lazyfreesize += newchunk->storesize;
935 
936  /* link chunk into chunk block */
937  retval = linkChunk(chkmem, newchunk);
938 
939  checkChkmem(chkmem);
940 
941  return retval;
942 }
943 
944 /** destroys a chunk without updating the chunk lists */
945 static
947  CHUNK* chunk /**< memory chunk */
948  )
949 {
950  assert(chunk != NULL);
951 
952  debugMessage("destroying chunk %p\n", (void*)chunk);
953 
954  /* free chunk header and store (allocated in one call) */
955  BMSfreeMemory(&chunk);
956 }
957 
958 /** removes a completely unused chunk, i.e. a chunk with all elements in the eager free list */
959 static
961  CHUNK* chunk /**< memory chunk */
962  )
963 {
964  assert(chunk != NULL);
965  assert(chunk->store != NULL);
966  assert(chunk->eagerfree != NULL);
967  assert(chunk->chkmem != NULL);
968  assert(chunk->chkmem->chunks != NULL);
969  assert(chunk->chkmem->firsteager != NULL);
970  assert(chunk->eagerfreesize == chunk->storesize);
971 
972  debugMessage("freeing chunk %p of chunk block %p [elemsize: %d]\n", (void*)chunk, (void*)chunk->chkmem, chunk->chkmem->elemsize);
973 
974  /* count the deleted eager free slots */
975  chunk->chkmem->eagerfreesize -= chunk->eagerfreesize;
976  assert(chunk->chkmem->eagerfreesize >= 0);
977 
978  /* remove chunk from eager chunk list */
979  unlinkEagerChunk(chunk);
980 
981  /* remove chunk from chunk list */
982  unlinkChunk(chunk);
983 
984  /* destroy the chunk */
985  destroyChunk(chunk);
986 }
987 
988 /** returns an element of the eager free list and removes it from the list */
989 static
991  CHUNK* chunk /**< memory chunk */
992  )
993 {
994  FREELIST* ptr;
995 
996  assert(chunk != NULL);
997  assert(chunk->eagerfree != NULL);
998  assert(chunk->eagerfreesize > 0);
999  assert(chunk->chkmem != NULL);
1000 
1001  debugMessage("allocating chunk element in chunk %p [elemsize: %d]\n", (void*)chunk, chunk->chkmem->elemsize);
1002 
1003  /* unlink first element in the eager free list */
1004  ptr = chunk->eagerfree;
1005  chunk->eagerfree = ptr->next;
1006  chunk->eagerfreesize--;
1007  chunk->chkmem->eagerfreesize--;
1008 
1009  assert((chunk->eagerfreesize == 0 && chunk->eagerfree == NULL)
1010  || (chunk->eagerfreesize != 0 && chunk->eagerfree != NULL));
1011  assert(chunk->chkmem->eagerfreesize >= 0);
1012 
1013  /* unlink chunk from eager chunk list if necessary */
1014  if( chunk->eagerfree == NULL )
1015  {
1016  assert(chunk->eagerfreesize == 0);
1017  unlinkEagerChunk(chunk);
1018  }
1019 
1020  checkChunk(chunk);
1021 
1022  return (void*) ptr;
1023 }
1024 
1025 /** puts given pointer into the eager free list and adds the chunk to the eager list of its chunk block, if necessary */
1026 static
1028  CHUNK* chunk, /**< memory chunk */
1029  void* ptr /**< pointer */
1030  )
1031 {
1032  assert(chunk != NULL);
1033  assert(chunk->chkmem != NULL);
1034  assert(isPtrInChunk(chunk, ptr));
1035 
1036  debugMessage("freeing chunk element %p of chunk %p [elemsize: %d]\n", (void*)ptr, (void*)chunk, chunk->chkmem->elemsize);
1037 
1038  /* link chunk to the eager chunk list if necessary */
1039  if( chunk->eagerfree == NULL )
1040  {
1041  assert(chunk->eagerfreesize == 0);
1042  linkEagerChunk(chunk->chkmem, chunk);
1043  }
1044 
1045  /* add ptr to the chunks eager free list */
1046  ((FREELIST*)ptr)->next = chunk->eagerfree;
1047  chunk->eagerfree = (FREELIST*)ptr;
1048  chunk->eagerfreesize++;
1049  chunk->chkmem->eagerfreesize++;
1050 
1051  checkChunk(chunk);
1052 }
1053 
1054 /** creates a new chunk block data structure */
1055 static
1057  int size, /**< element size of the chunk block */
1058  int initchunksize, /**< number of elements in the first chunk of the chunk block */
1059  int garbagefactor /**< garbage collector is called, if at least garbagefactor * avg. chunksize
1060  * elements are free (-1: disable garbage collection) */
1061  )
1062 {
1063  BMS_CHKMEM* chkmem;
1064 
1065  assert(size >= 0);
1066  assert(BMSisAligned((size_t)size)); /*lint !e571*/
1067 
1068  BMSallocMemory(&chkmem);
1069  if( chkmem == NULL )
1070  return NULL;
1071 
1072  chkmem->lazyfree = NULL;
1073  chkmem->chunks = NULL;
1074  chkmem->firsteager = NULL;
1075  chkmem->nextchkmem = NULL;
1076  chkmem->elemsize = size;
1077  chkmem->chunkssize = 0;
1078  chkmem->nchunks = 0;
1079  chkmem->lastchunksize = 0;
1080  chkmem->storesize = 0;
1081  chkmem->lazyfreesize = 0;
1082  chkmem->eagerfreesize = 0;
1083  chkmem->initchunksize = initchunksize;
1084  chkmem->garbagefactor = garbagefactor;
1085 #ifndef NDEBUG
1086  chkmem->filename = NULL;
1087  chkmem->line = 0;
1088  chkmem->ngarbagecalls = 0;
1089  chkmem->ngarbagefrees = 0;
1090 #endif
1091 
1092  return chkmem;
1093 }
1094 
1095 /** destroys all chunks of the chunk block, but keeps the chunk block header structure */
1096 static
1098  BMS_CHKMEM* chkmem /**< chunk block */
1099  )
1100 {
1101  int i;
1102 
1103  assert(chkmem != NULL);
1104 
1105  /* destroy all chunks of the chunk block */
1106  for( i = 0; i < chkmem->nchunks; ++i )
1107  destroyChunk(chkmem->chunks[i]);
1108 
1109  chkmem->lazyfree = NULL;
1110  chkmem->firsteager = NULL;
1111  chkmem->nchunks = 0;
1112  chkmem->lastchunksize = 0;
1113  chkmem->storesize = 0;
1114  chkmem->lazyfreesize = 0;
1115  chkmem->eagerfreesize = 0;
1116 }
1117 
1118 /** deletes chunk block and frees all associated memory chunks */
1119 static
1121  BMS_CHKMEM** chkmem /**< pointer to chunk block */
1122  )
1123 {
1124  assert(chkmem != NULL);
1125  assert(*chkmem != NULL);
1126 
1127  clearChkmem(*chkmem);
1128  BMSfreeMemoryArrayNull(&(*chkmem)->chunks);
1129 
1130 #ifndef NDEBUG
1131  BMSfreeMemoryArrayNull(&(*chkmem)->filename);
1132 #endif
1133 
1134  BMSfreeMemory(chkmem);
1135 }
1136 
1137 /** allocates a new memory element from the chunk block */
1138 static
1140  BMS_CHKMEM* chkmem /**< chunk block */
1141  )
1142 {
1143  FREELIST* ptr;
1144 
1145  assert(chkmem != NULL);
1146 
1147  /* if the lazy freelist is empty, we have to find the memory element somewhere else */
1148  if( chkmem->lazyfree == NULL )
1149  {
1150  assert(chkmem->lazyfreesize == 0);
1151 
1152  /* check for a free element in the eager freelists */
1153  if( chkmem->firsteager != NULL )
1154  return allocChunkElement(chkmem->firsteager);
1155 
1156  /* allocate a new chunk */
1157  if( !createChunk(chkmem) )
1158  return NULL;
1159  }
1160 
1161  /* now the lazy freelist should contain an element */
1162  assert(chkmem->lazyfree != NULL);
1163  assert(chkmem->lazyfreesize > 0);
1164 
1165  ptr = chkmem->lazyfree;
1166  chkmem->lazyfree = ptr->next;
1167  chkmem->lazyfreesize--;
1168 
1169  checkChkmem(chkmem);
1170 
1171  return (void*) ptr;
1172 }
1173 
1174 /** sorts the lazy free list of the chunk block into the eager free lists of the chunks, and removes completely
1175  * unused chunks
1176  */
1177 static
1179  BMS_CHKMEM* chkmem /**< chunk block */
1180  )
1181 {
1182  CHUNK* chunk;
1183  CHUNK* nexteager;
1184  FREELIST* lazyfree;
1185 
1186  assert(chkmem != NULL);
1187 
1188  debugMessage("garbage collection for chunk block %p [elemsize: %d]\n", (void*)chkmem, chkmem->elemsize);
1189 
1190  /* check, if the chunk block is completely unused */
1191  if( chkmem->lazyfreesize + chkmem->eagerfreesize == chkmem->storesize )
1192  {
1193  clearChkmem(chkmem);
1194  return;
1195  }
1196 
1197 #ifndef NDEBUG
1198  chkmem->ngarbagecalls++;
1199 #endif
1200 
1201  /* put the lazy free elements into the eager free lists */
1202  while( chkmem->lazyfree != NULL )
1203  {
1204  /* unlink first element from the lazy free list */
1205  lazyfree = chkmem->lazyfree;
1206  chkmem->lazyfree = chkmem->lazyfree->next;
1207  chkmem->lazyfreesize--;
1208 
1209  /* identify the chunk of the element */
1210  chunk = findChunk(chkmem, (void*)lazyfree);
1211 #ifndef NDEBUG
1212  if( chunk == NULL )
1213  {
1214  errorMessage("chunk for lazy free chunk %p not found in chunk block %p\n", (void*)lazyfree, (void*)chkmem);
1215  }
1216 #endif
1217  assert(chunk != NULL);
1218 
1219  /* add the element to the chunk's eager free list */
1220  freeChunkElement(chunk, (void*)lazyfree);
1221  assert(chunk->eagerfreesize > 0);
1222  }
1223  assert(chkmem->lazyfreesize == 0);
1224 
1225  /* delete completely unused chunks, but keep at least one */
1226  chunk = chkmem->firsteager;
1227  while( chunk != NULL && chkmem->nchunks > 1 )
1228  {
1229  nexteager = chunk->nexteager;
1230  if( chunk->eagerfreesize == chunk->storesize )
1231  {
1232 #ifndef NDEBUG
1233  chkmem->ngarbagefrees++;
1234 #endif
1235  freeChunk(chunk);
1236  }
1237  chunk = nexteager;
1238  }
1239 
1240  checkChkmem(chkmem);
1241 }
1242 
1243 /** frees a memory element and returns it to the lazy freelist of the chunk block */
1244 static
1246  BMS_CHKMEM* chkmem, /**< chunk block */
1247  void* ptr, /**< memory element */
1248  const char* filename, /**< source file of the function call */
1249  int line /**< line number in source file of the function call */
1250  )
1251 { /*lint --e{715}*/
1252  assert(chkmem != NULL);
1253  assert(ptr != NULL);
1254 
1255 #ifdef BMS_CHKMEM
1256  /* check, if ptr belongs to the chunk block */
1257  if( !isPtrInChkmem(chkmem, ptr) )
1258  {
1259  BMS_CHKMEM* correctchkmem;
1260 
1261  printErrorHeader(filename, line);
1262  printError("pointer %p does not belong to chunk block %p (size: %lld)\n",
1263  ptr, chkmem, (long long)(chkmem->elemsize));
1264  }
1265 #endif
1266 
1267  /* put ptr in lazy free list */
1268  ((FREELIST*)ptr)->next = chkmem->lazyfree;
1269  chkmem->lazyfree = (FREELIST*)ptr;
1270  chkmem->lazyfreesize++;
1271 
1272  /* check if we want to apply garbage collection */
1273  if( chkmem->garbagefactor >= 0 && chkmem->nchunks > 0 && chkmem->lazyfreesize >= GARBAGE_SIZE
1274  && chkmem->lazyfreesize + chkmem->eagerfreesize
1275  > chkmem->garbagefactor * (double)(chkmem->storesize) / (double)(chkmem->nchunks) )
1276  {
1277  garbagecollectChkmem(chkmem);
1278  }
1279 
1280  checkChkmem(chkmem);
1281 }
1282 
1283 /** creates a new chunk block data structure */
1285  size_t size, /**< element size of the chunk block */
1286  int initchunksize, /**< number of elements in the first chunk of the chunk block */
1287  int garbagefactor, /**< garbage collector is called, if at least garbagefactor * avg. chunksize
1288  * elements are free (-1: disable garbage collection) */
1289  const char* filename, /**< source file of the function call */
1290  int line /**< line number in source file of the function call */
1291  )
1292 {
1293  BMS_CHKMEM* chkmem;
1294 
1295  alignSize(&size);
1296  chkmem = createChkmem((int) size, initchunksize, garbagefactor);
1297  if( chkmem == NULL )
1298  {
1299  printErrorHeader(filename, line);
1300  printError("Insufficient memory for chunk block\n");
1301  }
1302  debugMessage("created chunk memory %p [elemsize: %d]\n", (void*)chkmem, (int)size);
1303 
1304  return chkmem;
1305 }
1306 
1307 /** clears a chunk block data structure */
1309  BMS_CHKMEM* chkmem, /**< chunk block */
1310  const char* filename, /**< source file of the function call */
1311  int line /**< line number in source file of the function call */
1312  )
1313 {
1314  debugMessage("clearing chunk memory %p [elemsize: %d]\n", (void*)chkmem, chkmem->elemsize);
1315 
1316  if( chkmem != NULL )
1317  clearChkmem(chkmem);
1318  else
1319  {
1320  printErrorHeader(filename, line);
1321  printError("Tried to clear null chunk block\n");
1322  }
1323 }
1324 
1325 /** destroys and frees a chunk block data structure */
1327  BMS_CHKMEM** chkmem, /**< pointer to chunk block */
1328  const char* filename, /**< source file of the function call */
1329  int line /**< line number in source file of the function call */
1330  )
1331 {
1332  assert(chkmem != NULL);
1333 
1334  debugMessage("destroying chunk memory %p [elemsize: %d]\n", (void*)*chkmem, (*chkmem)->elemsize);
1335 
1336  if( *chkmem != NULL )
1337  destroyChkmem(chkmem);
1338  else
1339  {
1340  printErrorHeader(filename, line);
1341  printError("Tried to destroy null chunk block\n");
1342  }
1343 }
1344 
1345 /** allocates a memory element of the given chunk block */
1347  BMS_CHKMEM* chkmem, /**< chunk block */
1348  size_t size, /**< size of memory element to allocate (only needed for sanity check) */
1349  const char* filename, /**< source file of the function call */
1350  int line /**< line number in source file of the function call */
1351  )
1352 {
1353  void* ptr;
1354 
1355  assert(chkmem != NULL);
1356  assert((int)size == chkmem->elemsize);
1357 
1358  /* get memory inside the chunk block */
1359  ptr = allocChkmemElement(chkmem);
1360  if( ptr == NULL )
1361  {
1362  printErrorHeader(filename, line);
1363  printError("Insufficient memory for new chunk\n");
1364  }
1365  debugMessage("alloced %8lld bytes in %p [%s:%d]\n", (long long)size, (void*)ptr, filename, line);
1366 
1367  checkChkmem(chkmem);
1368 
1369  return ptr;
1370 }
1371 
1372 /** duplicates a given memory element by allocating a new element of the same chunk block and copying the data */
1374  BMS_CHKMEM* chkmem, /**< chunk block */
1375  const void* source, /**< source memory element */
1376  size_t size, /**< size of memory element to allocate (only needed for sanity check) */
1377  const char* filename, /**< source file of the function call */
1378  int line /**< line number in source file of the function call */
1379  )
1380 {
1381  void* ptr;
1382 
1383  assert(chkmem != NULL);
1384  assert(source != NULL);
1385  assert((int)size == chkmem->elemsize);
1386 
1387  ptr = BMSallocChunkMemory_call(chkmem, size, filename, line);
1388  if( ptr != NULL )
1389  BMScopyMemorySize(ptr, source, (size_t) chkmem->elemsize);
1390 
1391  return ptr;
1392 }
1393 
1394 /** frees a memory element of the given chunk block */
1396  BMS_CHKMEM* chkmem, /**< chunk block */
1397  void* ptr, /**< memory element to free */
1398  size_t size, /**< size of memory element to allocate (only needed for sanity check) */
1399  const char* filename, /**< source file of the function call */
1400  int line /**< line number in source file of the function call */
1401  )
1402 {
1403  assert(chkmem != NULL);
1404  assert((int)size == chkmem->elemsize);
1405 
1406  debugMessage("free %8lld bytes in %p [%s:%d]\n", (long long)chkmem->elemsize, ptr, filename, line);
1407 
1408  if( ptr == NULL )
1409  {
1410  printErrorHeader(filename, line);
1411  printError("Tried to free null block pointer\n");
1412  return;
1413  }
1414 
1415  /* free memory in chunk block */
1416  freeChkmemElement(chkmem, ptr, filename, line);
1417 
1418  checkChkmem(chkmem);
1419 }
1420 
1421 /** calls garbage collection of chunk block and frees chunks without allocated memory elements */
1423  BMS_CHKMEM* chkmem /**< chunk block */
1424  )
1425 {
1426  debugMessage("garbage collection on chunk memory %p [elemsize: %d]\n", (void*)chkmem, chkmem->elemsize);
1427 
1428  garbagecollectChkmem(chkmem);
1429 }
1430 
1431 /** returns the number of allocated bytes in the chunk block */
1433  const BMS_CHKMEM* chkmem /**< chunk block */
1434  )
1435 {
1436  long long chkmemused;
1437  int i;
1438 
1439  assert(chkmem != NULL);
1440 
1441  chkmemused = 0;
1442  for( i = 0; i < chkmem->nchunks; ++i )
1443  chkmemused += (long long)(chkmem->chunks[i]->elemsize) * (long long)(chkmem->chunks[i]->storesize);
1444 
1445  return chkmemused;
1446 }
1447 
1448 
1449 
1450 
1451 /***********************************************************
1452  * Block Memory Management
1453  *
1454  * Efficient memory management for objects of varying sizes
1455  ***********************************************************/
1456 
1457 #define CHKHASH_SIZE 1013 /**< size of chunk block hash table; should be prime */
1458 
1459 /** collection of chunk blocks */
1460 struct BMS_BlkMem
1461 {
1462  BMS_CHKMEM* chkmemhash[CHKHASH_SIZE]; /**< hash table with chunk blocks */
1463  long long memused; /**< total number of used bytes in the memory header */
1464  int initchunksize; /**< number of elements in the first chunk of each chunk block */
1465  int garbagefactor; /**< garbage collector is called, if at least garbagefactor * avg. chunksize
1466  * elements are free (-1: disable garbage collection) */
1467 };
1468 
1469 
1470 
1471 /*
1472  * debugging methods
1473  */
1474 
1475 #ifdef CHECKMEM
1476 static
1477 void checkBlkmem(
1478  const BMS_BLKMEM* blkmem /**< block memory */
1479  )
1480 {
1481  const BMS_CHKMEM* chkmem;
1482  int i;
1483 
1484  assert(blkmem != NULL);
1485  assert(blkmem->chkmemhash != NULL);
1486 
1487  for( i = 0; i < CHKHASH_SIZE; ++i )
1488  {
1489  chkmem = blkmem->chkmemhash[i];
1490  while( chkmem != NULL )
1491  {
1492  checkChkmem(chkmem);
1493  chkmem = chkmem->nextchkmem;
1494  }
1495  }
1496 }
1497 #else
1498 #define checkBlkmem(blkmem) /**/
1499 #endif
1500 
1501 
1502 /** finds the chunk block, to whick the given pointer belongs to;
1503  * this could be done by selecting the chunk block of the corresponding element size, but in a case of an
1504  * error (free gives an incorrect element size), we want to identify and output the correct element size
1505  */
1506 static
1508  const BMS_BLKMEM* blkmem, /**< block memory */
1509  const void* ptr /**< memory element to search */
1510  )
1511 {
1512  BMS_CHKMEM* chkmem;
1513  int i;
1514 
1515  assert(blkmem != NULL);
1516 
1517  chkmem = NULL;
1518  for( i = 0; chkmem == NULL && i < CHKHASH_SIZE; ++i )
1519  {
1520  chkmem = blkmem->chkmemhash[i];
1521  while( chkmem != NULL && !isPtrInChkmem(chkmem, ptr) )
1522  chkmem = chkmem->nextchkmem;
1523  }
1524 
1525  return chkmem;
1526 }
1527 
1528 /** calculates hash number of memory size */
1529 static
1531  int size /**< element size */
1532  )
1533 {
1534  assert(size >= 0);
1535  assert(BMSisAligned((size_t)size)); /*lint !e571*/
1536 
1537  return (size % CHKHASH_SIZE);
1538 }
1539 
1540 /** creates a block memory allocation data structure */
1542  int initchunksize, /**< number of elements in the first chunk of each chunk block */
1543  int garbagefactor, /**< garbage collector is called, if at least garbagefactor * avg. chunksize
1544  * elements are free (-1: disable garbage collection) */
1545  const char* filename, /**< source file of the function call */
1546  int line /**< line number in source file of the function call */
1547  )
1548 {
1549  BMS_BLKMEM* blkmem;
1550  int i;
1551 
1552  BMSallocMemory(&blkmem);
1553  if( blkmem != NULL )
1554  {
1555  for( i = 0; i < CHKHASH_SIZE; ++i )
1556  blkmem->chkmemhash[i] = NULL;
1557  blkmem->initchunksize = initchunksize;
1558  blkmem->garbagefactor = garbagefactor;
1559  blkmem->memused = 0;
1560  }
1561  else
1562  {
1563  printErrorHeader(filename, line);
1564  printError("Insufficient memory for block memory header\n");
1565  }
1566 
1567  return blkmem;
1568 }
1569 
1570 /** frees all chunk blocks in the block memory */
1572  BMS_BLKMEM* blkmem, /**< block memory */
1573  const char* filename, /**< source file of the function call */
1574  int line /**< line number in source file of the function call */
1575  )
1576 {
1577  BMS_CHKMEM* chkmem;
1578  BMS_CHKMEM* nextchkmem;
1579  int i;
1580 
1581  if( blkmem != NULL )
1582  {
1583  for( i = 0; i < CHKHASH_SIZE; ++i )
1584  {
1585  chkmem = blkmem->chkmemhash[i];
1586  while( chkmem != NULL )
1587  {
1588  nextchkmem = chkmem->nextchkmem;
1589  destroyChkmem(&chkmem);
1590  chkmem = nextchkmem;
1591  }
1592  blkmem->chkmemhash[i] = NULL;
1593  }
1594  blkmem->memused = 0;
1595  }
1596  else
1597  {
1598  printErrorHeader(filename, line);
1599  printError("Tried to clear null block memory\n");
1600  }
1601 }
1602 
1603 /** clears and deletes block memory */
1605  BMS_BLKMEM** blkmem, /**< pointer to block memory */
1606  const char* filename, /**< source file of the function call */
1607  int line /**< line number in source file of the function call */
1608  )
1609 {
1610  assert(blkmem != NULL);
1611 
1612  if( *blkmem != NULL )
1613  {
1614  BMSclearBlockMemory_call(*blkmem, filename, line);
1615  BMSfreeMemory(blkmem);
1616  assert(*blkmem == NULL);
1617  }
1618  else
1619  {
1620  printErrorHeader(filename, line);
1621  printError("Tried to destroy null block memory\n");
1622  }
1623 }
1624 
1625 /** allocates memory in the block memory pool */
1627  BMS_BLKMEM* blkmem, /**< block memory */
1628  size_t size, /**< size of memory element to allocate */
1629  const char* filename, /**< source file of the function call */
1630  int line /**< line number in source file of the function call */
1631  )
1632 {
1633  BMS_CHKMEM** chkmemptr;
1634  int hashnumber;
1635  void* ptr;
1636 
1637  assert( blkmem != NULL );
1638 
1639  /* calculate hash number of given size */
1640  alignSize(&size);
1641  hashnumber = getHashNumber((int)size);
1642 
1643  /* find correspoding chunk block */
1644  chkmemptr = &(blkmem->chkmemhash[hashnumber]);
1645  while( *chkmemptr != NULL && (*chkmemptr)->elemsize != (int)size )
1646  chkmemptr = &((*chkmemptr)->nextchkmem);
1647 
1648  /* create new chunk block if necessary */
1649  if( *chkmemptr == NULL )
1650  {
1651  *chkmemptr = createChkmem((int)size, blkmem->initchunksize, blkmem->garbagefactor);
1652  if( *chkmemptr == NULL )
1653  {
1654  printErrorHeader(filename, line);
1655  printError("Insufficient memory for chunk block\n");
1656  return NULL;
1657  }
1658 #ifndef NDEBUG
1659  BMSduplicateMemoryArray(&(*chkmemptr)->filename, filename, strlen(filename) + 1);
1660  (*chkmemptr)->line = line;
1661 #endif
1662  }
1663 
1664  /* get memory inside the chunk block */
1665  ptr = allocChkmemElement(*chkmemptr);
1666  if( ptr == NULL )
1667  {
1668  printErrorHeader(filename, line);
1669  printError("Insufficient memory for new chunk\n");
1670  }
1671  debugMessage("alloced %8lld bytes in %p [%s:%d]\n", (long long)size, ptr, filename, line);
1672 
1673  blkmem->memused += (long long) size;
1674 
1675  checkBlkmem(blkmem);
1676 
1677  return ptr;
1678 }
1679 
1680 /** resizes memory element in the block memory pool, and copies the data */
1682  BMS_BLKMEM* blkmem, /**< block memory */
1683  void* ptr, /**< memory element to reallocated */
1684  size_t oldsize, /**< old size of memory element */
1685  size_t newsize, /**< new size of memory element */
1686  const char* filename, /**< source file of the function call */
1687  int line /**< line number in source file of the function call */
1688  )
1689 {
1690  void* newptr;
1691 
1692  if( ptr == NULL )
1693  {
1694  assert(oldsize == 0);
1695  return BMSallocBlockMemory_call(blkmem, newsize, filename, line);
1696  }
1697 
1698  alignSize(&oldsize);
1699  alignSize(&newsize);
1700  if( oldsize == newsize )
1701  return ptr;
1702 
1703  newptr = BMSallocBlockMemory_call(blkmem, newsize, filename, line);
1704  if( newptr != NULL )
1705  BMScopyMemorySize(newptr, ptr, MIN(oldsize, newsize));
1706  BMSfreeBlockMemory_call(blkmem, ptr, oldsize, filename, line);
1707 
1708  return newptr;
1709 }
1710 
1711 /** duplicates memory element in the block memory pool, and copies the data */
1713  BMS_BLKMEM* blkmem, /**< block memory */
1714  const void* source, /**< memory element to duplicate */
1715  size_t size, /**< size of memory elements */
1716  const char* filename, /**< source file of the function call */
1717  int line /**< line number in source file of the function call */
1718  )
1719 {
1720  void* ptr;
1721 
1722  assert(source != NULL);
1723 
1724  ptr = BMSallocBlockMemory_call(blkmem, size, filename, line);
1725  if( ptr != NULL )
1726  BMScopyMemorySize(ptr, source, size);
1727 
1728  return ptr;
1729 }
1730 
1731 /** frees memory element in the block memory pool */
1733  BMS_BLKMEM* blkmem, /**< block memory */
1734  void* ptr, /**< memory element to free */
1735  size_t size, /**< size of memory element */
1736  const char* filename, /**< source file of the function call */
1737  int line /**< line number in source file of the function call */
1738  )
1739 {
1740  BMS_CHKMEM* chkmem;
1741  int hashnumber;
1742 
1743  assert( blkmem != NULL );
1744 
1745  if( ptr != NULL )
1746  {
1747  /* calculate hash number of given size */
1748  alignSize(&size);
1749  hashnumber = getHashNumber((int)size);
1750 
1751  debugMessage("free %8lld bytes in %p [%s:%d]\n", (long long)size, ptr, filename, line);
1752 
1753  /* find correspoding chunk block */
1754  assert( blkmem->chkmemhash != NULL );
1755  chkmem = blkmem->chkmemhash[hashnumber];
1756  while( chkmem != NULL && chkmem->elemsize != (int)size )
1757  chkmem = chkmem->nextchkmem;
1758  if( chkmem == NULL )
1759  {
1760  printErrorHeader(filename, line);
1761  printError("Tried to free pointer <%p> in block memory <%p> of unknown size %lld\n",
1762  ptr, (void*)blkmem, (long long) size);
1763  return;
1764  }
1765  assert(chkmem->elemsize == (int)size);
1766 
1767  /* free memory in chunk block */
1768  freeChkmemElement(chkmem, ptr, filename, line);
1769 
1770  blkmem->memused -= (long long) size;
1771  assert(blkmem->memused >= 0);
1772  }
1773  else if( size != 0 )
1774  {
1775  printErrorHeader(filename, line);
1776  printError("Tried to free null block pointer\n");
1777  }
1778 
1779  checkBlkmem(blkmem);
1780 }
1781 
1782 /** calls garbage collection of block memory, frees chunks without allocated memory elements, and frees
1783  * chunk blocks without any chunks
1784  */
1786  BMS_BLKMEM* blkmem /**< block memory */
1787  )
1788 {
1789  int i;
1790 
1791  assert(blkmem != NULL);
1792 
1793  for( i = 0; i < CHKHASH_SIZE; ++i )
1794  {
1795  BMS_CHKMEM** chkmemptr;
1796 
1797  chkmemptr = &blkmem->chkmemhash[i];
1798  while( *chkmemptr != NULL )
1799  {
1800  garbagecollectChkmem(*chkmemptr);
1801  if( (*chkmemptr)->nchunks == 0 )
1802  {
1803  BMS_CHKMEM* nextchkmem;
1804 
1805  nextchkmem = (*chkmemptr)->nextchkmem;
1806  destroyChkmem(chkmemptr);
1807  *chkmemptr = nextchkmem;
1808  }
1809  else
1810  chkmemptr = &(*chkmemptr)->nextchkmem;
1811  }
1812  }
1813 }
1814 
1815 /** returns the number of allocated bytes in the block memory */
1817  const BMS_BLKMEM* blkmem /**< block memory */
1818  )
1819 {
1820  assert(blkmem != NULL);
1821 
1822  return blkmem->memused;
1823 }
1824 
1825 /** returns the size of the given memory element; returns 0, if the element is not member of the block memory */
1827  const BMS_BLKMEM* blkmem, /**< block memory */
1828  const void* ptr /**< memory element */
1829  )
1830 {
1831  const BMS_CHKMEM* chkmem;
1832 
1833  assert(blkmem != NULL);
1834 
1835  if( ptr == NULL )
1836  return 0;
1837 
1838  chkmem = findChkmem(blkmem, ptr);
1839  if( chkmem == NULL )
1840  return 0;
1841 
1842  return (size_t)(chkmem->elemsize); /*lint !e571*/
1843 }
1844 
1845 /** outputs allocation diagnostics of block memory */
1847  const BMS_BLKMEM* blkmem /**< block memory */
1848  )
1849 {
1850  const BMS_CHKMEM* chkmem;
1851  int nblocks = 0;
1852  int nunusedblocks = 0;
1853  int totalnchunks = 0;
1854  int totalneagerchunks = 0;
1855  int totalnelems = 0;
1856  int totalneagerelems = 0;
1857  int totalnlazyelems = 0;
1858 #ifndef NDEBUG
1859  int totalngarbagecalls = 0;
1860  int totalngarbagefrees = 0;
1861 #endif
1862  long long allocedmem = 0;
1863  long long freemem = 0;
1864  int i;
1865  int c;
1866 
1867 #ifndef NDEBUG
1868  printInfo(" ElSize #Chunk #Eag #Elems #EagFr #LazFr #GCl #GFr Free MBytes First Allocator\n");
1869 #else
1870  printInfo(" ElSize #Chunk #Eag #Elems #EagFr #LazFr Free MBytes\n");
1871 #endif
1872 
1873  assert(blkmem != NULL);
1874 
1875  for( i = 0; i < CHKHASH_SIZE; ++i )
1876  {
1877  chkmem = blkmem->chkmemhash[i];
1878  while( chkmem != NULL )
1879  {
1880  const CHUNK* chunk;
1881  int nchunks = 0;
1882  int nelems = 0;
1883  int neagerchunks = 0;
1884  int neagerelems = 0;
1885 
1886  for( c = 0; c < chkmem->nchunks; ++c )
1887  {
1888  chunk = chkmem->chunks[c];
1889  assert(chunk != NULL);
1890  assert(chunk->elemsize == chkmem->elemsize);
1891  assert(chunk->chkmem == chkmem);
1892  nchunks++;
1893  nelems += chunk->storesize;
1894  if( chunk->eagerfree != NULL )
1895  {
1896  neagerchunks++;
1897  neagerelems += chunk->eagerfreesize;
1898  }
1899  }
1900 
1901  assert(nchunks == chkmem->nchunks);
1902  assert(nelems == chkmem->storesize);
1903  assert(neagerelems == chkmem->eagerfreesize);
1904 
1905  if( nelems > 0 )
1906  {
1907  nblocks++;
1908  allocedmem += (long long)chkmem->elemsize * (long long)nelems;
1909  freemem += (long long)chkmem->elemsize * ((long long)neagerelems + (long long)chkmem->lazyfreesize);
1910 
1911 #ifndef NDEBUG
1912  printInfo("%7lld %6d %4d %7d %7d %7d %5d %4d %5.1f%% %6.1f %s:%d\n",
1913  (long long)(chkmem->elemsize), nchunks, neagerchunks, nelems,
1914  neagerelems, chkmem->lazyfreesize, chkmem->ngarbagecalls, chkmem->ngarbagefrees,
1915  100.0 * (double) (neagerelems + chkmem->lazyfreesize) / (double) (nelems),
1916  (double)chkmem->elemsize * nelems / (1024.0*1024.0),
1917  chkmem->filename, chkmem->line);
1918 #else
1919  printInfo("%7lld %6d %4d %7d %7d %7d %5.1f%% %6.1f\n",
1920  (long long)(chkmem->elemsize), nchunks, neagerchunks, nelems,
1921  neagerelems, chkmem->lazyfreesize,
1922  100.0 * (double) (neagerelems + chkmem->lazyfreesize) / (double) (nelems),
1923  (double)chkmem->elemsize * nelems / (1024.0*1024.0));
1924 #endif
1925  }
1926  else
1927  {
1928 #ifndef NDEBUG
1929  printInfo("%7lld <unused> %5d %4d %s:%d\n",
1930  (long long)(chkmem->elemsize), chkmem->ngarbagecalls, chkmem->ngarbagefrees,
1931  chkmem->filename, chkmem->line);
1932 #else
1933  printInfo("%7lld <unused>\n", (long long)(chkmem->elemsize));
1934 #endif
1935  nunusedblocks++;
1936  }
1937  totalnchunks += nchunks;
1938  totalneagerchunks += neagerchunks;
1939  totalnelems += nelems;
1940  totalneagerelems += neagerelems;
1941  totalnlazyelems += chkmem->lazyfreesize;
1942 #ifndef NDEBUG
1943  totalngarbagecalls += chkmem->ngarbagecalls;
1944  totalngarbagefrees += chkmem->ngarbagefrees;
1945 #endif
1946  chkmem = chkmem->nextchkmem;
1947  }
1948  }
1949 #ifndef NDEBUG
1950  printInfo(" Total %6d %4d %7d %7d %7d %5d %4d %5.1f%% %6.1f\n",
1951  totalnchunks, totalneagerchunks, totalnelems, totalneagerelems, totalnlazyelems,
1952  totalngarbagecalls, totalngarbagefrees,
1953  totalnelems > 0 ? 100.0 * (double) (totalneagerelems + totalnlazyelems) / (double) (totalnelems) : 0.0,
1954  (double)allocedmem/(1024.0*1024.0));
1955 #else
1956  printInfo(" Total %6d %4d %7d %7d %7d %5.1f%% %6.1f\n",
1957  totalnchunks, totalneagerchunks, totalnelems, totalneagerelems, totalnlazyelems,
1958  totalnelems > 0 ? 100.0 * (double) (totalneagerelems + totalnlazyelems) / (double) (totalnelems) : 0.0,
1959  (double)allocedmem/(1024.0*1024.0));
1960 #endif
1961  printInfo("%d blocks (%d unused), %lld bytes allocated, %lld bytes free",
1962  nblocks + nunusedblocks, nunusedblocks, allocedmem, freemem);
1963  if( allocedmem > 0 )
1964  printInfo(" (%.1f%%)", 100.0 * (double) freemem / (double) allocedmem);
1965  printInfo("\n");
1966 }
1967 
1968 /** outputs warning messages, if there are allocated elements in the block memory */
1970  const BMS_BLKMEM* blkmem /**< block memory */
1971  )
1972 {
1973  const BMS_CHKMEM* chkmem;
1974  long long allocedmem = 0;
1975  long long freemem = 0;
1976  int i;
1977  int c;
1978 
1979  assert(blkmem != NULL);
1980 
1981  for( i = 0; i < CHKHASH_SIZE; ++i )
1982  {
1983  chkmem = blkmem->chkmemhash[i];
1984  while( chkmem != NULL )
1985  {
1986  const CHUNK* chunk;
1987  int nchunks = 0;
1988  int nelems = 0;
1989  int neagerelems = 0;
1990 
1991  for( c = 0; c < chkmem->nchunks; ++c )
1992  {
1993  chunk = chkmem->chunks[c];
1994  assert(chunk != NULL);
1995  assert(chunk->elemsize == chkmem->elemsize);
1996  assert(chunk->chkmem == chkmem);
1997  nchunks++;
1998  nelems += chunk->storesize;
1999  if( chunk->eagerfree != NULL )
2000  neagerelems += chunk->eagerfreesize;
2001  }
2002 
2003  assert(nchunks == chkmem->nchunks);
2004  assert(nelems == chkmem->storesize);
2005  assert(neagerelems == chkmem->eagerfreesize);
2006 
2007  if( nelems > 0 )
2008  {
2009  allocedmem += (long long)chkmem->elemsize * (long long)nelems;
2010  freemem += (long long)chkmem->elemsize * ((long long)neagerelems + (long long)chkmem->lazyfreesize);
2011 
2012  if( nelems != neagerelems + chkmem->lazyfreesize )
2013  {
2014 #ifndef NDEBUG
2015  printInfo("%lld bytes (%d elements of size %lld) not freed. First Allocator: %s:%d\n",
2016  (((long long)nelems - (long long)neagerelems) - (long long)chkmem->lazyfreesize)
2017  * (long long)(chkmem->elemsize),
2018  (nelems - neagerelems) - chkmem->lazyfreesize, (long long)(chkmem->elemsize),
2019  chkmem->filename, chkmem->line);
2020 #else
2021  printInfo("%lld bytes (%d elements of size %lld) not freed.\n",
2022  ((nelems - neagerelems) - chkmem->lazyfreesize) * (long long)(chkmem->elemsize),
2023  (nelems - neagerelems) - chkmem->lazyfreesize, (long long)(chkmem->elemsize));
2024 #endif
2025  }
2026  }
2027  chkmem = chkmem->nextchkmem;
2028  }
2029  }
2030 
2031  if( allocedmem != freemem )
2032  printInfo("%lld bytes not freed in total.\n", allocedmem - freemem);
2033 }
void BMSdestroyBlockMemory_call(BMS_BLKMEM **blkmem, const char *filename, int line)
Definition: memory.c:1604
long long BMSgetMemoryUsed_call(void)
Definition: memory.c:270
#define printError
Definition: memory.c:46
#define ALIGNMENT
Definition: memory.c:470
void * BMSallocChunkMemory_call(BMS_CHKMEM *chkmem, size_t size, const char *filename, int line)
Definition: memory.c:1346
#define BMScopyMemorySize(ptr, source, size)
Definition: memory.h:103
struct BMS_ChkMem BMS_CHKMEM
Definition: memory.h:240
int BMSisAligned(size_t size)
Definition: memory.c:544
void BMSfreeMemory_call(void *ptr, const char *filename, int line)
Definition: memory.c:433
#define BMSfreeMemoryArrayNull(ptr)
Definition: memory.h:122
void BMSdisplayBlockMemory_call(const BMS_BLKMEM *blkmem)
Definition: memory.c:1846
static void garbagecollectChkmem(BMS_CHKMEM *chkmem)
Definition: memory.c:1178
#define checkChunk(chunk)
Definition: memory.c:715
#define NULL
Definition: lpi_spx.cpp:129
#define checkBlkmem(blkmem)
Definition: memory.c:1498
#define STORESIZE_MAX
Definition: memory.c:468
void * BMSduplicateChunkMemory_call(BMS_CHKMEM *chkmem, const void *source, size_t size, const char *filename, int line)
Definition: memory.c:1373
void BMSdestroyChunkMemory_call(BMS_CHKMEM **chkmem, const char *filename, int line)
Definition: memory.c:1326
void * BMSallocBlockMemory_call(BMS_BLKMEM *blkmem, size_t size, const char *filename, int line)
Definition: memory.c:1626
struct Chunk CHUNK
Definition: memory.c:473
size_t BMSgetBlockPointerSize_call(const BMS_BLKMEM *blkmem, const void *ptr)
Definition: memory.c:1826
static void * allocChkmemElement(BMS_CHKMEM *chkmem)
Definition: memory.c:1139
#define debugMessage
Definition: memory.c:43
#define CHKHASH_SIZE
Definition: memory.c:1457
static void * allocChunkElement(CHUNK *chunk)
Definition: memory.c:990
#define GARBAGE_SIZE
Definition: memory.c:469
#define warningMessage
Definition: memory.c:49
static void unlinkEagerChunk(CHUNK *chunk)
Definition: memory.c:850
#define FALSE
Definition: memory.c:54
void * BMSreallocBlockMemory_call(BMS_BLKMEM *blkmem, void *ptr, size_t oldsize, size_t newsize, const char *filename, int line)
Definition: memory.c:1681
#define printErrorHeader(f, l)
Definition: memory.c:45
#define BMSfreeMemory(ptr)
Definition: memory.h:117
void BMSfreeBlockMemory_call(BMS_BLKMEM *blkmem, void *ptr, size_t size, const char *filename, int line)
Definition: memory.c:1732
static BMS_CHKMEM * findChkmem(const BMS_BLKMEM *blkmem, const void *ptr)
Definition: memory.c:1507
static int linkChunk(BMS_CHKMEM *chkmem, CHUNK *chunk)
Definition: memory.c:724
#define CHUNKLENGTH_MIN
Definition: memory.c:466
void * BMSallocClearMemory_call(size_t num, size_t size, const char *filename, int line)
Definition: memory.c:280
struct Freelist FREELIST
Definition: memory.c:472
static void unlinkChunk(CHUNK *chunk)
Definition: memory.c:796
void BMSgarbagecollectBlockMemory_call(BMS_BLKMEM *blkmem)
Definition: memory.c:1785
void * BMSduplicateMemory_call(const void *source, size_t size, const char *filename, int line)
Definition: memory.c:414
long long BMSgetBlockMemoryUsed_call(const BMS_BLKMEM *blkmem)
Definition: memory.c:1816
void BMScheckEmptyBlockMemory_call(const BMS_BLKMEM *blkmem)
Definition: memory.c:1969
static int isPtrInChunk(const CHUNK *chunk, const void *ptr)
Definition: memory.c:555
static void alignSize(size_t *size)
Definition: memory.c:524
#define BMSduplicateMemoryArray(ptr, source, num)
Definition: memory.h:111
static int isPtrInChkmem(const BMS_CHKMEM *chkmem, const void *ptr)
Definition: memory.c:608
static void freeChkmemElement(BMS_CHKMEM *chkmem, void *ptr, const char *filename, int line)
Definition: memory.c:1245
void BMSgarbagecollectChunkMemory_call(BMS_CHKMEM *chkmem)
Definition: memory.c:1422
#define checkChkmem(chkmem)
Definition: memory.c:716
#define CHUNKLENGTH_MAX
Definition: memory.c:467
void BMSclearMemory_call(void *ptr, size_t size)
Definition: memory.c:369
long long BMSgetChunkMemoryUsed_call(const BMS_CHKMEM *chkmem)
Definition: memory.c:1432
static void freeChunkElement(CHUNK *chunk, void *ptr)
Definition: memory.c:1027
static void destroyChunk(CHUNK *chunk)
Definition: memory.c:946
void BMSdisplayMemory_call(void)
Definition: memory.c:250
#define printInfo
Definition: memory.c:50
static int getHashNumber(int size)
Definition: memory.c:1530
void BMScopyMemory_call(void *ptr, const void *source, size_t size)
Definition: memory.c:382
BMS_BLKMEM * BMScreateBlockMemory_call(int initchunksize, int garbagefactor, const char *filename, int line)
Definition: memory.c:1541
static int createChunk(BMS_CHKMEM *chkmem)
Definition: memory.c:875
static void linkEagerChunk(BMS_CHKMEM *chkmem, CHUNK *chunk)
Definition: memory.c:829
void BMSmoveMemory_call(void *ptr, const void *source, size_t size)
Definition: memory.c:399
static void freeChunk(CHUNK *chunk)
Definition: memory.c:960
#define errorMessage
Definition: memory.c:44
void * BMSduplicateBlockMemory_call(BMS_BLKMEM *blkmem, const void *source, size_t size, const char *filename, int line)
Definition: memory.c:1712
void BMScheckEmptyMemory_call(void)
Definition: memory.c:260
void BMSclearChunkMemory_call(BMS_CHKMEM *chkmem, const char *filename, int line)
Definition: memory.c:1308
static void clearChkmem(BMS_CHKMEM *chkmem)
Definition: memory.c:1097
size_t BMSgetPointerSize_call(const void *ptr)
Definition: memory.c:242
void * BMSreallocMemory_call(void *ptr, size_t size, const char *filename, int line)
Definition: memory.c:336
#define BMSallocMemorySize(ptr, size)
Definition: memory.h:93
public methods for message output
#define TRUE
Definition: memory.c:55
void * BMSallocMemory_call(size_t size, const char *filename, int line)
Definition: memory.c:309
#define MIN(x, y)
Definition: memory.c:59
#define BMSallocMemory(ptr)
Definition: memory.h:92
#define BMSreallocMemoryArray(ptr, num)
Definition: memory.h:80
static CHUNK * findChunk(const BMS_CHKMEM *chkmem, const void *ptr)
Definition: memory.c:572
BMS_CHKMEM * BMScreateChunkMemory_call(size_t size, int initchunksize, int garbagefactor, const char *filename, int line)
Definition: memory.c:1284
common defines and data types used in all packages of SCIP
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:371
static BMS_CHKMEM * createChkmem(int size, int initchunksize, int garbagefactor)
Definition: memory.c:1056
#define MAX(x, y)
Definition: memory.c:58
void BMSfreeChunkMemory_call(BMS_CHKMEM *chkmem, void *ptr, size_t size, const char *filename, int line)
Definition: memory.c:1395
void BMSclearBlockMemory_call(BMS_BLKMEM *blkmem, const char *filename, int line)
Definition: memory.c:1571
void BMSalignMemsize(size_t *size)
Definition: memory.c:535
static void destroyChkmem(BMS_CHKMEM **chkmem)
Definition: memory.c:1120
memory allocation routines