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