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-2016 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 scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file memory.c
17  * @brief memory allocation routines
18  * @author Tobias Achterberg
19  * @author Gerald Gamrath
20  * @author Marc Pfetsch
21  */
22 
23 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
24 
25 #ifdef __cplusplus
26 #define __STDC_LIMIT_MACROS
27 #endif
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <assert.h>
32 #include <string.h>
33 
34 #ifdef WITH_SCIPDEF
35 #include "scip/def.h"
36 #include "scip/pub_message.h"
37 #else
38 #include <stdint.h>
39 #endif
40 
41 #include "blockmemshell/memory.h"
42 
43 /*#define CHECKMEM*/
44 
45 
46 /* if we are included in SCIP, use SCIP's message output methods */
47 #ifdef SCIPdebugMessage
48 #define debugMessage SCIPdebugMessage
49 #define errorMessage SCIPerrorMessage
50 #else
51 #define debugMessage while( FALSE ) printf
52 #define errorMessage printf
53 #define printErrorHeader(f,l) printf("[%s:%d] ERROR: ", f, l)
54 #define printError printf
55 #endif
56 
57 #define warningMessage printf
58 #define printInfo printf
59 
60 /* define some macros (if not already defined) */
61 #ifndef FALSE
62 #define FALSE 0
63 #define TRUE 1
64 #endif
65 #ifndef MAX
66 #define MAX(x,y) ((x) >= (y) ? (x) : (y))
67 #define MIN(x,y) ((x) <= (y) ? (x) : (y))
68 #endif
69 
70 #ifndef SCIP_LONGINT_FORMAT
71 #if defined(_WIN32) || defined(_WIN64)
72 #define LONGINT_FORMAT "I64d"
73 #else
74 #define LONGINT_FORMAT "lld"
75 #endif
76 #else
77 #define LONGINT_FORMAT SCIP_LONGINT_FORMAT
78 #endif
79 
80 #ifndef SCIP_MAXMEMSIZE
81 /* we take SIZE_MAX / 2 to detect negative sizes which got a very large value when casting to (unsigned) size_t */
82 #define MAXMEMSIZE SIZE_MAX / 2
83 #else
84 #define MAXMEMSIZE SCIP_MAXMEMSIZE
85 #endif
86 
87 /* define inline (if not already defined) */
88 #ifndef INLINE
89 #if defined(_WIN32) || defined(_WIN64) || defined(__STDC__)
90 #define INLINE __inline
91 #else
92 #define INLINE inline
93 #endif
94 #endif
95 
96 /*************************************************************************************
97  * Standard Memory Management
98  *
99  * In debug mode, these methods extend malloc() and free() by logging all currently
100  * allocated memory elements in an allocation list. This can be used as a simple leak
101  * detection.
102  *************************************************************************************/
103 #if !defined(NDEBUG) && defined(NPARASCIP)
104 
105 typedef struct Memlist MEMLIST; /**< memory list for debugging purposes */
106 
107 /** memory list for debugging purposes */
108 struct Memlist
109 {
110  const void* ptr; /**< pointer to allocated memory */
111  size_t size; /**< size of memory element */
112  char* filename; /**< source file where the allocation was performed */
113  int line; /**< line number in source file where the allocation was performed */
114  MEMLIST* next; /**< next entry in the memory list */
115 };
116 
117 static MEMLIST* memlist = NULL; /**< global memory list for debugging purposes */
118 static size_t memused = 0; /**< number of allocated bytes */
119 
120 #ifdef CHECKMEM
121 /** checks, whether the number of allocated bytes match the entries in the memory list */
122 static
123 void checkMemlist(
124  void
125  )
126 {
127  MEMLIST* list = memlist;
128  size_t used = 0;
129 
130  while( list != NULL )
131  {
132  used += list->size;
133  list = list->next;
134  }
135  assert(used == memused);
136 }
137 #else
138 #define checkMemlist() /**/
139 #endif
140 
141 /** adds entry to list of allocated memory */
142 static
143 void addMemlistEntry(
144  const void* ptr, /**< pointer to allocated memory */
145  size_t size, /**< size of memory element */
146  const char* filename, /**< source file where the allocation was performed */
147  int line /**< line number in source file where the allocation was performed */
148  )
149 {
150  MEMLIST* list;
151 
152  assert(ptr != NULL && size > 0);
153 
154  list = (MEMLIST*)malloc(sizeof(MEMLIST));
155  assert(list != NULL);
156 
157  list->ptr = ptr;
158  list->size = size;
159  list->filename = strdup(filename);
160  assert(list->filename != NULL);
161  list->line = line;
162  list->next = memlist;
163  memlist = list;
164  memused += size;
165  checkMemlist();
166 }
167 
168 /** removes entry from the list of allocated memory */
169 static
170 void removeMemlistEntry(
171  const void* ptr, /**< pointer to allocated memory */
172  const char* filename, /**< source file where the deallocation was performed */
173  int line /**< line number in source file where the deallocation was performed */
174  )
175 {
176  MEMLIST* list;
177  MEMLIST** listptr;
178 
179  assert(ptr != NULL);
180 
181  list = memlist;
182  listptr = &memlist;
183  while( list != NULL && ptr != list->ptr )
184  {
185  listptr = &(list->next);
186  list = list->next;
187  }
188  if( list != NULL )
189  {
190  assert(ptr == list->ptr);
191 
192  *listptr = list->next;
193  assert( list->size <= memused );
194  memused -= list->size;
195  free(list->filename);
196  free(list);
197  }
198  else
199  {
200  printErrorHeader(filename, line);
201  printError("Tried to free unknown pointer <%p>.\n", ptr);
202  }
203  checkMemlist();
204 }
205 
206 /** returns the size of an allocated memory element */
208  const void* ptr /**< pointer to allocated memory */
209  )
210 {
211  MEMLIST* list;
212 
213  list = memlist;
214  while( list != NULL && ptr != list->ptr )
215  list = list->next;
216  if( list != NULL )
217  return list->size;
218  else
219  return 0;
220 }
221 
222 /** outputs information about currently allocated memory to the screen */
224  void
225  )
226 {
227  MEMLIST* list;
228  size_t used = 0;
229 
230  printInfo("Allocated memory:\n");
231  list = memlist;
232  while( list != NULL )
233  {
234  printInfo("%12p %8llu %s:%d\n", list->ptr, (unsigned long long) list->size, list->filename, list->line);
235  used += list->size;
236  list = list->next;
237  }
238  printInfo("Total: %8llu\n", (unsigned long long) memused);
239  if( used != memused )
240  {
241  errorMessage("Used memory in list sums up to %llu instead of %llu\n", (unsigned long long)used, (unsigned long long)memused);
242  }
243  checkMemlist();
244 }
245 
246 /** displays a warning message on the screen, if allocated memory exists */
248  void
249  )
250 {
251  if( memlist != NULL || memused > 0 )
252  {
253  warningMessage("Memory list not empty.\n");
255  }
256 }
257 
258 /** returns total number of allocated bytes */
259 long long BMSgetMemoryUsed_call(
260  void
261  )
262 {
263  return (long long) memused;
264 }
265 
266 #else
267 
268 /* these methods are implemented even in optimized mode, such that a program, that includes memory.h in debug mode
269  * but links the optimized version compiles
270  */
271 
272 /** returns the size of an allocated memory element */
274  const void* ptr /**< pointer to allocated memory */
275  )
276 {
277  return 0;
278 }
279 
280 /** outputs information about currently allocated memory to the screen */
282  void
283  )
284 {
285 #ifdef NPARASCIP
286  printInfo("Optimized version of memory shell linked - no memory diagnostics available.\n");
287 #endif
288 }
289 
290 /** displays a warning message on the screen, if allocated memory exists */
292  void
293  )
294 {
295 #ifdef NPARASCIP
296  printInfo("Optimized version of memory shell linked - no memory leakage check available.\n");
297 #endif
298 }
299 
300 /** returns total number of allocated bytes */
302  void
303  )
304 {
305  return 0;
306 }
307 
308 #endif
309 
310 /** allocates array and initializes it with 0; returns NULL if memory allocation failed */
312  size_t num, /**< number of memory element to allocate */
313  size_t typesize, /**< size of one memory element to allocate */
314  const char* filename, /**< source file where the allocation is performed */
315  int line /**< line number in source file where the allocation is performed */
316  )
317 {
318  void* ptr;
319 
320  debugMessage("calloc %llu elements of %llu bytes [%s:%d]\n", (unsigned long long)num, (unsigned long long)typesize,
321  filename, line);
322 
323 #ifndef NDEBUG
324  if ( num > (MAXMEMSIZE / typesize) )
325  {
326  printErrorHeader(filename, line);
327  printError("Tried to allocate standard memory of size exceeding %u.\n", MAXMEMSIZE);
328  return NULL;
329  }
330 #endif
331 
332  num = MAX(num, 1);
333  typesize = MAX(typesize, 1);
334  ptr = calloc(num, typesize);
335 
336  if( ptr == NULL )
337  {
338  printErrorHeader(filename, line);
339  printError("Insufficient memory for allocation of %llu bytes.\n", (unsigned long long)(num * typesize));
340  }
341 #if !defined(NDEBUG) && defined(NPARASCIP)
342  else
343  addMemlistEntry(ptr, num*typesize, filename, line);
344 #endif
345 
346  return ptr;
347 }
348 
349 /** allocates memory; returns NULL if memory allocation failed */
351  size_t size, /**< size of memory element to allocate */
352  const char* filename, /**< source file where the allocation is performed */
353  int line /**< line number in source file where the allocation is performed */
354  )
355 {
356  void* ptr;
357 
358  debugMessage("malloc %llu bytes [%s:%d]\n", (unsigned long long)size, filename, line);
359 
360 #ifndef NDEBUG
361  if ( size > MAXMEMSIZE )
362  {
363  printErrorHeader(filename, line);
364  printError("Tried to allocate standard memory of size exceeding %u.\n", MAXMEMSIZE);
365  return NULL;
366  }
367 #endif
368 
369  size = MAX(size, 1);
370  ptr = malloc(size);
371 
372  if( ptr == NULL )
373  {
374  printErrorHeader(filename, line);
375  printError("Insufficient memory for allocation of %llu bytes.\n", (unsigned long long)size);
376  }
377 #if !defined(NDEBUG) && defined(NPARASCIP)
378  else
379  addMemlistEntry(ptr, size, filename, line);
380 #endif
381 
382  return ptr;
383 }
384 
385 /** allocates array; returns NULL if memory allocation failed */
387  size_t num, /**< number of components of array to allocate */
388  size_t typesize, /**< size of each component */
389  const char* filename, /**< source file where the allocation is performed */
390  int line /**< line number in source file where the allocation is performed */
391  )
392 {
393  void* ptr;
394  size_t size;
395 
396  debugMessage("malloc %llu elements of %llu bytes [%s:%d]\n",
397  (unsigned long long)num, (unsigned long long)typesize, filename, line);
398 
399 #ifndef NDEBUG
400  if ( num > (MAXMEMSIZE / typesize) )
401  {
402  printErrorHeader(filename, line);
403  printError("Tried to allocate standard memory of size exceeding %u.\n", MAXMEMSIZE);
404  return NULL;
405  }
406 #endif
407 
408  size = num * typesize;
409  size = MAX(size, 1);
410  ptr = malloc(size);
411 
412  if( ptr == NULL )
413  {
414  printErrorHeader(filename, line);
415  printError("Insufficient memory for allocation of %llu bytes.\n", (unsigned long long)size);
416  }
417 #if !defined(NDEBUG) && defined(NPARASCIP)
418  else
419  addMemlistEntry(ptr, size, filename, line);
420 #endif
421 
422  return ptr;
423 }
424 
425 /** allocates memory; returns NULL if memory allocation failed */
427  void* ptr, /**< pointer to memory to reallocate */
428  size_t size, /**< new size of memory element */
429  const char* filename, /**< source file where the reallocation is performed */
430  int line /**< line number in source file where the reallocation is performed */
431  )
432 {
433  void* newptr;
434 
435 #if !defined(NDEBUG) && defined(NPARASCIP)
436  if( ptr != NULL )
437  removeMemlistEntry(ptr, filename, line);
438 #endif
439 
440 #ifndef NDEBUG
441  if ( size > MAXMEMSIZE )
442  {
443  printErrorHeader(filename, line);
444  printError("Tried to allocate standard memory of size exceeding %llu.\n", MAXMEMSIZE);
445  return NULL;
446  }
447 #endif
448 
449  size = MAX(size, 1);
450  newptr = realloc(ptr, size);
451 
452  if( newptr == NULL )
453  {
454  printErrorHeader(filename, line);
455  printError("Insufficient memory for reallocation of %llu bytes.\n", (unsigned long long)size);
456  }
457 #if !defined(NDEBUG) && defined(NPARASCIP)
458  else
459  addMemlistEntry(newptr, size, filename, line);
460 #endif
461 
462  return newptr;
463 }
464 
465 /** reallocates array; returns NULL if memory allocation failed */
467  void* ptr, /**< pointer to memory to reallocate */
468  size_t num, /**< number of components of array to allocate */
469  size_t typesize, /**< size of each component */
470  const char* filename, /**< source file where the reallocation is performed */
471  int line /**< line number in source file where the reallocation is performed */
472  )
473 {
474  void* newptr;
475  size_t size;
476 
477 #if !defined(NDEBUG) && defined(NPARASCIP)
478  if( ptr != NULL )
479  removeMemlistEntry(ptr, filename, line);
480 #endif
481 
482 #ifndef NDEBUG
483  if ( num > (MAXMEMSIZE / typesize) )
484  {
485  printErrorHeader(filename, line);
486  printError("Tried to allocate standard memory of size exceeding %llu.\n", MAXMEMSIZE);
487  return NULL;
488  }
489 #endif
490 
491  size = num * typesize;
492  size = MAX(size, 1);
493  newptr = realloc(ptr, size);
494 
495  if( newptr == NULL )
496  {
497  printErrorHeader(filename, line);
498  printError("Insufficient memory for reallocation of %llu bytes.\n", (unsigned long long)size);
499  }
500 #if !defined(NDEBUG) && defined(NPARASCIP)
501  else
502  addMemlistEntry(newptr, size, filename, line);
503 #endif
504 
505  return newptr;
506 }
507 
508 /** clears a memory element (i.e. fills it with zeros) */
510  void* ptr, /**< pointer to memory element */
511  size_t size /**< size of memory element */
512  )
513 {
514  if( size > 0 )
515  {
516  assert(ptr != NULL);
517  memset(ptr, 0, size);
518  }
519 }
520 
521 /** copies the contents of one memory element into another memory element */
523  void* ptr, /**< pointer to target memory element */
524  const void* source, /**< pointer to source memory element */
525  size_t size /**< size of memory element to copy */
526  )
527 {
528  if( size > 0 )
529  {
530  assert(ptr != NULL);
531  assert(source != NULL);
532  memcpy(ptr, source, size);
533  }
534 }
535 
536 /** moves the contents of one memory element into another memory element, should be used if both elements overlap,
537  * otherwise BMScopyMemory is faster
538  */
540  void* ptr, /**< pointer to target memory element */
541  const void* source, /**< pointer to source memory element */
542  size_t size /**< size of memory element to copy */
543  )
544 {
545  if( size > 0 )
546  {
547  assert(ptr != NULL);
548  assert(source != NULL);
549  memmove(ptr, source, size);
550  }
551 }
552 
553 /** allocates memory and copies the contents of the given memory element into the new memory element */
555  const void* source, /**< pointer to source memory element */
556  size_t size, /**< size of memory element to copy */
557  const char* filename, /**< source file where the duplication is performed */
558  int line /**< line number in source file where the duplication is performed */
559  )
560 {
561  void* ptr;
562 
563  assert(source != NULL || size == 0);
564 
565  ptr = BMSallocMemory_call(size, filename, line);
566  if( ptr != NULL )
567  BMScopyMemory_call(ptr, source, size);
568 
569  return ptr;
570 }
571 
572 /** allocates array and copies the contents of the given source array into the new array */
574  const void* source, /**< pointer to source memory element */
575  size_t num, /**< number of components of array to allocate */
576  size_t typesize, /**< size of each component */
577  const char* filename, /**< source file where the duplication is performed */
578  int line /**< line number in source file where the duplication is performed */
579  )
580 {
581  void* ptr;
582 
583  assert(source != NULL || num == 0);
584 
585  ptr = BMSallocMemoryArray_call(num, typesize, filename, line);
586  if( ptr != NULL )
587  BMScopyMemory_call(ptr, source, num * typesize);
588 
589  return ptr;
590 }
591 
592 /** frees an allocated memory element and sets pointer to NULL */
594  void** ptr, /**< pointer to pointer to memory element */
595  const char* filename, /**< source file where the deallocation is performed */
596  int line /**< line number in source file where the deallocation is performed */
597  )
598 {
599  assert( ptr != NULL );
600  if( *ptr != NULL )
601  {
602 #if !defined(NDEBUG) && defined(NPARASCIP)
603  removeMemlistEntry(*ptr, filename, line);
604 #endif
605  free(*ptr);
606  *ptr = NULL;
607  }
608  else
609  {
610  printErrorHeader(filename, line);
611  printError("Tried to free null pointer.\n");
612  }
613 }
614 
615 /** frees an allocated memory element if pointer is not NULL and sets pointer to NULL */
617  void** ptr, /**< pointer to pointer to memory element */
618  const char* filename, /**< source file where the deallocation is performed */
619  int line /**< line number in source file where the deallocation is performed */
620  )
621 {
622  assert( ptr != NULL );
623  if ( *ptr != NULL )
624  {
625 #if !defined(NDEBUG) && defined(NPARASCIP)
626  removeMemlistEntry(*ptr, filename, line);
627 #endif
628  free(*ptr);
629  *ptr = NULL;
630  }
631 }
632 
633 
634 
635 
636 /********************************************************************
637  * Chunk Memory Management
638  *
639  * Efficient memory management for multiple objects of the same size
640  ********************************************************************/
641 
642 /*
643  * block memory methods for faster memory access
644  */
645 
646 #define CHUNKLENGTH_MIN 1024 /**< minimal size of a chunk (in bytes) */
647 #define CHUNKLENGTH_MAX 1048576 /**< maximal size of a chunk (in bytes) */
648 #define STORESIZE_MAX 8192 /**< maximal number of elements in one chunk */
649 #define GARBAGE_SIZE 256 /**< size of lazy free list to start garbage collection */
650 #define ALIGNMENT (sizeof(FREELIST)) /**< minimal alignment of chunks */
651 
652 typedef struct Freelist FREELIST; /**< linked list of free memory elements */
653 typedef struct Chunk CHUNK; /**< chunk of memory elements */
654 
655 /** linked list of free memory elements */
656 struct Freelist
657 {
658  FREELIST* next; /**< pointer to the next free element */
659 };
660 
661 /** chunk of memory elements */
662 struct Chunk
663 {
664  void* store; /**< data storage */
665  void* storeend; /**< points to the first byte in memory not belonging to the chunk */
666  FREELIST* eagerfree; /**< eager free list */
667  CHUNK* nexteager; /**< next chunk, that has a non-empty eager free list */
668  CHUNK* preveager; /**< previous chunk, that has a non-empty eager free list */
669  BMS_CHKMEM* chkmem; /**< chunk memory collection, this chunk belongs to */
670  int elemsize; /**< size of each element in the chunk */
671  int storesize; /**< number of elements in this chunk */
672  int eagerfreesize; /**< number of elements in the eager free list */
673  int arraypos; /**< position of chunk in the chunk header's chunkarray */
674 }; /* the chunk data structure must be aligned, because the storage is allocated directly behind the chunk header! */
675 
676 /** collection of memory chunks of the same element size */
677 struct BMS_ChkMem
678 {
679  FREELIST* lazyfree; /**< lazy free list of unused memory elements of all chunks of this chunk block */
680  CHUNK** chunks; /**< array with the chunks of the chunk header */
681  CHUNK* firsteager; /**< first chunk with a non-empty eager free list */
682  BMS_CHKMEM* nextchkmem; /**< next chunk block in the block memory's hash list */
683  int elemsize; /**< size of each memory element in the chunk memory */
684  int chunkssize; /**< size of the chunks array */
685  int nchunks; /**< number of chunks in this chunk block (used slots of the chunk array) */
686  int lastchunksize; /**< number of elements in the last allocated chunk */
687  int storesize; /**< total number of elements in this chunk block */
688  int lazyfreesize; /**< number of elements in the lazy free list of the chunk block */
689  int eagerfreesize; /**< total number of elements of all eager free lists of the block's chunks */
690  int initchunksize; /**< number of elements in the first chunk */
691  int garbagefactor; /**< garbage collector is called, if at least garbagefactor * avg. chunksize
692  * elements are free (-1: disable garbage collection) */
693 #ifndef NDEBUG
694  char* filename; /**< source file, where this chunk block was created */
695  int line; /**< source line, where this chunk block was created */
696  int ngarbagecalls; /**< number of times, the garbage collector was called */
697  int ngarbagefrees; /**< number of chunks, the garbage collector freed */
698 #endif
699 };
700 
701 
702 /** aligns the given byte size corresponding to the minimal alignment */
703 static
705  size_t* size /**< pointer to the size to align */
706  )
707 {
708  if( *size < ALIGNMENT )
709  *size = ALIGNMENT;
710  else
711  *size = ((*size + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT;
712 }
713 
714 /** aligns the given byte size corresponding to the minimal alignment for chunk and block memory */
716  size_t* size /**< pointer to the size to align */
717  )
718 {
719  assert(ALIGNMENT == sizeof(void*));
720  alignSize(size);
721 }
722 
723 /** checks whether the given size meets the alignment conditions for chunk and block memory */
725  size_t size /**< size to check for alignment */
726  )
727 {
728  assert(ALIGNMENT == sizeof(void*));
729  return( size >= ALIGNMENT && size % ALIGNMENT == 0 );
730 }
731 
732 #ifndef NDEBUG
733 /** checks, if the given pointer belongs to the given chunk */
734 static
736  const CHUNK* chunk, /**< memory chunk */
737  const void* ptr /**< pointer */
738  )
739 {
740  assert(chunk != NULL);
741  assert(chunk->store <= chunk->storeend);
742 
743  return (ptr >= (void*)(chunk->store) && ptr < (void*)(chunk->storeend));
744 }
745 #endif
746 
747 /** given a pointer, finds the chunk this pointer points to in the chunk array of the given chunk block;
748  * binary search is used;
749  * returns NULL if the pointer does not belong to the chunk block
750  */
751 static
753  const BMS_CHKMEM* chkmem, /**< chunk block */
754  const void* ptr /**< pointer */
755  )
756 {
757  CHUNK* chunk;
758  int left;
759  int right;
760  int middle;
761 
762  assert(chkmem != NULL);
763  assert(ptr != NULL);
764 
765  /* binary search for the chunk containing the ptr */
766  left = 0;
767  right = chkmem->nchunks-1;
768  while( left <= right )
769  {
770  middle = (left+right)/2;
771  assert(0 <= middle && middle < chkmem->nchunks);
772  chunk = chkmem->chunks[middle];
773  assert(chunk != NULL);
774  if( ptr < chunk->store )
775  right = middle-1;
776  else if( ptr >= chunk->storeend )
777  left = middle+1;
778  else
779  return chunk;
780  }
781 
782  /* ptr was not found in chunk */
783  return NULL;
784 }
785 
786 /** checks, if a pointer belongs to a chunk of the given chunk block */
787 static
789  const BMS_CHKMEM* chkmem, /**< chunk block */
790  const void* ptr /**< pointer */
791  )
792 {
793  assert(chkmem != NULL);
794 
795  return (findChunk(chkmem, ptr) != NULL);
796 }
797 
798 
799 
800 /*
801  * debugging methods
802  */
803 
804 #ifdef CHECKMEM
805 /** sanity check for a memory chunk */
806 static
807 void checkChunk(
808  const CHUNK* chunk /**< memory chunk */
809  )
810 {
811  FREELIST* eager;
812  int eagerfreesize;
813 
814  assert(chunk != NULL);
815  assert(chunk->store != NULL);
816  assert(chunk->storeend == (void*)((char*)(chunk->store) + chunk->elemsize * chunk->storesize));
817  assert(chunk->chkmem != NULL);
818  assert(chunk->chkmem->elemsize == chunk->elemsize);
819 
820  if( chunk->eagerfree == NULL )
821  assert(chunk->nexteager == NULL && chunk->preveager == NULL);
822  else if( chunk->preveager == NULL )
823  assert(chunk->chkmem->firsteager == chunk);
824 
825  if( chunk->nexteager != NULL )
826  assert(chunk->nexteager->preveager == chunk);
827  if( chunk->preveager != NULL )
828  assert(chunk->preveager->nexteager == chunk);
829 
830  eagerfreesize = 0;
831  eager = chunk->eagerfree;
832  while( eager != NULL )
833  {
834  assert(isPtrInChunk(chunk, eager));
835  eagerfreesize++;
836  eager = eager->next;
837  }
838  assert(chunk->eagerfreesize == eagerfreesize);
839 }
840 
841 /** sanity check for a chunk block */
842 static
843 void checkChkmem(
844  const BMS_CHKMEM* chkmem /**< chunk block */
845  )
846 {
847  CHUNK* chunk;
848  FREELIST* lazy;
849  int nchunks;
850  int storesize;
851  int lazyfreesize;
852  int eagerfreesize;
853  int i;
854 
855  assert(chkmem != NULL);
856  assert(chkmem->chunks != NULL || chkmem->chunkssize == 0);
857  assert(chkmem->nchunks <= chkmem->chunkssize);
858 
859  nchunks = 0;
860  storesize = 0;
861  lazyfreesize = 0;
862  eagerfreesize = 0;
863 
864  for( i = 0; i < chkmem->nchunks; ++i )
865  {
866  chunk = chkmem->chunks[i];
867  assert(chunk != NULL);
868 
869  checkChunk(chunk);
870  nchunks++;
871  storesize += chunk->storesize;
872  eagerfreesize += chunk->eagerfreesize;
873  }
874  assert(chkmem->nchunks == nchunks);
875  assert(chkmem->storesize == storesize);
876  assert(chkmem->eagerfreesize == eagerfreesize);
877 
878  assert((chkmem->eagerfreesize == 0) ^ (chkmem->firsteager != NULL));
879 
880  if( chkmem->firsteager != NULL )
881  assert(chkmem->firsteager->preveager == NULL);
882 
883  lazy = chkmem->lazyfree;
884  while( lazy != NULL )
885  {
886  chunk = findChunk(chkmem, lazy);
887  assert(chunk != NULL);
888  assert(chunk->chkmem == chkmem);
889  lazyfreesize++;
890  lazy = lazy->next;
891  }
892  assert(chkmem->lazyfreesize == lazyfreesize);
893 }
894 #else
895 #define checkChunk(chunk) /**/
896 #define checkChkmem(chkmem) /**/
897 #endif
898 
899 
900 /** links chunk to the block's chunk array, sort it by store pointer;
901  * returns TRUE if successful, FALSE otherwise
902  */
903 static
905  BMS_CHKMEM* chkmem, /**< chunk block */
906  CHUNK* chunk /**< memory chunk */
907  )
908 {
909  CHUNK* curchunk;
910  int left;
911  int right;
912  int middle;
913  int i;
914 
915  assert(chkmem != NULL);
916  assert(chkmem->nchunks <= chkmem->chunkssize);
917  assert(chunk != NULL);
918  assert(chunk->store != NULL);
919 
920  debugMessage("linking chunk %p to chunk block %p [elemsize:%d, %d chunks]\n",
921  (void*)chunk, (void*)chkmem, chkmem->elemsize, chkmem->nchunks);
922 
923  /* binary search for the position to insert the chunk */
924  left = -1;
925  right = chkmem->nchunks;
926  while( left < right-1 )
927  {
928  middle = (left+right)/2;
929  assert(0 <= middle && middle < chkmem->nchunks);
930  assert(left < middle && middle < right);
931  curchunk = chkmem->chunks[middle];
932  assert(curchunk != NULL);
933  if( chunk->store < curchunk->store )
934  right = middle;
935  else
936  {
937  assert(chunk->store >= curchunk->storeend);
938  left = middle;
939  }
940  }
941  assert(-1 <= left && left < chkmem->nchunks);
942  assert(0 <= right && right <= chkmem->nchunks);
943  assert(left+1 == right);
944  assert(left == -1 || chkmem->chunks[left]->storeend <= chunk->store);
945  assert(right == chkmem->nchunks || chunk->storeend <= chkmem->chunks[right]->store);
946 
947  /* ensure, that chunk array can store the additional chunk */
948  if( chkmem->nchunks == chkmem->chunkssize )
949  {
950  chkmem->chunkssize = 2*(chkmem->nchunks+1);
951  BMSreallocMemoryArray(&chkmem->chunks, chkmem->chunkssize);
952  if( chkmem->chunks == NULL )
953  return FALSE;
954  }
955  assert(chkmem->nchunks < chkmem->chunkssize);
956  assert(chkmem->chunks != NULL);
957 
958  /* move all chunks from 'right' to end one position to the right */
959  for( i = chkmem->nchunks; i > right; --i )
960  {
961  chkmem->chunks[i] = chkmem->chunks[i-1];
962  chkmem->chunks[i]->arraypos = i;
963  }
964 
965  /* insert chunk at position 'right' */
966  chunk->arraypos = right;
967  chkmem->chunks[right] = chunk;
968  chkmem->nchunks++;
969  chkmem->storesize += chunk->storesize;
970 
971  return TRUE;
972 }
973 
974 /** unlinks chunk from the chunk block's chunk list */
975 static
977  CHUNK* chunk /**< memory chunk */
978  )
979 {
980  BMS_CHKMEM* chkmem;
981  int i;
982 
983  assert(chunk != NULL);
984  assert(chunk->eagerfree == NULL);
985  assert(chunk->nexteager == NULL);
986  assert(chunk->preveager == NULL);
987 
988  chkmem = chunk->chkmem;
989  assert(chkmem != NULL);
990  assert(chkmem->elemsize == chunk->elemsize);
991  assert(0 <= chunk->arraypos && chunk->arraypos < chkmem->nchunks);
992  assert(chkmem->chunks[chunk->arraypos] == chunk);
993 
994  debugMessage("unlinking chunk %p from chunk block %p [elemsize:%d, %d chunks]\n",
995  (void*)chunk, (void*)chkmem, chkmem->elemsize, chkmem->nchunks);
996 
997  /* remove the chunk from the chunks of the chunk block */
998  for( i = chunk->arraypos; i < chkmem->nchunks-1; ++i )
999  {
1000  chkmem->chunks[i] = chkmem->chunks[i+1];
1001  chkmem->chunks[i]->arraypos = i;
1002  }
1003  chkmem->nchunks--;
1004  chkmem->storesize -= chunk->storesize;
1005 }
1006 
1007 /** links chunk to the chunk block's eager chunk list */
1008 static
1010  BMS_CHKMEM* chkmem, /**< chunk block */
1011  CHUNK* chunk /**< memory chunk */
1012  )
1013 {
1014  assert(chunk->chkmem == chkmem);
1015  assert(chunk->nexteager == NULL);
1016  assert(chunk->preveager == NULL);
1017 
1018  chunk->nexteager = chkmem->firsteager;
1019  chunk->preveager = NULL;
1020  if( chkmem->firsteager != NULL )
1021  {
1022  assert(chkmem->firsteager->preveager == NULL);
1023  chkmem->firsteager->preveager = chunk;
1024  }
1025  chkmem->firsteager = chunk;
1026 }
1027 
1028 /** unlinks chunk from the chunk block's eager chunk list */
1029 static
1031  CHUNK* chunk /**< memory chunk */
1032  )
1033 {
1034  assert(chunk != NULL);
1035  assert(chunk->eagerfreesize == 0 || chunk->eagerfreesize == chunk->storesize);
1036 
1037  if( chunk->nexteager != NULL )
1038  chunk->nexteager->preveager = chunk->preveager;
1039  if( chunk->preveager != NULL )
1040  chunk->preveager->nexteager = chunk->nexteager;
1041  else
1042  {
1043  assert(chunk->chkmem->firsteager == chunk);
1044  chunk->chkmem->firsteager = chunk->nexteager;
1045  }
1046  chunk->nexteager = NULL;
1047  chunk->preveager = NULL;
1048  chunk->eagerfree = NULL;
1049 }
1050 
1051 /** creates a new memory chunk in the given chunk block and adds memory elements to the lazy free list;
1052  * returns TRUE if successful, FALSE otherwise
1053  */
1054 static
1056  BMS_CHKMEM* chkmem /**< chunk block */
1057  )
1058 {
1059  CHUNK *newchunk;
1060  FREELIST *freelist;
1061  int i;
1062  int storesize;
1063  int retval;
1064 
1065  assert(chkmem != NULL);
1066 
1067  debugMessage("creating new chunk in chunk block %p [elemsize: %d]\n", (void*)chkmem, chkmem->elemsize);
1068 
1069  /* calculate store size */
1070  if( chkmem->nchunks == 0 )
1071  storesize = chkmem->initchunksize;
1072  else
1073  storesize = 2 * chkmem->lastchunksize;
1074  assert(storesize > 0);
1075  storesize = MAX(storesize, CHUNKLENGTH_MIN / chkmem->elemsize);
1076  storesize = MIN(storesize, CHUNKLENGTH_MAX / chkmem->elemsize);
1077  storesize = MIN(storesize, STORESIZE_MAX);
1078  storesize = MAX(storesize, 1);
1079  chkmem->lastchunksize = storesize;
1080 
1081  /* create new chunk */
1082  assert(BMSisAligned(sizeof(CHUNK)));
1083  assert( chkmem->elemsize < INT_MAX / storesize );
1084  assert( sizeof(CHUNK) < MAXMEMSIZE - (size_t)(storesize * chkmem->elemsize) ); /*lint !e571 !e647*/
1085  BMSallocMemorySize(&newchunk, sizeof(CHUNK) + storesize * chkmem->elemsize);
1086  if( newchunk == NULL )
1087  return FALSE;
1088 
1089  /* the store is allocated directly behind the chunk header */
1090  newchunk->store = (void*) ((char*) newchunk + sizeof(CHUNK));
1091  newchunk->storeend = (void*) ((char*) newchunk->store + storesize * chkmem->elemsize);
1092  newchunk->eagerfree = NULL;
1093  newchunk->nexteager = NULL;
1094  newchunk->preveager = NULL;
1095  newchunk->chkmem = chkmem;
1096  newchunk->elemsize = chkmem->elemsize;
1097  newchunk->storesize = storesize;
1098  newchunk->eagerfreesize = 0;
1099  newchunk->arraypos = -1;
1100 
1101  debugMessage("allocated new chunk %p: %d elements with size %d\n", (void*)newchunk, newchunk->storesize, newchunk->elemsize);
1102 
1103  /* add new memory to the lazy free list */
1104  for( i = 0; i < newchunk->storesize - 1; ++i )
1105  {
1106  freelist = (FREELIST*) ((char*) (newchunk->store) + i * chkmem->elemsize); /*lint !e826*/
1107  freelist->next = (FREELIST*) ((char*) (newchunk->store) + (i + 1) * chkmem->elemsize); /*lint !e826*/
1108  }
1109 
1110  freelist = (FREELIST*) ((char*) (newchunk->store) + (newchunk->storesize - 1) * chkmem->elemsize); /*lint !e826*/
1111  freelist->next = chkmem->lazyfree;
1112  chkmem->lazyfree = (FREELIST*) (newchunk->store);
1113  chkmem->lazyfreesize += newchunk->storesize;
1114 
1115  /* link chunk into chunk block */
1116  retval = linkChunk(chkmem, newchunk);
1117 
1118  checkChkmem(chkmem);
1119 
1120  return retval;
1121 }
1122 
1123 /** destroys a chunk without updating the chunk lists */
1124 static
1126  CHUNK* chunk /**< memory chunk */
1127  )
1128 {
1129  assert(chunk != NULL);
1130 
1131  debugMessage("destroying chunk %p\n", (void*)chunk);
1132 
1133  /* free chunk header and store (allocated in one call) */
1134  BMSfreeMemory(&chunk);
1135 }
1136 
1137 /** removes a completely unused chunk, i.e. a chunk with all elements in the eager free list */
1138 static
1140  CHUNK* chunk /**< memory chunk */
1141  )
1142 {
1143  assert(chunk != NULL);
1144  assert(chunk->store != NULL);
1145  assert(chunk->eagerfree != NULL);
1146  assert(chunk->chkmem != NULL);
1147  assert(chunk->chkmem->chunks != NULL);
1148  assert(chunk->chkmem->firsteager != NULL);
1149  assert(chunk->eagerfreesize == chunk->storesize);
1150 
1151  debugMessage("freeing chunk %p of chunk block %p [elemsize: %d]\n", (void*)chunk, (void*)chunk->chkmem, chunk->chkmem->elemsize);
1152 
1153  /* count the deleted eager free slots */
1154  chunk->chkmem->eagerfreesize -= chunk->eagerfreesize;
1155  assert(chunk->chkmem->eagerfreesize >= 0);
1156 
1157  /* remove chunk from eager chunk list */
1158  unlinkEagerChunk(chunk);
1159 
1160  /* remove chunk from chunk list */
1161  unlinkChunk(chunk);
1162 
1163  /* destroy the chunk */
1164  destroyChunk(chunk);
1165 }
1166 
1167 /** returns an element of the eager free list and removes it from the list */
1168 static
1170  CHUNK* chunk /**< memory chunk */
1171  )
1172 {
1173  FREELIST* ptr;
1174 
1175  assert(chunk != NULL);
1176  assert(chunk->eagerfree != NULL);
1177  assert(chunk->eagerfreesize > 0);
1178  assert(chunk->chkmem != NULL);
1179 
1180  debugMessage("allocating chunk element in chunk %p [elemsize: %d]\n", (void*)chunk, chunk->chkmem->elemsize);
1181 
1182  /* unlink first element in the eager free list */
1183  ptr = chunk->eagerfree;
1184  chunk->eagerfree = ptr->next;
1185  chunk->eagerfreesize--;
1186  chunk->chkmem->eagerfreesize--;
1187 
1188  assert((chunk->eagerfreesize == 0 && chunk->eagerfree == NULL)
1189  || (chunk->eagerfreesize != 0 && chunk->eagerfree != NULL));
1190  assert(chunk->chkmem->eagerfreesize >= 0);
1191 
1192  /* unlink chunk from eager chunk list if necessary */
1193  if( chunk->eagerfree == NULL )
1194  {
1195  assert(chunk->eagerfreesize == 0);
1196  unlinkEagerChunk(chunk);
1197  }
1198 
1199  checkChunk(chunk);
1200 
1201  return (void*) ptr;
1202 }
1203 
1204 /** puts given pointer into the eager free list and adds the chunk to the eager list of its chunk block, if necessary */
1205 static
1207  CHUNK* chunk, /**< memory chunk */
1208  void* ptr /**< pointer */
1209  )
1210 {
1211  assert(chunk != NULL);
1212  assert(chunk->chkmem != NULL);
1213  assert(isPtrInChunk(chunk, ptr));
1214 
1215  debugMessage("freeing chunk element %p of chunk %p [elemsize: %d]\n", (void*)ptr, (void*)chunk, chunk->chkmem->elemsize);
1216 
1217  /* link chunk to the eager chunk list if necessary */
1218  if( chunk->eagerfree == NULL )
1219  {
1220  assert(chunk->eagerfreesize == 0);
1221  linkEagerChunk(chunk->chkmem, chunk);
1222  }
1223 
1224  /* add ptr to the chunks eager free list */
1225  ((FREELIST*)ptr)->next = chunk->eagerfree;
1226  chunk->eagerfree = (FREELIST*)ptr;
1227  chunk->eagerfreesize++;
1228  chunk->chkmem->eagerfreesize++;
1229 
1230  checkChunk(chunk);
1231 }
1232 
1233 /** creates a new chunk block data structure */
1234 static
1236  int size, /**< element size of the chunk block */
1237  int initchunksize, /**< number of elements in the first chunk of the chunk block */
1238  int garbagefactor /**< garbage collector is called, if at least garbagefactor * avg. chunksize
1239  * elements are free (-1: disable garbage collection) */
1240  )
1241 {
1242  BMS_CHKMEM* chkmem;
1243 
1244  assert(size >= 0);
1245  assert(BMSisAligned((size_t)size)); /*lint !e571*/
1246 
1247  BMSallocMemory(&chkmem);
1248  if( chkmem == NULL )
1249  return NULL;
1250 
1251  chkmem->lazyfree = NULL;
1252  chkmem->chunks = NULL;
1253  chkmem->firsteager = NULL;
1254  chkmem->nextchkmem = NULL;
1255  chkmem->elemsize = size;
1256  chkmem->chunkssize = 0;
1257  chkmem->nchunks = 0;
1258  chkmem->lastchunksize = 0;
1259  chkmem->storesize = 0;
1260  chkmem->lazyfreesize = 0;
1261  chkmem->eagerfreesize = 0;
1262  chkmem->initchunksize = initchunksize;
1263  chkmem->garbagefactor = garbagefactor;
1264 #ifndef NDEBUG
1265  chkmem->filename = NULL;
1266  chkmem->line = 0;
1267  chkmem->ngarbagecalls = 0;
1268  chkmem->ngarbagefrees = 0;
1269 #endif
1270 
1271  return chkmem;
1272 }
1273 
1274 /** destroys all chunks of the chunk block, but keeps the chunk block header structure */
1275 static
1277  BMS_CHKMEM* chkmem /**< chunk block */
1278  )
1279 {
1280  int i;
1281 
1282  assert(chkmem != NULL);
1283 
1284  /* destroy all chunks of the chunk block */
1285  for( i = 0; i < chkmem->nchunks; ++i )
1286  destroyChunk(chkmem->chunks[i]);
1287 
1288  chkmem->lazyfree = NULL;
1289  chkmem->firsteager = NULL;
1290  chkmem->nchunks = 0;
1291  chkmem->lastchunksize = 0;
1292  chkmem->storesize = 0;
1293  chkmem->lazyfreesize = 0;
1294  chkmem->eagerfreesize = 0;
1295 }
1296 
1297 /** deletes chunk block and frees all associated memory chunks */
1298 static
1300  BMS_CHKMEM** chkmem /**< pointer to chunk block */
1301  )
1302 {
1303  assert(chkmem != NULL);
1304  assert(*chkmem != NULL);
1305 
1306  clearChkmem(*chkmem);
1307  BMSfreeMemoryArrayNull(&(*chkmem)->chunks);
1308 
1309 #ifndef NDEBUG
1310  BMSfreeMemoryArrayNull(&(*chkmem)->filename);
1311 #endif
1312 
1313  BMSfreeMemory(chkmem);
1314 }
1315 
1316 /** allocates a new memory element from the chunk block */
1317 static
1319  BMS_CHKMEM* chkmem /**< chunk block */
1320  )
1321 {
1322  FREELIST* ptr;
1323 
1324  assert(chkmem != NULL);
1325 
1326  /* if the lazy freelist is empty, we have to find the memory element somewhere else */
1327  if( chkmem->lazyfree == NULL )
1328  {
1329  assert(chkmem->lazyfreesize == 0);
1330 
1331  /* check for a free element in the eager freelists */
1332  if( chkmem->firsteager != NULL )
1333  return allocChunkElement(chkmem->firsteager);
1334 
1335  /* allocate a new chunk */
1336  if( !createChunk(chkmem) )
1337  return NULL;
1338  }
1339 
1340  /* now the lazy freelist should contain an element */
1341  assert(chkmem->lazyfree != NULL);
1342  assert(chkmem->lazyfreesize > 0);
1343 
1344  ptr = chkmem->lazyfree;
1345  chkmem->lazyfree = ptr->next;
1346  chkmem->lazyfreesize--;
1347 
1348  checkChkmem(chkmem);
1349 
1350  return (void*) ptr;
1351 }
1352 
1353 /** sorts the lazy free list of the chunk block into the eager free lists of the chunks, and removes completely
1354  * unused chunks
1355  */
1356 static
1358  BMS_CHKMEM* chkmem /**< chunk block */
1359  )
1360 {
1361  CHUNK* chunk;
1362  CHUNK* nexteager;
1363  FREELIST* lazyfree;
1364 
1365  assert(chkmem != NULL);
1366 
1367  debugMessage("garbage collection for chunk block %p [elemsize: %d]\n", (void*)chkmem, chkmem->elemsize);
1368 
1369  /* check, if the chunk block is completely unused */
1370  if( chkmem->lazyfreesize + chkmem->eagerfreesize == chkmem->storesize )
1371  {
1372  clearChkmem(chkmem);
1373  return;
1374  }
1375 
1376 #ifndef NDEBUG
1377  chkmem->ngarbagecalls++;
1378 #endif
1379 
1380  /* put the lazy free elements into the eager free lists */
1381  while( chkmem->lazyfree != NULL )
1382  {
1383  /* unlink first element from the lazy free list */
1384  lazyfree = chkmem->lazyfree;
1385  chkmem->lazyfree = chkmem->lazyfree->next;
1386  chkmem->lazyfreesize--;
1387 
1388  /* identify the chunk of the element */
1389  chunk = findChunk(chkmem, (void*)lazyfree);
1390 #ifndef NDEBUG
1391  if( chunk == NULL )
1392  {
1393  errorMessage("chunk for lazy free chunk %p not found in chunk block %p\n", (void*)lazyfree, (void*)chkmem);
1394  }
1395 #endif
1396  assert(chunk != NULL);
1397 
1398  /* add the element to the chunk's eager free list */
1399  freeChunkElement(chunk, (void*)lazyfree);
1400  assert(chunk->eagerfreesize > 0);
1401  }
1402  assert(chkmem->lazyfreesize == 0);
1403 
1404  /* delete completely unused chunks, but keep at least one */
1405  chunk = chkmem->firsteager;
1406  while( chunk != NULL && chkmem->nchunks > 1 )
1407  {
1408  nexteager = chunk->nexteager;
1409  if( chunk->eagerfreesize == chunk->storesize )
1410  {
1411 #ifndef NDEBUG
1412  chkmem->ngarbagefrees++;
1413 #endif
1414  freeChunk(chunk);
1415  }
1416  chunk = nexteager;
1417  }
1418 
1419  checkChkmem(chkmem);
1420 }
1421 
1422 /** frees a memory element and returns it to the lazy freelist of the chunk block */
1423 static
1425  BMS_CHKMEM* chkmem, /**< chunk block */
1426  void* ptr, /**< memory element */
1427  const char* filename, /**< source file of the function call */
1428  int line /**< line number in source file of the function call */
1429  )
1430 { /*lint --e{715}*/
1431  assert(chkmem != NULL);
1432  assert(ptr != NULL);
1433 
1434 #ifdef BMS_CHKMEM
1435  /* check, if ptr belongs to the chunk block */
1436  if( !isPtrInChkmem(chkmem, ptr) )
1437  {
1438  BMS_CHKMEM* correctchkmem;
1439 
1440  printErrorHeader(filename, line);
1441  printError("Pointer %p does not belong to chunk block %p (size: %d).\n", ptr, chkmem, chkmem->elemsize);
1442  }
1443 #endif
1444 
1445  /* put ptr in lazy free list */
1446  ((FREELIST*)ptr)->next = chkmem->lazyfree;
1447  chkmem->lazyfree = (FREELIST*)ptr;
1448  chkmem->lazyfreesize++;
1449 
1450  /* check if we want to apply garbage collection */
1451  if( chkmem->garbagefactor >= 0 && chkmem->nchunks > 0 && chkmem->lazyfreesize >= GARBAGE_SIZE
1452  && chkmem->lazyfreesize + chkmem->eagerfreesize
1453  > chkmem->garbagefactor * (double)(chkmem->storesize) / (double)(chkmem->nchunks) )
1454  {
1455  garbagecollectChkmem(chkmem);
1456  }
1457 
1458  checkChkmem(chkmem);
1459 }
1460 
1461 /** creates a new chunk block data structure */
1463  size_t size, /**< element size of the chunk block */
1464  int initchunksize, /**< number of elements in the first chunk of the chunk block */
1465  int garbagefactor, /**< garbage collector is called, if at least garbagefactor * avg. chunksize
1466  * elements are free (-1: disable garbage collection) */
1467  const char* filename, /**< source file of the function call */
1468  int line /**< line number in source file of the function call */
1469  )
1470 {
1471  BMS_CHKMEM* chkmem;
1472 
1473  alignSize(&size);
1474  chkmem = createChkmem((int) size, initchunksize, garbagefactor);
1475  if( chkmem == NULL )
1476  {
1477  printErrorHeader(filename, line);
1478  printError("Insufficient memory for chunk block.\n");
1479  }
1480  debugMessage("created chunk memory %p [elemsize: %d]\n", (void*)chkmem, (int)size);
1481 
1482  return chkmem;
1483 }
1484 
1485 /** clears a chunk block data structure */
1487  BMS_CHKMEM* chkmem, /**< chunk block */
1488  const char* filename, /**< source file of the function call */
1489  int line /**< line number in source file of the function call */
1490  )
1491 {
1492  debugMessage("clearing chunk memory %p [elemsize: %d]\n", (void*)chkmem, chkmem->elemsize);
1493 
1494  if( chkmem != NULL )
1495  clearChkmem(chkmem);
1496  else
1497  {
1498  printErrorHeader(filename, line);
1499  printError("Tried to clear null chunk block.\n");
1500  }
1501 }
1502 
1503 /** destroys and frees a chunk block data structure */
1505  BMS_CHKMEM** chkmem, /**< pointer to chunk block */
1506  const char* filename, /**< source file of the function call */
1507  int line /**< line number in source file of the function call */
1508  )
1509 {
1510  assert(chkmem != NULL);
1511 
1512  debugMessage("destroying chunk memory %p [elemsize: %d]\n", (void*)*chkmem, (*chkmem)->elemsize);
1513 
1514  if( *chkmem != NULL )
1515  destroyChkmem(chkmem);
1516  else
1517  {
1518  printErrorHeader(filename, line);
1519  printError("Tried to destroy null chunk block.\n");
1520  }
1521 }
1522 
1523 /** allocates a memory element of the given chunk block */
1525  BMS_CHKMEM* chkmem, /**< chunk block */
1526  size_t size, /**< size of memory element to allocate (only needed for sanity check) */
1527  const char* filename, /**< source file of the function call */
1528  int line /**< line number in source file of the function call */
1529  )
1530 {
1531  void* ptr;
1532 
1533  assert(chkmem != NULL);
1534  assert((int)size == chkmem->elemsize);
1535 
1536  /* get memory inside the chunk block */
1537  ptr = allocChkmemElement(chkmem);
1538  if( ptr == NULL )
1539  {
1540  printErrorHeader(filename, line);
1541  printError("Insufficient memory for new chunk.\n");
1542  }
1543  debugMessage("alloced %8llu bytes in %p [%s:%d]\n", (unsigned long long)size, (void*)ptr, filename, line);
1544 
1545  checkChkmem(chkmem);
1546 
1547  return ptr;
1548 }
1549 
1550 /** duplicates a given memory element by allocating a new element of the same chunk block and copying the data */
1552  BMS_CHKMEM* chkmem, /**< chunk block */
1553  const void* source, /**< source memory element */
1554  size_t size, /**< size of memory element to allocate (only needed for sanity check) */
1555  const char* filename, /**< source file of the function call */
1556  int line /**< line number in source file of the function call */
1557  )
1558 {
1559  void* ptr;
1560 
1561  assert(chkmem != NULL);
1562  assert(source != NULL);
1563  assert((int)size == chkmem->elemsize);
1564 
1565  ptr = BMSallocChunkMemory_call(chkmem, size, filename, line);
1566  if( ptr != NULL )
1567  BMScopyMemorySize(ptr, source, chkmem->elemsize);
1568 
1569  return ptr;
1570 }
1571 
1572 /** frees a memory element of the given chunk block and sets pointer to NULL */
1574  BMS_CHKMEM* chkmem, /**< chunk block */
1575  void** ptr, /**< pointer to pointer to memory element to free */
1576  size_t size, /**< size of memory element to allocate (only needed for sanity check) */
1577  const char* filename, /**< source file of the function call */
1578  int line /**< line number in source file of the function call */
1579  )
1580 {
1581  assert(chkmem != NULL);
1582  assert((int)size == chkmem->elemsize);
1583  assert( ptr != NULL );
1584 
1585  if ( *ptr != NULL )
1586  {
1587  debugMessage("free %8d bytes in %p [%s:%d]\n", chkmem->elemsize, *ptr, filename, line);
1588 
1589  /* free memory in chunk block */
1590  freeChkmemElement(chkmem, *ptr, filename, line);
1591  checkChkmem(chkmem);
1592  *ptr = NULL;
1593  }
1594  else
1595  {
1596  printErrorHeader(filename, line);
1597  printError("Tried to free null chunk pointer.\n");
1598  }
1599 }
1600 
1601 /** frees a memory element of the given chunk block if pointer is not NULL and sets pointer to NULL */
1603  BMS_CHKMEM* chkmem, /**< chunk block */
1604  void** ptr, /**< pointer to pointer to memory element to free */
1605  size_t size, /**< size of memory element to allocate (only needed for sanity check) */
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(chkmem != NULL);
1611  assert((int)size == chkmem->elemsize);
1612  assert( ptr != NULL );
1613 
1614  if ( *ptr != NULL )
1615  {
1616  debugMessage("free %8d bytes in %p [%s:%d]\n", chkmem->elemsize, *ptr, filename, line);
1617 
1618  /* free memory in chunk block */
1619  freeChkmemElement(chkmem, *ptr, filename, line);
1620  checkChkmem(chkmem);
1621  *ptr = NULL;
1622  }
1623 }
1624 
1625 /** calls garbage collection of chunk block and frees chunks without allocated memory elements */
1627  BMS_CHKMEM* chkmem /**< chunk block */
1628  )
1629 {
1630  debugMessage("garbage collection on chunk memory %p [elemsize: %d]\n", (void*)chkmem, chkmem->elemsize);
1631 
1632  garbagecollectChkmem(chkmem);
1633 }
1634 
1635 /** returns the number of allocated bytes in the chunk block */
1637  const BMS_CHKMEM* chkmem /**< chunk block */
1638  )
1639 {
1640  long long chkmemused;
1641  int i;
1642 
1643  assert(chkmem != NULL);
1644 
1645  chkmemused = 0;
1646  for( i = 0; i < chkmem->nchunks; ++i )
1647  chkmemused += (long long)(chkmem->chunks[i]->elemsize) * (long long)(chkmem->chunks[i]->storesize);
1648 
1649  return chkmemused;
1650 }
1651 
1652 
1653 
1654 
1655 /***********************************************************
1656  * Block Memory Management
1657  *
1658  * Efficient memory management for objects of varying sizes
1659  ***********************************************************/
1660 
1661 #define CHKHASH_SIZE 1013 /**< size of chunk block hash table; should be prime */
1662 
1663 /** collection of chunk blocks */
1664 struct BMS_BlkMem
1665 {
1666  BMS_CHKMEM* chkmemhash[CHKHASH_SIZE]; /**< hash table with chunk blocks */
1667  long long memused; /**< total number of used bytes in the memory header */
1668  int initchunksize; /**< number of elements in the first chunk of each chunk block */
1669  int garbagefactor; /**< garbage collector is called, if at least garbagefactor * avg. chunksize
1670  * elements are free (-1: disable garbage collection) */
1671 };
1672 
1673 
1674 
1675 /*
1676  * debugging methods
1677  */
1678 
1679 #ifdef CHECKMEM
1680 static
1681 void checkBlkmem(
1682  const BMS_BLKMEM* blkmem /**< block memory */
1683  )
1684 {
1685  const BMS_CHKMEM* chkmem;
1686  int i;
1687 
1688  assert(blkmem != NULL);
1689  assert(blkmem->chkmemhash != NULL);
1690 
1691  for( i = 0; i < CHKHASH_SIZE; ++i )
1692  {
1693  chkmem = blkmem->chkmemhash[i];
1694  while( chkmem != NULL )
1695  {
1696  checkChkmem(chkmem);
1697  chkmem = chkmem->nextchkmem;
1698  }
1699  }
1700 }
1701 #else
1702 #define checkBlkmem(blkmem) /**/
1703 #endif
1704 
1705 
1706 /** finds the chunk block, to whick the given pointer belongs to
1707  *
1708  * This could be done by selecting the chunk block of the corresponding element size, but in a case of an
1709  * error (free gives an incorrect element size), we want to identify and output the correct element size.
1710  */
1711 static
1713  const BMS_BLKMEM* blkmem, /**< block memory */
1714  const void* ptr /**< memory element to search */
1715  )
1716 {
1717  BMS_CHKMEM* chkmem;
1718  int i;
1719 
1720  assert(blkmem != NULL);
1721 
1722  chkmem = NULL;
1723  for( i = 0; chkmem == NULL && i < CHKHASH_SIZE; ++i )
1724  {
1725  chkmem = blkmem->chkmemhash[i];
1726  while( chkmem != NULL && !isPtrInChkmem(chkmem, ptr) )
1727  chkmem = chkmem->nextchkmem;
1728  }
1729 
1730  return chkmem;
1731 }
1732 
1733 /** calculates hash number of memory size */
1734 static
1736  int size /**< element size */
1737  )
1738 {
1739  assert(size >= 0);
1740  assert(BMSisAligned((size_t)size)); /*lint !e571*/
1741 
1742  return (size % CHKHASH_SIZE);
1743 }
1744 
1745 /** creates a block memory allocation data structure */
1747  int initchunksize, /**< number of elements in the first chunk of each chunk block */
1748  int garbagefactor, /**< garbage collector is called, if at least garbagefactor * avg. chunksize
1749  * elements are free (-1: disable garbage collection) */
1750  const char* filename, /**< source file of the function call */
1751  int line /**< line number in source file of the function call */
1752  )
1753 {
1754  BMS_BLKMEM* blkmem;
1755  int i;
1756 
1757  BMSallocMemory(&blkmem);
1758  if( blkmem != NULL )
1759  {
1760  for( i = 0; i < CHKHASH_SIZE; ++i )
1761  blkmem->chkmemhash[i] = NULL;
1762  blkmem->initchunksize = initchunksize;
1763  blkmem->garbagefactor = garbagefactor;
1764  blkmem->memused = 0;
1765  }
1766  else
1767  {
1768  printErrorHeader(filename, line);
1769  printError("Insufficient memory for block memory header.\n");
1770  }
1771 
1772  return blkmem;
1773 }
1774 
1775 /** frees all chunk blocks in the block memory */
1777  BMS_BLKMEM* blkmem, /**< block memory */
1778  const char* filename, /**< source file of the function call */
1779  int line /**< line number in source file of the function call */
1780  )
1781 {
1782  BMS_CHKMEM* chkmem;
1783  BMS_CHKMEM* nextchkmem;
1784  int i;
1785 
1786  if( blkmem != NULL )
1787  {
1788  for( i = 0; i < CHKHASH_SIZE; ++i )
1789  {
1790  chkmem = blkmem->chkmemhash[i];
1791  while( chkmem != NULL )
1792  {
1793  nextchkmem = chkmem->nextchkmem;
1794  destroyChkmem(&chkmem);
1795  chkmem = nextchkmem;
1796  }
1797  blkmem->chkmemhash[i] = NULL;
1798  }
1799  blkmem->memused = 0;
1800  }
1801  else
1802  {
1803  printErrorHeader(filename, line);
1804  printError("Tried to clear null block memory.\n");
1805  }
1806 }
1807 
1808 /** clears and deletes block memory */
1810  BMS_BLKMEM** blkmem, /**< pointer to block memory */
1811  const char* filename, /**< source file of the function call */
1812  int line /**< line number in source file of the function call */
1813  )
1814 {
1815  assert(blkmem != NULL);
1816 
1817  if( *blkmem != NULL )
1818  {
1819  BMSclearBlockMemory_call(*blkmem, filename, line);
1820  BMSfreeMemory(blkmem);
1821  assert(*blkmem == NULL);
1822  }
1823  else
1824  {
1825  printErrorHeader(filename, line);
1826  printError("Tried to destroy null block memory.\n");
1827  }
1828 }
1829 
1830 /** work for allocating memory in the block memory pool */
1831 INLINE static
1833  BMS_BLKMEM* blkmem, /**< block memory */
1834  size_t size, /**< size of memory element to allocate */
1835  const char* filename, /**< source file of the function call */
1836  int line /**< line number in source file of the function call */
1837  )
1838 {
1839  BMS_CHKMEM** chkmemptr;
1840  int hashnumber;
1841  void* ptr;
1842 
1843  assert( blkmem != NULL );
1844 
1845  /* calculate hash number of given size */
1846  alignSize(&size);
1847  hashnumber = getHashNumber((int)size);
1848 
1849  /* find correspoding chunk block */
1850  chkmemptr = &(blkmem->chkmemhash[hashnumber]);
1851  while( *chkmemptr != NULL && (*chkmemptr)->elemsize != (int)size )
1852  chkmemptr = &((*chkmemptr)->nextchkmem);
1853 
1854  /* create new chunk block if necessary */
1855  if( *chkmemptr == NULL )
1856  {
1857  *chkmemptr = createChkmem((int)size, blkmem->initchunksize, blkmem->garbagefactor);
1858  if( *chkmemptr == NULL )
1859  {
1860  printErrorHeader(filename, line);
1861  printError("Insufficient memory for chunk block.\n");
1862  return NULL;
1863  }
1864 #ifndef NDEBUG
1865  BMSduplicateMemoryArray(&(*chkmemptr)->filename, filename, strlen(filename) + 1);
1866  (*chkmemptr)->line = line;
1867 #endif
1868  }
1869 
1870  /* get memory inside the chunk block */
1871  ptr = allocChkmemElement(*chkmemptr);
1872  if( ptr == NULL )
1873  {
1874  printErrorHeader(filename, line);
1875  printError("Insufficient memory for new chunk.\n");
1876  }
1877  debugMessage("alloced %8llu bytes in %p [%s:%d]\n", (unsigned long long)size, ptr, filename, line);
1878 
1879  blkmem->memused += (long long) size;
1880 
1881  checkBlkmem(blkmem);
1882 
1883  return ptr;
1884 }
1885 
1886 /** allocates memory in the block memory pool */
1888  BMS_BLKMEM* blkmem, /**< block memory */
1889  size_t size, /**< size of memory element to allocate */
1890  const char* filename, /**< source file of the function call */
1891  int line /**< line number in source file of the function call */
1892  )
1893 {
1894 #ifndef NDEBUG
1895  if ( size > MAXMEMSIZE )
1896  {
1897  printErrorHeader(filename, line);
1898  printError("Tried to allocate block of size exceeding %u.\n", MAXMEMSIZE);
1899  return NULL;
1900  }
1901 #endif
1902 
1903  return BMSallocBlockMemory_work(blkmem, size, filename, line);
1904 }
1905 
1906 /** allocates array in the block memory pool */
1908  BMS_BLKMEM* blkmem, /**< block memory */
1909  size_t num, /**< size of array to be allocated */
1910  size_t typesize, /**< size of each component */
1911  const char* filename, /**< source file of the function call */
1912  int line /**< line number in source file of the function call */
1913  )
1914 {
1915 #ifndef NDEBUG
1916  if ( num > (MAXMEMSIZE / typesize) )
1917  {
1918  printErrorHeader(filename, line);
1919  printError("Tried to allocate block of size exceeding %u.\n", MAXMEMSIZE);
1920  return NULL;
1921  }
1922 #endif
1923 
1924  return BMSallocBlockMemory_work(blkmem, num * typesize, filename, line);
1925 }
1926 
1927 /** allocates array in the block memory pool and clears it */
1929  BMS_BLKMEM* blkmem, /**< block memory */
1930  size_t num, /**< size of array to be allocated */
1931  size_t typesize, /**< size of each component */
1932  const char* filename, /**< source file of the function call */
1933  int line /**< line number in source file of the function call */
1934  )
1935 {
1936  void* ptr;
1937 
1938  ptr = BMSallocBlockMemoryArray_call(blkmem, num, typesize, filename, line);
1939  if ( ptr != NULL )
1940  BMSclearMemorySize(ptr, num * typesize);
1941 
1942  return ptr;
1943 }
1944 
1945 /** resizes memory element in the block memory pool and copies the data */
1947  BMS_BLKMEM* blkmem, /**< block memory */
1948  void* ptr, /**< memory element to reallocated */
1949  size_t oldsize, /**< old size of memory element */
1950  size_t newsize, /**< new size of memory element */
1951  const char* filename, /**< source file of the function call */
1952  int line /**< line number in source file of the function call */
1953  )
1954 {
1955  void* newptr;
1956 
1957  if( ptr == NULL )
1958  {
1959  assert(oldsize == 0);
1960  return BMSallocBlockMemory_call(blkmem, newsize, filename, line);
1961  }
1962 
1963 #ifndef NDEBUG
1964  if ( newsize > MAXMEMSIZE )
1965  {
1966  printErrorHeader(filename, line);
1967  printError("Tried to allocate block of size exceeding %u.\n", MAXMEMSIZE);
1968  return NULL;
1969  }
1970 #endif
1971 
1972  alignSize(&oldsize);
1973  alignSize(&newsize);
1974  if( oldsize == newsize )
1975  return ptr;
1976 
1977  newptr = BMSallocBlockMemory_call(blkmem, newsize, filename, line);
1978  if( newptr != NULL )
1979  BMScopyMemorySize(newptr, ptr, MIN(oldsize, newsize));
1980  BMSfreeBlockMemory_call(blkmem, &ptr, oldsize, filename, line);
1981 
1982  return newptr;
1983 }
1984 
1985 /** resizes array in the block memory pool and copies the data */
1987  BMS_BLKMEM* blkmem, /**< block memory */
1988  void* ptr, /**< memory element to reallocated */
1989  size_t oldnum, /**< old size of array */
1990  size_t newnum, /**< new size of array */
1991  size_t typesize, /**< size of each component */
1992  const char* filename, /**< source file of the function call */
1993  int line /**< line number in source file of the function call */
1994  )
1995 {
1996  void* newptr;
1997 
1998  if( ptr == NULL )
1999  {
2000  assert(oldnum == 0);
2001  return BMSallocBlockMemoryArray_call(blkmem, newnum, typesize, filename, line);
2002  }
2003 
2004 #ifndef NDEBUG
2005  if ( newnum > (MAXMEMSIZE / typesize) )
2006  {
2007  printErrorHeader(filename, line);
2008  printError("Tried to allocate array of size exceeding %u.\n", MAXMEMSIZE);
2009  return NULL;
2010  }
2011 #endif
2012 
2013  if ( oldnum == newnum )
2014  return ptr;
2015 
2016  newptr = BMSallocBlockMemoryArray_call(blkmem, newnum, typesize, filename, line);
2017  if ( newptr != NULL )
2018  BMScopyMemorySize(newptr, ptr, MIN(oldnum, newnum) * typesize);
2019  BMSfreeBlockMemory_call(blkmem, &ptr, oldnum * typesize, filename, line);
2020 
2021  return newptr;
2022 }
2023 
2024 /** duplicates memory element in the block memory pool and copies the data */
2026  BMS_BLKMEM* blkmem, /**< block memory */
2027  const void* source, /**< memory element to duplicate */
2028  size_t size, /**< size of memory elements */
2029  const char* filename, /**< source file of the function call */
2030  int line /**< line number in source file of the function call */
2031  )
2032 {
2033  void* ptr;
2034 
2035  assert(source != NULL);
2036 
2037  ptr = BMSallocBlockMemory_call(blkmem, size, filename, line);
2038  if( ptr != NULL )
2039  BMScopyMemorySize(ptr, source, size);
2040 
2041  return ptr;
2042 }
2043 
2044 /** duplicates array in the block memory pool and copies the data */
2046  BMS_BLKMEM* blkmem, /**< block memory */
2047  const void* source, /**< memory element to duplicate */
2048  size_t num, /**< size of array to be duplicated */
2049  size_t typesize, /**< size of each component */
2050  const char* filename, /**< source file of the function call */
2051  int line /**< line number in source file of the function call */
2052  )
2053 {
2054  void* ptr;
2055 
2056  assert(source != NULL);
2057 
2058  ptr = BMSallocBlockMemoryArray_call(blkmem, num, typesize, filename, line);
2059  if( ptr != NULL )
2060  BMScopyMemorySize(ptr, source, num * typesize);
2061 
2062  return ptr;
2063 }
2064 
2065 /** common work for freeing block memory */
2066 INLINE static
2068  BMS_BLKMEM* blkmem, /**< block memory */
2069  void** ptr, /**< pointer to pointer to memory element to free */
2070  size_t size, /**< size of memory element */
2071  const char* filename, /**< source file of the function call */
2072  int line /**< line number in source file of the function call */
2073  )
2074 {
2075  BMS_CHKMEM* chkmem;
2076  int hashnumber;
2077 
2078  assert(ptr != NULL);
2079  assert(*ptr != NULL);
2080 
2081  /* calculate hash number of given size */
2082  alignSize(&size);
2083  hashnumber = getHashNumber((int)size);
2084 
2085  debugMessage("free %8llu bytes in %p [%s:%d]\n", (unsigned long long)size, *ptr, filename, line);
2086 
2087  /* find correspoding chunk block */
2088  assert( blkmem->chkmemhash != NULL );
2089  chkmem = blkmem->chkmemhash[hashnumber];
2090  while( chkmem != NULL && chkmem->elemsize != (int)size )
2091  chkmem = chkmem->nextchkmem;
2092  if( chkmem == NULL )
2093  {
2094  printErrorHeader(filename, line);
2095  printError("Tried to free pointer <%p> in block memory <%p> of unknown size %llu.\n", *ptr, (void*)blkmem, (unsigned long long)size);
2096  return;
2097  }
2098  assert(chkmem->elemsize == (int)size);
2099 
2100  /* free memory in chunk block */
2101  freeChkmemElement(chkmem, *ptr, filename, line);
2102 
2103  blkmem->memused -= (long long) size;
2104  assert(blkmem->memused >= 0);
2105 
2106  *ptr = NULL;
2107 }
2108 
2109 /** frees memory element in the block memory pool and sets pointer to NULL */
2111  BMS_BLKMEM* blkmem, /**< block memory */
2112  void** ptr, /**< pointer to pointer to memory element to free */
2113  size_t size, /**< size of memory element */
2114  const char* filename, /**< source file of the function call */
2115  int line /**< line number in source file of the function call */
2116  )
2117 {
2118  assert( blkmem != NULL );
2119  assert( ptr != NULL );
2120 
2121  if( *ptr != NULL )
2122  BMSfreeBlockMemory_work(blkmem, ptr, size, filename, line);
2123  else if( size != 0 )
2124  {
2125  printErrorHeader(filename, line);
2126  printError("Tried to free null block pointer.\n");
2127  }
2128  checkBlkmem(blkmem);
2129 }
2130 
2131 /** frees memory element in the block memory pool if pointer is not NULL and sets pointer to NULL */
2133  BMS_BLKMEM* blkmem, /**< block memory */
2134  void** ptr, /**< pointer to pointer to memory element to free */
2135  size_t size, /**< size of memory element */
2136  const char* filename, /**< source file of the function call */
2137  int line /**< line number in source file of the function call */
2138  )
2139 {
2140  assert( blkmem != NULL );
2141  assert( ptr != NULL );
2142 
2143  if( *ptr != NULL )
2144  {
2145  BMSfreeBlockMemory_work(blkmem, ptr, size, filename, line);
2146  checkBlkmem(blkmem);
2147  }
2148 }
2149 
2150 /** calls garbage collection of block memory, frees chunks without allocated memory elements, and frees
2151  * chunk blocks without any chunks
2152  */
2154  BMS_BLKMEM* blkmem /**< block memory */
2155  )
2156 {
2157  int i;
2158 
2159  assert(blkmem != NULL);
2160 
2161  for( i = 0; i < CHKHASH_SIZE; ++i )
2162  {
2163  BMS_CHKMEM** chkmemptr;
2164 
2165  chkmemptr = &blkmem->chkmemhash[i];
2166  while( *chkmemptr != NULL )
2167  {
2168  garbagecollectChkmem(*chkmemptr);
2169  if( (*chkmemptr)->nchunks == 0 )
2170  {
2171  BMS_CHKMEM* nextchkmem;
2172 
2173  nextchkmem = (*chkmemptr)->nextchkmem;
2174  destroyChkmem(chkmemptr);
2175  *chkmemptr = nextchkmem;
2176  }
2177  else
2178  chkmemptr = &(*chkmemptr)->nextchkmem;
2179  }
2180  }
2181 }
2182 
2183 /** returns the number of allocated bytes in the block memory */
2185  const BMS_BLKMEM* blkmem /**< block memory */
2186  )
2187 {
2188  assert( blkmem != NULL );
2189 
2190  return blkmem->memused;
2191 }
2192 
2193 /** returns the size of the given memory element; returns 0, if the element is not member of the block memory */
2195  const BMS_BLKMEM* blkmem, /**< block memory */
2196  const void* ptr /**< memory element */
2197  )
2198 {
2199  const BMS_CHKMEM* chkmem;
2200 
2201  assert(blkmem != NULL);
2202 
2203  if( ptr == NULL )
2204  return 0;
2205 
2206  chkmem = findChkmem(blkmem, ptr);
2207  if( chkmem == NULL )
2208  return 0;
2209 
2210  return (size_t)(chkmem->elemsize); /*lint !e571*/
2211 }
2212 
2213 /** outputs allocation diagnostics of block memory */
2215  const BMS_BLKMEM* blkmem /**< block memory */
2216  )
2217 {
2218  const BMS_CHKMEM* chkmem;
2219  int nblocks = 0;
2220  int nunusedblocks = 0;
2221  int totalnchunks = 0;
2222  int totalneagerchunks = 0;
2223  int totalnelems = 0;
2224  int totalneagerelems = 0;
2225  int totalnlazyelems = 0;
2226 #ifndef NDEBUG
2227  int totalngarbagecalls = 0;
2228  int totalngarbagefrees = 0;
2229 #endif
2230  long long allocedmem = 0;
2231  long long freemem = 0;
2232  int i;
2233  int c;
2234 
2235 #ifndef NDEBUG
2236  printInfo(" ElSize #Chunk #Eag #Elems #EagFr #LazFr #GCl #GFr Free MBytes First Allocator\n");
2237 #else
2238  printInfo(" ElSize #Chunk #Eag #Elems #EagFr #LazFr Free MBytes\n");
2239 #endif
2240 
2241  assert(blkmem != NULL);
2242 
2243  for( i = 0; i < CHKHASH_SIZE; ++i )
2244  {
2245  chkmem = blkmem->chkmemhash[i];
2246  while( chkmem != NULL )
2247  {
2248  const CHUNK* chunk;
2249  int nchunks = 0;
2250  int nelems = 0;
2251  int neagerchunks = 0;
2252  int neagerelems = 0;
2253 
2254  for( c = 0; c < chkmem->nchunks; ++c )
2255  {
2256  chunk = chkmem->chunks[c];
2257  assert(chunk != NULL);
2258  assert(chunk->elemsize == chkmem->elemsize);
2259  assert(chunk->chkmem == chkmem);
2260  nchunks++;
2261  nelems += chunk->storesize;
2262  if( chunk->eagerfree != NULL )
2263  {
2264  neagerchunks++;
2265  neagerelems += chunk->eagerfreesize;
2266  }
2267  }
2268 
2269  assert(nchunks == chkmem->nchunks);
2270  assert(nelems == chkmem->storesize);
2271  assert(neagerelems == chkmem->eagerfreesize);
2272 
2273  if( nelems > 0 )
2274  {
2275  nblocks++;
2276  allocedmem += (long long)chkmem->elemsize * (long long)nelems;
2277  freemem += (long long)chkmem->elemsize * ((long long)neagerelems + (long long)chkmem->lazyfreesize);
2278 
2279 #ifndef NDEBUG
2280  printInfo("%7d %6d %4d %7d %7d %7d %5d %4d %5.1f%% %6.1f %s:%d\n",
2281  chkmem->elemsize, nchunks, neagerchunks, nelems,
2282  neagerelems, chkmem->lazyfreesize, chkmem->ngarbagecalls, chkmem->ngarbagefrees,
2283  100.0 * (double) (neagerelems + chkmem->lazyfreesize) / (double) (nelems),
2284  (double)chkmem->elemsize * nelems / (1024.0*1024.0),
2285  chkmem->filename, chkmem->line);
2286 #else
2287  printInfo("%7d %6d %4d %7d %7d %7d %5.1f%% %6.1f\n",
2288  chkmem->elemsize, nchunks, neagerchunks, nelems,
2289  neagerelems, chkmem->lazyfreesize,
2290  100.0 * (double) (neagerelems + chkmem->lazyfreesize) / (double) (nelems),
2291  (double)chkmem->elemsize * nelems / (1024.0*1024.0));
2292 #endif
2293  }
2294  else
2295  {
2296 #ifndef NDEBUG
2297  printInfo("%7d <unused> %5d %4d %s:%d\n",
2298  chkmem->elemsize, chkmem->ngarbagecalls, chkmem->ngarbagefrees,
2299  chkmem->filename, chkmem->line);
2300 #else
2301  printInfo("%7d <unused>\n", chkmem->elemsize);
2302 #endif
2303  nunusedblocks++;
2304  }
2305  totalnchunks += nchunks;
2306  totalneagerchunks += neagerchunks;
2307  totalnelems += nelems;
2308  totalneagerelems += neagerelems;
2309  totalnlazyelems += chkmem->lazyfreesize;
2310 #ifndef NDEBUG
2311  totalngarbagecalls += chkmem->ngarbagecalls;
2312  totalngarbagefrees += chkmem->ngarbagefrees;
2313 #endif
2314  chkmem = chkmem->nextchkmem;
2315  }
2316  }
2317 #ifndef NDEBUG
2318  printInfo(" Total %6d %4d %7d %7d %7d %5d %4d %5.1f%% %6.1f\n",
2319  totalnchunks, totalneagerchunks, totalnelems, totalneagerelems, totalnlazyelems,
2320  totalngarbagecalls, totalngarbagefrees,
2321  totalnelems > 0 ? 100.0 * (double) (totalneagerelems + totalnlazyelems) / (double) (totalnelems) : 0.0,
2322  (double)allocedmem/(1024.0*1024.0));
2323 #else
2324  printInfo(" Total %6d %4d %7d %7d %7d %5.1f%% %6.1f\n",
2325  totalnchunks, totalneagerchunks, totalnelems, totalneagerelems, totalnlazyelems,
2326  totalnelems > 0 ? 100.0 * (double) (totalneagerelems + totalnlazyelems) / (double) (totalnelems) : 0.0,
2327  (double)allocedmem/(1024.0*1024.0));
2328 #endif
2329  printInfo("%d blocks (%d unused), %" LONGINT_FORMAT " bytes allocated, %" LONGINT_FORMAT " bytes free",
2330  nblocks + nunusedblocks, nunusedblocks, allocedmem, freemem);
2331  if( allocedmem > 0 )
2332  printInfo(" (%.1f%%)", 100.0 * (double) freemem / (double) allocedmem);
2333  printInfo("\n");
2334 }
2335 
2336 /** outputs warning messages, if there are allocated elements in the block memory */
2338  const BMS_BLKMEM* blkmem /**< block memory */
2339  )
2340 {
2341  const BMS_CHKMEM* chkmem;
2342  long long allocedmem = 0;
2343  long long freemem = 0;
2344  int i;
2345  int c;
2346 
2347  assert(blkmem != NULL);
2348 
2349  for( i = 0; i < CHKHASH_SIZE; ++i )
2350  {
2351  chkmem = blkmem->chkmemhash[i];
2352  while( chkmem != NULL )
2353  {
2354  const CHUNK* chunk;
2355  int nchunks = 0;
2356  int nelems = 0;
2357  int neagerelems = 0;
2358 
2359  for( c = 0; c < chkmem->nchunks; ++c )
2360  {
2361  chunk = chkmem->chunks[c];
2362  assert(chunk != NULL);
2363  assert(chunk->elemsize == chkmem->elemsize);
2364  assert(chunk->chkmem == chkmem);
2365  nchunks++;
2366  nelems += chunk->storesize;
2367  if( chunk->eagerfree != NULL )
2368  neagerelems += chunk->eagerfreesize;
2369  }
2370 
2371  assert(nchunks == chkmem->nchunks);
2372  assert(nelems == chkmem->storesize);
2373  assert(neagerelems == chkmem->eagerfreesize);
2374 
2375  if( nelems > 0 )
2376  {
2377  allocedmem += (long long)chkmem->elemsize * (long long)nelems;
2378  freemem += (long long)chkmem->elemsize * ((long long)neagerelems + (long long)chkmem->lazyfreesize);
2379 
2380  if( nelems != neagerelems + chkmem->lazyfreesize )
2381  {
2382 #ifndef NDEBUG
2383  printInfo("%" LONGINT_FORMAT " bytes (%d elements of size %" LONGINT_FORMAT ") not freed. First Allocator: %s:%d\n",
2384  (((long long)nelems - (long long)neagerelems) - (long long)chkmem->lazyfreesize)
2385  * (long long)(chkmem->elemsize),
2386  (nelems - neagerelems) - chkmem->lazyfreesize, (long long)(chkmem->elemsize),
2387  chkmem->filename, chkmem->line);
2388 #else
2389  printInfo("%" LONGINT_FORMAT " bytes (%d elements of size %" LONGINT_FORMAT ") not freed.\n",
2390  ((nelems - neagerelems) - chkmem->lazyfreesize) * (long long)(chkmem->elemsize),
2391  (nelems - neagerelems) - chkmem->lazyfreesize, (long long)(chkmem->elemsize));
2392 #endif
2393  }
2394  }
2395  chkmem = chkmem->nextchkmem;
2396  }
2397  }
2398 
2399  if( allocedmem != freemem )
2400  printInfo("%" LONGINT_FORMAT " bytes not freed in total.\n", allocedmem - freemem);
2401 }
2402 
2403 
2404 
2405 
2406 
2407 
2408 /***********************************************************
2409  * Buffer Memory Management
2410  *
2411  * Efficient memory management for temporary objects
2412  ***********************************************************/
2413 
2414 /** memory buffer storage for temporary objects */
2416 {
2417  void** data; /**< allocated memory chunks for arbitrary data */
2418  size_t* size; /**< sizes of buffers in bytes */
2419  unsigned int* used; /**< 1 iff corresponding buffer is in use */
2420  size_t totalmem; /**< total memory consumption of buffer */
2421  unsigned int clean; /**< 1 iff the memory blocks in the buffer should be initialized to zero? */
2422  size_t ndata; /**< number of memory chunks */
2423  size_t firstfree; /**< first unused memory chunk */
2424  double arraygrowfac; /**< memory growing factor for dynamically allocated arrays */
2425  unsigned int arraygrowinit; /**< initial size of dynamically allocated arrays */
2426 };
2427 
2428 
2429 /** creates memory buffer storage */
2431  double arraygrowfac, /**< memory growing factor for dynamically allocated arrays */
2432  int arraygrowinit, /**< initial size of dynamically allocated arrays */
2433  unsigned int clean, /**< should the memory blocks in the buffer be initialized to zero? */
2434  const char* filename, /**< source file of the function call */
2435  int line /**< line number in source file of the function call */
2436  )
2437 {
2438  BMS_BUFMEM* buffer;
2439 
2440  assert( arraygrowinit > 0 );
2441  assert( arraygrowfac > 0.0 );
2442 
2443  BMSallocMemory(&buffer);
2444  if ( buffer != NULL )
2445  {
2446  buffer->data = NULL;
2447  buffer->size = NULL;
2448  buffer->used = NULL;
2449  buffer->totalmem = 0UL;
2450  buffer->clean = clean;
2451  buffer->ndata = 0;
2452  buffer->firstfree = 0;
2453  buffer->arraygrowinit = (unsigned) arraygrowinit;
2454  buffer->arraygrowfac = arraygrowfac;
2455  }
2456  else
2457  {
2458  printErrorHeader(filename, line);
2459  printError("Insufficient memory for buffer memory header.\n");
2460  }
2461 
2462  return buffer;
2463 }
2464 
2465 /** destroys buffer memory */
2467  BMS_BUFMEM** buffer, /**< pointer to memory buffer storage */
2468  const char* filename, /**< source file of the function call */
2469  int line /**< line number in source file of the function call */
2470  )
2471 {
2472  size_t i;
2473 
2474  if ( *buffer != NULL )
2475  {
2476  i = (*buffer)->ndata;
2477  if ( i > 0 ) {
2478  for (--i ; ; i--)
2479  {
2480  assert( ! (*buffer)->used[i] );
2481  BMSfreeMemoryArrayNull(&(*buffer)->data[i]);
2482  if ( i == 0 )
2483  break;
2484  }
2485  }
2486  BMSfreeMemoryArrayNull(&(*buffer)->data);
2487  BMSfreeMemoryArrayNull(&(*buffer)->size);
2488  BMSfreeMemoryArrayNull(&(*buffer)->used);
2489  BMSfreeMemory(buffer);
2490  }
2491  else
2492  {
2493  printErrorHeader(filename, line);
2494  printError("Tried to free null buffer memory.\n");
2495  }
2496 }
2497 
2498 /** set arraygrowfac */
2500  BMS_BUFMEM* buffer, /**< pointer to memory buffer storage */
2501  double arraygrowfac /**< memory growing factor for dynamically allocated arrays */
2502  )
2503 {
2504  assert( buffer != NULL );
2505  assert( arraygrowfac > 0.0 );
2506 
2507  buffer->arraygrowfac = arraygrowfac;
2508 }
2509 
2510 /** set arraygrowinit */
2512  BMS_BUFMEM* buffer, /**< pointer to memory buffer storage */
2513  int arraygrowinit /**< initial size of dynamically allocated arrays */
2514  )
2515 {
2516  assert( buffer != NULL );
2517  assert( arraygrowinit > 0 );
2518 
2519  buffer->arraygrowinit = (unsigned) arraygrowinit;
2520 }
2521 
2522 #ifndef SCIP_NOBUFFERMEM
2523 /** calculate memory size for dynamically allocated arrays
2524  *
2525  * This function is a copy of the function in set.c in order to be able to use memory.? separately.
2526  */
2527 static
2529  size_t initsize, /**< initial size of array */
2530  SCIP_Real growfac, /**< growing factor of array */
2531  size_t num /**< minimum number of entries to store */
2532  )
2533 {
2534  size_t size;
2535 
2536  assert( growfac >= 1.0 );
2537 
2538  if ( growfac == 1.0 )
2539  size = MAX(initsize, num);
2540  else
2541  {
2542  size_t oldsize;
2543 
2544  /* calculate the size with this loop, such that the resulting numbers are always the same */
2545  initsize = MAX(initsize, 4);
2546  size = initsize;
2547  oldsize = size - 1;
2548 
2549  /* second condition checks against overflow */
2550  while ( size < num && size > oldsize )
2551  {
2552  oldsize = size;
2553  size = (size_t)(growfac * size + initsize);
2554  }
2555 
2556  /* if an overflow happened, set the correct value */
2557  if ( size <= oldsize )
2558  size = num;
2559  }
2560 
2561  assert( size >= initsize );
2562  assert( size >= num );
2563 
2564  return size;
2565 }
2566 #endif
2567 
2568 /** work for allocating the next unused buffer */
2569 INLINE static
2571  BMS_BUFMEM* buffer, /**< memory buffer storage */
2572  size_t size, /**< minimal required size of the buffer */
2573  const char* filename, /**< source file of the function call */
2574  int line /**< line number in source file of the function call */
2575  )
2576 {
2577  void* ptr;
2578 #ifndef SCIP_NOBUFFERMEM
2579  size_t bufnum;
2580 #endif
2581 
2582 #ifndef SCIP_NOBUFFERMEM
2583  assert( buffer != NULL );
2584  assert( buffer->firstfree <= buffer->ndata );
2585 
2586  /* allocate a minimum of 1 byte */
2587  if ( size == 0 )
2588  size = 1;
2589 
2590  /* check, if we need additional buffers */
2591  if ( buffer->firstfree == buffer->ndata )
2592  {
2593  size_t newsize;
2594  size_t i;
2595 
2596  /* create additional buffers */
2597  newsize = calcMemoryGrowSize((size_t)buffer->arraygrowinit, buffer->arraygrowfac, buffer->firstfree + 1);
2598  BMSreallocMemoryArray(&buffer->data, newsize);
2599  if ( buffer->data == NULL )
2600  {
2601  printErrorHeader(filename, line);
2602  printError("Insufficient memory for reallocating buffer data storage.\n");
2603  return NULL;
2604  }
2605  BMSreallocMemoryArray(&buffer->size, newsize);
2606  if ( buffer->size == NULL )
2607  {
2608  printErrorHeader(filename, line);
2609  printError("Insufficient memory for reallocating buffer size storage.\n");
2610  return NULL;
2611  }
2612  BMSreallocMemoryArray(&buffer->used, newsize);
2613  if ( buffer->used == NULL )
2614  {
2615  printErrorHeader(filename, line);
2616  printError("Insufficient memory for reallocating buffer used storage.\n");
2617  return NULL;
2618  }
2619 
2620  /* init data */
2621  for (i = buffer->ndata; i < newsize; ++i)
2622  {
2623  buffer->data[i] = NULL;
2624  buffer->size[i] = 0;
2625  buffer->used[i] = FALSE;
2626  }
2627  buffer->ndata = newsize;
2628  }
2629  assert(buffer->firstfree < buffer->ndata);
2630 
2631  /* check, if the current buffer is large enough */
2632  bufnum = buffer->firstfree;
2633  assert( ! buffer->used[bufnum] );
2634  if ( buffer->size[bufnum] < size )
2635  {
2636  size_t newsize;
2637 
2638  /* enlarge buffer */
2639  newsize = calcMemoryGrowSize((size_t)buffer->arraygrowinit, buffer->arraygrowfac, size);
2640  BMSreallocMemorySize(&buffer->data[bufnum], newsize);
2641 
2642  /* clear new memory */
2643  if( buffer->clean )
2644  {
2645  char* tmpptr = (char*)(buffer->data[bufnum]);
2646  size_t inc = buffer->size[bufnum] / sizeof(*tmpptr);
2647  tmpptr += inc;
2648 
2649  BMSclearMemorySize(tmpptr, newsize - buffer->size[bufnum]);
2650  }
2651  assert( newsize > buffer->size[bufnum] );
2652  buffer->totalmem += newsize - buffer->size[bufnum];
2653  buffer->size[bufnum] = newsize;
2654 
2655  if ( buffer->data[bufnum] == NULL )
2656  {
2657  printErrorHeader(filename, line);
2658  printError("Insufficient memory for reallocating buffer storage.\n");
2659  return NULL;
2660  }
2661  }
2662  assert( buffer->size[bufnum] >= size );
2663 
2664 #ifdef CHECKMEM
2665  /* check that the memory is cleared */
2666  if( buffer->clean )
2667  {
2668  char* tmpptr = (char*)(buffer->data[bufnum]);
2669  unsigned int inc = buffer->size[bufnum] / sizeof(*tmpptr);
2670  tmpptr += inc;
2671 
2672  while( --tmpptr >= (char*)(buffer->data[bufnum]) )
2673  assert(*tmpptr == '\0');
2674  }
2675 #endif
2676 
2677  ptr = buffer->data[bufnum];
2678  buffer->used[bufnum] = TRUE;
2679  buffer->firstfree++;
2680 
2681  debugMessage("Allocated buffer %llu/%llu at %p of size %llu (required size: %llu) for pointer %p.\n",
2682  (unsigned long long)bufnum, (unsigned long long)(buffer->ndata), buffer->data[bufnum],
2683  (unsigned long long)(buffer->size[bufnum]), (unsigned long long)size, ptr);
2684 
2685 #else
2686  if( buffer->clean )
2687  {
2688  BMSallocClearMemorySize(&ptr, size);
2689  }
2690  else
2691  {
2692  BMSallocMemorySize(&ptr, size);
2693  }
2694 #endif
2695 
2696  return ptr;
2697 }
2698 
2699 /** allocates the next unused buffer */
2701  BMS_BUFMEM* buffer, /**< memory buffer storage */
2702  size_t size, /**< minimal required size of the buffer */
2703  const char* filename, /**< source file of the function call */
2704  int line /**< line number in source file of the function call */
2705  )
2706 {
2707 #ifndef NDEBUG
2708  if ( size > MAXMEMSIZE )
2709  {
2710  printErrorHeader(filename, line);
2711  printError("Tried to allocate buffer of size exceeding %u.\n", MAXMEMSIZE);
2712  return NULL;
2713  }
2714 #endif
2715 
2716  return BMSallocBufferMemory_work(buffer, size, filename, line);
2717 }
2718 
2719 /** allocates the next unused buffer array */
2721  BMS_BUFMEM* buffer, /**< memory buffer storage */
2722  size_t num, /**< size of array to be allocated */
2723  size_t typesize, /**< size of components */
2724  const char* filename, /**< source file of the function call */
2725  int line /**< line number in source file of the function call */
2726  )
2727 {
2728 #ifndef NDEBUG
2729  if ( num > (MAXMEMSIZE / typesize) )
2730  {
2731  printErrorHeader(filename, line);
2732  printError("Tried to allocate buffer of size exceeding %u.\n", MAXMEMSIZE);
2733  return NULL;
2734  }
2735 #endif
2736 
2737  return BMSallocBufferMemory_work(buffer, num * typesize, filename, line);
2738 }
2739 
2740 /** allocates the next unused buffer and clears it */
2742  BMS_BUFMEM* buffer, /**< memory buffer storage */
2743  size_t num, /**< size of array to be allocated */
2744  size_t typesize, /**< size of components */
2745  const char* filename, /**< source file of the function call */
2746  int line /**< line number in source file of the function call */
2747  )
2748 {
2749  void* ptr;
2750 
2751  ptr = BMSallocBufferMemoryArray_call(buffer, num, typesize, filename, line);
2752  if ( ptr != NULL )
2753  BMSclearMemorySize(ptr, num * typesize);
2754 
2755  return ptr;
2756 }
2757 
2758 /** work for reallocating the buffer to at least the given size */
2759 INLINE static
2761  BMS_BUFMEM* buffer, /**< memory buffer storage */
2762  void* ptr, /**< pointer to the allocated memory buffer */
2763  size_t size, /**< minimal required size of the buffer */
2764  const char* filename, /**< source file of the function call */
2765  int line /**< line number in source file of the function call */
2766  )
2767 {
2768  void* newptr;
2769 #ifndef SCIP_NOBUFFERMEM
2770  size_t bufnum;
2771 #endif
2772 
2773 #ifndef SCIP_NOBUFFERMEM
2774  assert( buffer != NULL );
2775  assert( buffer->firstfree <= buffer->ndata );
2776  assert(!buffer->clean); /* reallocating clean buffer elements is not supported */
2777 
2778  /* if the pointer doesn't exist yet, allocate it */
2779  if ( ptr == NULL )
2780  return BMSallocBufferMemory_call(buffer, size, filename, line);
2781 
2782  assert( buffer->firstfree >= 1 );
2783 
2784  /* Search the pointer in the buffer list:
2785  * Usually, buffers are allocated and freed like a stack, such that the currently used pointer is
2786  * most likely at the end of the buffer list.
2787  */
2788  bufnum = buffer->firstfree - 1;
2789  while ( bufnum > 0 && buffer->data[bufnum] != ptr )
2790  --bufnum;
2791 
2792  newptr = ptr;
2793  assert( buffer->data[bufnum] == newptr );
2794  assert( buffer->used[bufnum] );
2795  assert( buffer->size[bufnum] >= 1 );
2796 
2797  /* check if the buffer has to be enlarged */
2798  if ( size > buffer->size[bufnum] )
2799  {
2800  size_t newsize;
2801 
2802  /* enlarge buffer */
2803  newsize = calcMemoryGrowSize((size_t)buffer->arraygrowinit, buffer->arraygrowfac, size);
2804  BMSreallocMemorySize(&buffer->data[bufnum], newsize);
2805  assert( newsize > buffer->size[bufnum] );
2806  buffer->totalmem += newsize - buffer->size[bufnum];
2807  buffer->size[bufnum] = newsize;
2808  if ( buffer->data[bufnum] == NULL )
2809  {
2810  printErrorHeader(filename, line);
2811  printError("Insufficient memory for reallocating buffer storage.\n");
2812  return NULL;
2813  }
2814  newptr = buffer->data[bufnum];
2815  }
2816  assert( buffer->size[bufnum] >= size );
2817  assert( newptr == buffer->data[bufnum] );
2818 
2819  debugMessage("Reallocated buffer %llu/%llu at %p to size %llu (required size: %llu) for pointer %p.\n",
2820  (unsigned long long)bufnum, (unsigned long long)(buffer->ndata), buffer->data[bufnum],
2821  (unsigned long long)(buffer->size[bufnum]), (unsigned long long)size, newptr);
2822 
2823 #else
2824  newptr = ptr;
2825  BMSreallocMemorySize(&newptr, size);
2826 #endif
2827 
2828  return newptr;
2829 }
2830 
2831 /** reallocates the buffer to at least the given size */
2833  BMS_BUFMEM* buffer, /**< memory buffer storage */
2834  void* ptr, /**< pointer to the allocated memory buffer */
2835  size_t size, /**< minimal required size of the buffer */
2836  const char* filename, /**< source file of the function call */
2837  int line /**< line number in source file of the function call */
2838  )
2839 {
2840 #ifndef NDEBUG
2841  if ( size > MAXMEMSIZE )
2842  {
2843  printErrorHeader(filename, line);
2844  printError("Tried to allocate buffer of size exceeding %u.\n", MAXMEMSIZE);
2845  return NULL;
2846  }
2847 #endif
2848 
2849  return BMSreallocBufferMemory_work(buffer, ptr, size, filename, line);
2850 }
2851 
2852 /** reallocates an array in the buffer to at least the given size */
2854  BMS_BUFMEM* buffer, /**< memory buffer storage */
2855  void* ptr, /**< pointer to the allocated memory buffer */
2856  size_t num, /**< size of array to be allocated */
2857  size_t typesize, /**< size of components */
2858  const char* filename, /**< source file of the function call */
2859  int line /**< line number in source file of the function call */
2860  )
2861 {
2862 #ifndef NDEBUG
2863  if ( num > (MAXMEMSIZE / typesize) )
2864  {
2865  printErrorHeader(filename, line);
2866  printError("Tried to allocate array of size exceeding %u.\n", MAXMEMSIZE);
2867  return NULL;
2868  }
2869 #endif
2870 
2871  return BMSreallocBufferMemory_work(buffer, ptr, num * typesize, filename, line);
2872 }
2873 
2874 /** allocates the next unused buffer and copies the given memory into the buffer */
2876  BMS_BUFMEM* buffer, /**< memory buffer storage */
2877  const void* source, /**< memory block to copy into the buffer */
2878  size_t size, /**< minimal required size of the buffer */
2879  const char* filename, /**< source file of the function call */
2880  int line /**< line number in source file of the function call */
2881  )
2882 {
2883  void* ptr;
2884 
2885  assert( source != NULL );
2886 
2887  /* allocate a buffer of the given size */
2888  ptr = BMSallocBufferMemory_call(buffer, size, filename, line);
2889 
2890  /* copy the source memory into the buffer */
2891  if ( ptr != NULL )
2892  BMScopyMemorySize(ptr, source, size);
2893 
2894  return ptr;
2895 }
2896 
2897 /** allocates an array in the next unused buffer and copies the given memory into the buffer */
2899  BMS_BUFMEM* buffer, /**< memory buffer storage */
2900  const void* source, /**< memory block to copy into the buffer */
2901  size_t num, /**< size of array to be allocated */
2902  size_t typesize, /**< size of components */
2903  const char* filename, /**< source file of the function call */
2904  int line /**< line number in source file of the function call */
2905  )
2906 {
2907  void* ptr;
2908 
2909  assert( source != NULL );
2910 
2911  /* allocate a buffer of the given size */
2912  ptr = BMSallocBufferMemoryArray_call(buffer, num, typesize, filename, line);
2913 
2914  /* copy the source memory into the buffer */
2915  if ( ptr != NULL )
2916  BMScopyMemorySize(ptr, source, num * typesize);
2917 
2918  return ptr;
2919 }
2920 
2921 /** work for freeing a buffer */
2922 INLINE static
2924  BMS_BUFMEM* buffer, /**< memory buffer storage */
2925  void** ptr, /**< pointer to pointer to the allocated memory buffer */
2926  const char* filename, /**< source file of the function call */
2927  int line /**< line number in source file of the function call */
2928  )
2929 { /*lint --e{715}*/
2930  size_t bufnum;
2931 
2932  assert( buffer != NULL );
2933  assert( buffer->firstfree <= buffer->ndata );
2934  assert( buffer->firstfree >= 1 );
2935  assert( ptr != NULL );
2936  assert( *ptr != NULL );
2937 
2938  /* Search the pointer in the buffer list:
2939  * Usually, buffers are allocated and freed like a stack, such that the freed pointer is
2940  * most likely at the end of the buffer list.
2941  */
2942  bufnum = buffer->firstfree-1;
2943  while ( bufnum > 0 && buffer->data[bufnum] != *ptr )
2944  --bufnum;
2945 
2946 #ifndef NDEBUG
2947  if ( bufnum == 0 && buffer->data[bufnum] != *ptr )
2948  {
2949  printErrorHeader(filename, line);
2950  printError("Tried to free unkown buffer pointer.\n");
2951  return;
2952  }
2953  if ( ! buffer->used[bufnum] )
2954  {
2955  printErrorHeader(filename, line);
2956  printError("Tried to free buffer pointer already freed.\n");
2957  return;
2958  }
2959 #endif
2960 
2961 #ifdef CHECKMEM
2962  /* check that the memory is cleared */
2963  if( buffer->clean )
2964  {
2965  char* tmpptr = (char*)(buffer->data[bufnum]);
2966  unsigned int inc = buffer->size[bufnum] / sizeof(*tmpptr);
2967  tmpptr += inc;
2968 
2969  while( --tmpptr >= (char*)(buffer->data[bufnum]) )
2970  assert(*tmpptr == '\0');
2971  }
2972 #endif
2973 
2974  assert( buffer->data[bufnum] == *ptr );
2975  buffer->used[bufnum] = FALSE;
2976 
2977  while ( buffer->firstfree > 0 && !buffer->used[buffer->firstfree-1] )
2978  --buffer->firstfree;
2979 
2980  debugMessage("Freed buffer %llu/%llu at %p of size %llu for pointer %p, first free is %llu.\n",
2981  (unsigned long long)bufnum, (unsigned long long)(buffer->ndata), buffer->data[bufnum],
2982  (unsigned long long)(buffer->size[bufnum]), *ptr, (unsigned long long)(buffer->firstfree));
2983 
2984  *ptr = NULL;
2985 }
2986 
2987 /** frees a buffer and sets pointer to NULL */
2989  BMS_BUFMEM* buffer, /**< memory buffer storage */
2990  void** ptr, /**< pointer to pointer to the allocated memory buffer */
2991  const char* filename, /**< source file of the function call */
2992  int line /**< line number in source file of the function call */
2993  )
2994 { /*lint --e{715}*/
2995  assert( ptr != NULL );
2996 
2997 #ifndef SCIP_NOBUFFERMEM
2998  if ( *ptr != NULL )
2999  BMSfreeBufferMemory_work(buffer, ptr, filename, line);
3000  else
3001  {
3002  printErrorHeader(filename, line);
3003  printError("Tried to free null buffer pointer.\n");
3004  }
3005 #else
3006  BMSfreeMemory(ptr);
3007 #endif
3008 }
3009 
3010 /** frees a buffer if pointer is not NULL and sets pointer to NULL */
3012  BMS_BUFMEM* buffer, /**< memory buffer storage */
3013  void** ptr, /**< pointer to pointer to the allocated memory buffer */
3014  const char* filename, /**< source file of the function call */
3015  int line /**< line number in source file of the function call */
3016  )
3017 { /*lint --e{715}*/
3018  assert( ptr != NULL );
3019 
3020  if ( *ptr != NULL )
3021  {
3022 #ifndef SCIP_NOBUFFERMEM
3023  BMSfreeBufferMemory_work(buffer, ptr, filename, line);
3024 #else
3025  BMSfreeMemory(ptr);
3026 #endif
3027  }
3028 }
3029 
3030 /** gets number of used buffers */
3032  BMS_BUFMEM* buffer /**< memory buffer storage */
3033  )
3034 {
3035  assert( buffer != NULL );
3036 
3037  return buffer->firstfree;
3038 }
3039 
3040 /** returns the number of allocated bytes in the buffer memory */
3042  const BMS_BUFMEM* buffer /**< buffer memory */
3043  )
3044 {
3045 #ifdef CHECKMEM
3046  size_t totalmem = 0UL;
3047  int i;
3048 
3049  assert( buffer != NULL );
3050  for (i = 0; i < buffer->ndata; ++i)
3051  totalmem += buffer->size[i];
3052  assert( totalmem == buffer->totalmem );
3053 #endif
3054 
3055  return (long long) buffer->totalmem;
3056 }
3057 
3058 /** outputs statistics about currently allocated buffers to the screen */
3060  BMS_BUFMEM* buffer /**< memory buffer storage */
3061  )
3062 {
3063  size_t totalmem;
3064  size_t i;
3065 
3066  assert( buffer != NULL );
3067 
3068  totalmem = 0UL;
3069  for (i = 0; i < buffer->ndata; ++i)
3070  {
3071  printf("[%c] %8llu bytes at %p\n", buffer->used[i] ? '*' : ' ', (unsigned long long)(buffer->size[i]), buffer->data[i]);
3072  totalmem += buffer->size[i];
3073  }
3074  printf(" %8llu bytes total in %llu buffers\n", (unsigned long long)totalmem, (unsigned long long)(buffer->ndata));
3075 }
void BMSdestroyBlockMemory_call(BMS_BLKMEM **blkmem, const char *filename, int line)
Definition: memory.c:1809
long long BMSgetMemoryUsed_call(void)
Definition: memory.c:301
#define printError
Definition: memory.c:54
#define ALIGNMENT
Definition: memory.c:650
void * BMSallocChunkMemory_call(BMS_CHKMEM *chkmem, size_t size, const char *filename, int line)
Definition: memory.c:1524
#define BMScopyMemorySize(ptr, source, size)
Definition: memory.h:90
struct BMS_ChkMem BMS_CHKMEM
Definition: memory.h:257
#define BMSallocClearMemorySize(ptr, size)
Definition: memory.h:77
int BMSisAligned(size_t size)
Definition: memory.c:724
static INLINE void BMSfreeBlockMemory_work(BMS_BLKMEM *blkmem, void **ptr, size_t size, const char *filename, int line)
Definition: memory.c:2067
void * BMSduplicateMemoryArray_call(const void *source, size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:573
void BMSdisplayBlockMemory_call(const BMS_BLKMEM *blkmem)
Definition: memory.c:2214
void * BMSallocBlockMemoryArray_call(BMS_BLKMEM *blkmem, size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:1907
static void garbagecollectChkmem(BMS_CHKMEM *chkmem)
Definition: memory.c:1357
#define checkChunk(chunk)
Definition: memory.c:895
double arraygrowfac
Definition: memory.c:2424
#define NULL
Definition: lpi_spx.cpp:130
void BMSfreeBufferMemoryNull_call(BMS_BUFMEM *buffer, void **ptr, const char *filename, int line)
Definition: memory.c:3011
void * BMSduplicateBufferMemoryArray_call(BMS_BUFMEM *buffer, const void *source, size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:2898
#define checkBlkmem(blkmem)
Definition: memory.c:1702
void * BMSallocBufferMemoryArray_call(BMS_BUFMEM *buffer, size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:2720
size_t * size
Definition: memory.c:2418
#define STORESIZE_MAX
Definition: memory.c:648
void * BMSduplicateChunkMemory_call(BMS_CHKMEM *chkmem, const void *source, size_t size, const char *filename, int line)
Definition: memory.c:1551
void * BMSallocClearBlockMemoryArray_call(BMS_BLKMEM *blkmem, size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:1928
void BMSdestroyChunkMemory_call(BMS_CHKMEM **chkmem, const char *filename, int line)
Definition: memory.c:1504
void * BMSallocBlockMemory_call(BMS_BLKMEM *blkmem, size_t size, const char *filename, int line)
Definition: memory.c:1887
struct Chunk CHUNK
Definition: memory.c:653
size_t BMSgetBlockPointerSize_call(const BMS_BLKMEM *blkmem, const void *ptr)
Definition: memory.c:2194
static void * allocChkmemElement(BMS_CHKMEM *chkmem)
Definition: memory.c:1318
#define BMSclearMemorySize(ptr, size)
Definition: memory.h:86
#define debugMessage
Definition: memory.c:51
void BMSfreeChunkMemory_call(BMS_CHKMEM *chkmem, void **ptr, size_t size, const char *filename, int line)
Definition: memory.c:1573
#define CHKHASH_SIZE
Definition: memory.c:1661
unsigned int * used
Definition: memory.c:2419
static void * allocChunkElement(CHUNK *chunk)
Definition: memory.c:1169
#define GARBAGE_SIZE
Definition: memory.c:649
#define warningMessage
Definition: memory.c:57
static void unlinkEagerChunk(CHUNK *chunk)
Definition: memory.c:1030
#define FALSE
Definition: memory.c:62
void * BMSreallocBlockMemoryArray_call(BMS_BLKMEM *blkmem, void *ptr, size_t oldnum, size_t newnum, size_t typesize, const char *filename, int line)
Definition: memory.c:1986
void * BMSreallocBlockMemory_call(BMS_BLKMEM *blkmem, void *ptr, size_t oldsize, size_t newsize, const char *filename, int line)
Definition: memory.c:1946
#define printErrorHeader(f, l)
Definition: memory.c:53
void ** data
Definition: memory.c:2417
size_t totalmem
Definition: memory.c:2420
static BMS_CHKMEM * findChkmem(const BMS_BLKMEM *blkmem, const void *ptr)
Definition: memory.c:1712
static int linkChunk(BMS_CHKMEM *chkmem, CHUNK *chunk)
Definition: memory.c:904
void * BMSallocClearBufferMemoryArray_call(BMS_BUFMEM *buffer, size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:2741
#define CHUNKLENGTH_MIN
Definition: memory.c:646
long long BMSgetBufferMemoryUsed(const BMS_BUFMEM *buffer)
Definition: memory.c:3041
void BMSsetBufferMemoryArraygrowinit(BMS_BUFMEM *buffer, int arraygrowinit)
Definition: memory.c:2511
struct Freelist FREELIST
Definition: memory.c:652
void * BMSreallocMemoryArray_call(void *ptr, size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:466
#define BMSallocMemorySize(ptr, size)
Definition: memory.h:75
static INLINE void * BMSallocBufferMemory_work(BMS_BUFMEM *buffer, size_t size, const char *filename, int line)
Definition: memory.c:2570
size_t firstfree
Definition: memory.c:2423
static INLINE void BMSfreeBufferMemory_work(BMS_BUFMEM *buffer, void **ptr, const char *filename, int line)
Definition: memory.c:2923
#define LONGINT_FORMAT
Definition: memory.c:74
#define BMSallocMemory(ptr)
Definition: memory.h:74
void * BMSallocBufferMemory_call(BMS_BUFMEM *buffer, size_t size, const char *filename, int line)
Definition: memory.c:2700
static void unlinkChunk(CHUNK *chunk)
Definition: memory.c:976
#define BMSreallocMemorySize(ptr, size)
Definition: memory.h:81
static INLINE void * BMSallocBlockMemory_work(BMS_BLKMEM *blkmem, size_t size, const char *filename, int line)
Definition: memory.c:1832
#define BMSreallocMemoryArray(ptr, num)
Definition: memory.h:82
#define BMSfreeMemory(ptr)
Definition: memory.h:100
void BMSgarbagecollectBlockMemory_call(BMS_BLKMEM *blkmem)
Definition: memory.c:2153
void * BMSduplicateMemory_call(const void *source, size_t size, const char *filename, int line)
Definition: memory.c:554
long long BMSgetBlockMemoryUsed_call(const BMS_BLKMEM *blkmem)
Definition: memory.c:2184
void * BMSallocMemoryArray_call(size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:386
void BMScheckEmptyBlockMemory_call(const BMS_BLKMEM *blkmem)
Definition: memory.c:2337
static int isPtrInChunk(const CHUNK *chunk, const void *ptr)
Definition: memory.c:735
void BMSdestroyBufferMemory_call(BMS_BUFMEM **buffer, const char *filename, int line)
Definition: memory.c:2466
static void alignSize(size_t *size)
Definition: memory.c:704
void * BMSduplicateBlockMemoryArray_call(BMS_BLKMEM *blkmem, const void *source, size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:2045
#define BMSduplicateMemoryArray(ptr, source, num)
Definition: memory.h:98
#define BMSfreeMemoryArrayNull(ptr)
Definition: memory.h:103
static int isPtrInChkmem(const BMS_CHKMEM *chkmem, const void *ptr)
Definition: memory.c:788
static void freeChkmemElement(BMS_CHKMEM *chkmem, void *ptr, const char *filename, int line)
Definition: memory.c:1424
void BMSgarbagecollectChunkMemory_call(BMS_CHKMEM *chkmem)
Definition: memory.c:1626
#define checkChkmem(chkmem)
Definition: memory.c:896
void BMSsetBufferMemoryArraygrowfac(BMS_BUFMEM *buffer, double arraygrowfac)
Definition: memory.c:2499
#define CHUNKLENGTH_MAX
Definition: memory.c:647
void BMSclearMemory_call(void *ptr, size_t size)
Definition: memory.c:509
long long BMSgetChunkMemoryUsed_call(const BMS_CHKMEM *chkmem)
Definition: memory.c:1636
static void freeChunkElement(CHUNK *chunk, void *ptr)
Definition: memory.c:1206
static void destroyChunk(CHUNK *chunk)
Definition: memory.c:1125
void BMSdisplayMemory_call(void)
Definition: memory.c:281
#define printInfo
Definition: memory.c:58
void BMSfreeMemory_call(void **ptr, const char *filename, int line)
Definition: memory.c:593
static int getHashNumber(int size)
Definition: memory.c:1735
void BMScopyMemory_call(void *ptr, const void *source, size_t size)
Definition: memory.c:522
unsigned int arraygrowinit
Definition: memory.c:2425
BMS_BUFMEM * BMScreateBufferMemory_call(double arraygrowfac, int arraygrowinit, unsigned int clean, const char *filename, int line)
Definition: memory.c:2430
void BMSfreeBufferMemory_call(BMS_BUFMEM *buffer, void **ptr, const char *filename, int line)
Definition: memory.c:2988
void BMSfreeBlockMemory_call(BMS_BLKMEM *blkmem, void **ptr, size_t size, const char *filename, int line)
Definition: memory.c:2110
BMS_BLKMEM * BMScreateBlockMemory_call(int initchunksize, int garbagefactor, const char *filename, int line)
Definition: memory.c:1746
static int createChunk(BMS_CHKMEM *chkmem)
Definition: memory.c:1055
static void linkEagerChunk(BMS_CHKMEM *chkmem, CHUNK *chunk)
Definition: memory.c:1009
void BMSmoveMemory_call(void *ptr, const void *source, size_t size)
Definition: memory.c:539
static void freeChunk(CHUNK *chunk)
Definition: memory.c:1139
#define errorMessage
Definition: memory.c:52
void * BMSreallocBufferMemoryArray_call(BMS_BUFMEM *buffer, void *ptr, size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:2853
void BMSprintBufferMemory(BMS_BUFMEM *buffer)
Definition: memory.c:3059
void * BMSduplicateBlockMemory_call(BMS_BLKMEM *blkmem, const void *source, size_t size, const char *filename, int line)
Definition: memory.c:2025
void * BMSallocClearMemory_call(size_t num, size_t typesize, const char *filename, int line)
Definition: memory.c:311
void BMScheckEmptyMemory_call(void)
Definition: memory.c:291
void BMSclearChunkMemory_call(BMS_CHKMEM *chkmem, const char *filename, int line)
Definition: memory.c:1486
static void clearChkmem(BMS_CHKMEM *chkmem)
Definition: memory.c:1276
size_t BMSgetNUsedBufferMemory(BMS_BUFMEM *buffer)
Definition: memory.c:3031
size_t BMSgetPointerSize_call(const void *ptr)
Definition: memory.c:273
void * BMSreallocMemory_call(void *ptr, size_t size, const char *filename, int line)
Definition: memory.c:426
void * BMSduplicateBufferMemory_call(BMS_BUFMEM *buffer, const void *source, size_t size, const char *filename, int line)
Definition: memory.c:2875
public methods for message output
#define TRUE
Definition: memory.c:63
void * BMSallocMemory_call(size_t size, const char *filename, int line)
Definition: memory.c:350
#define SCIP_Real
Definition: def.h:127
void BMSfreeBlockMemoryNull_call(BMS_BLKMEM *blkmem, void **ptr, size_t size, const char *filename, int line)
Definition: memory.c:2132
#define MIN(x, y)
Definition: memory.c:67
#define INLINE
Definition: memory.c:92
static CHUNK * findChunk(const BMS_CHKMEM *chkmem, const void *ptr)
Definition: memory.c:752
static INLINE void * BMSreallocBufferMemory_work(BMS_BUFMEM *buffer, void *ptr, size_t size, const char *filename, int line)
Definition: memory.c:2760
#define MAXMEMSIZE
Definition: memory.c:82
BMS_CHKMEM * BMScreateChunkMemory_call(size_t size, int initchunksize, int garbagefactor, const char *filename, int line)
Definition: memory.c:1462
void BMSfreeMemoryNull_call(void **ptr, const char *filename, int line)
Definition: memory.c:616
void BMSfreeChunkMemoryNull_call(BMS_CHKMEM *chkmem, void **ptr, size_t size, const char *filename, int line)
Definition: memory.c:1602
static size_t calcMemoryGrowSize(size_t initsize, SCIP_Real growfac, size_t num)
Definition: memory.c:2528
common defines and data types used in all packages of SCIP
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:392
static BMS_CHKMEM * createChkmem(int size, int initchunksize, int garbagefactor)
Definition: memory.c:1235
#define MAX(x, y)
Definition: memory.c:66
unsigned int clean
Definition: memory.c:2421
void * BMSreallocBufferMemory_call(BMS_BUFMEM *buffer, void *ptr, size_t size, const char *filename, int line)
Definition: memory.c:2832
void BMSclearBlockMemory_call(BMS_BLKMEM *blkmem, const char *filename, int line)
Definition: memory.c:1776
size_t ndata
Definition: memory.c:2422
void BMSalignMemsize(size_t *size)
Definition: memory.c:715
static void destroyChkmem(BMS_CHKMEM **chkmem)
Definition: memory.c:1299
memory allocation routines