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