Changes in / [4f102fa:a55472cc]
- Files:
-
- 10 edited
-
libcfa/src/bits/locks.hfa (modified) (2 diffs)
-
libcfa/src/concurrency/kernel/startup.cfa (modified) (3 diffs)
-
libcfa/src/heap.cfa (modified) (55 diffs)
-
libcfa/src/heap.hfa (modified) (3 diffs)
-
libcfa/src/startup.cfa (modified) (2 diffs)
-
libcfa/src/stdhdr/assert.h (modified) (2 diffs)
-
tests/.expect/alloc.txt (modified) (1 diff)
-
tests/alloc.cfa (modified) (3 diffs)
-
tests/alloc2.cfa (modified) (8 diffs)
-
tests/malloc.cfa (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/bits/locks.hfa
r4f102fa ra55472cc 13 13 // Created On : Tue Oct 31 15:14:38 2017 14 14 // Last Modified By : Peter A. Buhr 15 // Last Modified On : Tue Sep 20 22:09:50202216 // Update Count : 1 815 // Last Modified On : Mon Sep 19 18:51:53 2022 16 // Update Count : 17 17 17 // 18 18 … … 64 64 #ifndef NOEXPBACK 65 65 // exponential spin 66 for ( volatile unsigned int s; 0 ~ spin ) Pause();66 for ( volatile unsigned int s; 0 ~ spin ) Pause(); 67 67 68 68 // slowly increase by powers of 2 -
libcfa/src/concurrency/kernel/startup.cfa
r4f102fa ra55472cc 184 184 185 185 186 extern void heapManagerCtor();187 extern void heapManagerDtor();188 189 186 //============================================================================================= 190 187 // Kernel Setup logic … … 368 365 proc->local_data = &__cfaabi_tls; 369 366 370 heapManagerCtor(); // initialize heap371 372 367 __cfa_io_start( proc ); 373 368 register_tls( proc ); … … 421 416 unregister_tls( proc ); 422 417 __cfa_io_stop( proc ); 423 424 heapManagerDtor(); // de-initialize heap425 418 426 419 return 0p; -
libcfa/src/heap.cfa
r4f102fa ra55472cc 10 10 // Created On : Tue Dec 19 21:58:35 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Oct 11 15:08:33 202213 // Update Count : 1 52512 // Last Modified On : Fri Apr 29 19:05:03 2022 13 // Update Count : 1167 14 14 // 15 15 16 #include <stdio.h>17 16 #include <string.h> // memset, memcpy 18 17 #include <limits.h> // ULONG_MAX … … 22 21 #include <malloc.h> // memalign, malloc_usable_size 23 22 #include <sys/mman.h> // mmap, munmap 24 extern "C" {25 23 #include <sys/sysinfo.h> // get_nprocs 26 } // extern "C"27 24 28 25 #include "bits/align.hfa" // libAlign 29 26 #include "bits/defs.hfa" // likely, unlikely 30 27 #include "bits/locks.hfa" // __spinlock_t 31 #include "concurrency/kernel/fwd.hfa" // __POLL_PREEMPTION32 28 #include "startup.hfa" // STARTUP_PRIORITY_MEMORY 33 #include "math.hfa" // ceiling,min29 #include "math.hfa" // min 34 30 #include "bitmanip.hfa" // is_pow2, ceiling2 35 31 36 // supported mallopt options 37 #ifndef M_MMAP_THRESHOLD 38 #define M_MMAP_THRESHOLD (-1) 39 #endif // M_MMAP_THRESHOLD 40 41 #ifndef M_TOP_PAD 42 #define M_TOP_PAD (-2) 43 #endif // M_TOP_PAD 44 45 #define FASTLOOKUP // use O(1) table lookup from allocation size to bucket size 46 #define RETURNSPIN // toggle spinlock / lockfree stack 47 #define OWNERSHIP // return freed memory to owner thread 48 49 #define CACHE_ALIGN 64 50 #define CALIGN __attribute__(( aligned(CACHE_ALIGN) )) 51 52 #define TLSMODEL __attribute__(( tls_model("initial-exec") )) 53 54 //#define __STATISTICS__ 55 56 enum { 57 // The default extension heap amount in units of bytes. When the current heap reaches the brk address, the brk 58 // address is extended by the extension amount. 59 __CFA_DEFAULT_HEAP_EXPANSION__ = 10 * 1024 * 1024, 60 61 // The mmap crossover point during allocation. Allocations less than this amount are allocated from buckets; values 62 // greater than or equal to this value are mmap from the operating system. 63 __CFA_DEFAULT_MMAP_START__ = 512 * 1024 + 1, 64 65 // The default unfreed storage amount in units of bytes. When the uC++ program ends it subtracts this amount from 66 // the malloc/free counter to adjust for storage the program does not free. 67 __CFA_DEFAULT_HEAP_UNFREED__ = 0 68 }; // enum 69 70 71 //####################### Heap Trace/Print #################### 32 #define FASTLOOKUP 33 #define __STATISTICS__ 72 34 73 35 … … 93 55 static bool prtFree = false; 94 56 95 bool prtFree() {57 static bool prtFree() { 96 58 return prtFree; 97 59 } // prtFree 98 60 99 bool prtFreeOn() {61 static bool prtFreeOn() { 100 62 bool temp = prtFree; 101 63 prtFree = true; … … 103 65 } // prtFreeOn 104 66 105 bool prtFreeOff() {67 static bool prtFreeOff() { 106 68 bool temp = prtFree; 107 69 prtFree = false; … … 110 72 111 73 112 //######################### Spin Lock ######################### 113 114 115 // pause to prevent excess processor bus usage 116 #if defined( __i386 ) || defined( __x86_64 ) 117 #define Pause() __asm__ __volatile__ ( "pause" : : : ) 118 #elif defined(__ARM_ARCH) 119 #define Pause() __asm__ __volatile__ ( "YIELD" : : : ) 120 #else 121 #error unsupported architecture 122 #endif 123 124 typedef volatile uintptr_t SpinLock_t CALIGN; // aligned addressable word-size 125 126 static inline __attribute__((always_inline)) void lock( volatile SpinLock_t & slock ) { 127 enum { SPIN_START = 4, SPIN_END = 64 * 1024, }; 128 unsigned int spin = SPIN_START; 129 130 for ( unsigned int i = 1;; i += 1 ) { 131 if ( slock == 0 && __atomic_test_and_set( &slock, __ATOMIC_SEQ_CST ) == 0 ) break; // Fence 132 for ( volatile unsigned int s = 0; s < spin; s += 1 ) Pause(); // exponential spin 133 spin += spin; // powers of 2 134 //if ( i % 64 == 0 ) spin += spin; // slowly increase by powers of 2 135 if ( spin > SPIN_END ) spin = SPIN_END; // cap spinning 136 } // for 137 } // spin_lock 138 139 static inline __attribute__((always_inline)) void unlock( volatile SpinLock_t & slock ) { 140 __atomic_clear( &slock, __ATOMIC_SEQ_CST ); // Fence 141 } // spin_unlock 74 enum { 75 // The default extension heap amount in units of bytes. When the current heap reaches the brk address, the brk 76 // address is extended by the extension amount. 77 __CFA_DEFAULT_HEAP_EXPANSION__ = 10 * 1024 * 1024, 78 79 // The mmap crossover point during allocation. Allocations less than this amount are allocated from buckets; values 80 // greater than or equal to this value are mmap from the operating system. 81 __CFA_DEFAULT_MMAP_START__ = 512 * 1024 + 1, 82 83 // The default unfreed storage amount in units of bytes. When the uC++ program ends it subtracts this amount from 84 // the malloc/free counter to adjust for storage the program does not free. 85 __CFA_DEFAULT_HEAP_UNFREED__ = 0 86 }; // enum 142 87 143 88 … … 175 120 unsigned int free_calls, free_null_calls; 176 121 unsigned long long int free_storage_request, free_storage_alloc; 177 unsigned int return_pulls, return_pushes;178 unsigned long long int return_storage_request, return_storage_alloc;122 unsigned int away_pulls, away_pushes; 123 unsigned long long int away_storage_request, away_storage_alloc; 179 124 unsigned int mmap_calls, mmap_0_calls; // no zero calls 180 125 unsigned long long int mmap_storage_request, mmap_storage_alloc; … … 186 131 187 132 static_assert( sizeof(HeapStatistics) == CntTriples * sizeof(StatsOverlay), 188 "Heap statistics counter-triplets does not match with array size" );133 "Heap statistics counter-triplets does not match with array size" ); 189 134 190 135 static void HeapStatisticsCtor( HeapStatistics & stats ) { … … 258 203 static_assert( libAlign() >= sizeof( Storage ), "minimum alignment < sizeof( Storage )" ); 259 204 260 struct __attribute__(( aligned (8) ))FreeHeader {261 size_t blockSize __attribute__(( aligned (8) )); // size of allocations on this list205 struct FreeHeader { 206 size_t blockSize __attribute__(( aligned (8) )); // size of allocations on this list 262 207 #if BUCKETLOCK == SPINLOCK 263 #ifdef OWNERSHIP 264 #ifdef RETURNSPIN 265 SpinLock_t returnLock; 266 #endif // RETURNSPIN 267 Storage * returnList; // other thread return list 268 #endif // OWNERSHIP 269 Storage * freeList; // thread free list 208 __spinlock_t lock; 209 Storage * freeList; 270 210 #else 271 211 StackLF(Storage) freeList; 272 212 #endif // BUCKETLOCK 273 Heap * homeManager; // heap owner (free storage to bucket, from bucket to heap) 274 }; // FreeHeader 213 } __attribute__(( aligned (8) )); // FreeHeader 275 214 276 215 FreeHeader freeLists[NoBucketSizes]; // buckets for different allocation sizes 277 void * heapBuffer; // start of free storage in buffer 278 size_t heapReserve; // amount of remaining free storage in buffer 279 280 #if defined( __STATISTICS__ ) || defined( __CFA_DEBUG__ ) 281 Heap * nextHeapManager; // intrusive link of existing heaps; traversed to collect statistics or check unfreed storage 282 #endif // __STATISTICS__ || __CFA_DEBUG__ 283 Heap * nextFreeHeapManager; // intrusive link of free heaps from terminated threads; reused by new threads 284 285 #ifdef __CFA_DEBUG__ 286 int64_t allocUnfreed; // running total of allocations minus frees; can be negative 287 #endif // __CFA_DEBUG__ 288 289 #ifdef __STATISTICS__ 290 HeapStatistics stats; // local statistic table for this heap 291 #endif // __STATISTICS__ 216 217 __spinlock_t extlock; // protects allocation-buffer extension 218 void * heapBegin; // start of heap 219 void * heapEnd; // logical end of heap 220 size_t heapRemaining; // amount of storage not allocated in the current chunk 292 221 }; // Heap 293 222 294 223 #if BUCKETLOCK == LOCKFREE 295 inline __attribute__((always_inline)) 296 static { 224 static inline { 297 225 Link(Heap.Storage) * ?`next( Heap.Storage * this ) { return &this->header.kind.real.next; } 298 226 void ?{}( Heap.FreeHeader & ) {} … … 301 229 #endif // LOCKFREE 302 230 303 304 struct HeapMaster { 305 SpinLock_t extLock; // protects allocation-buffer extension 306 SpinLock_t mgrLock; // protects freeHeapManagersList, heapManagersList, heapManagersStorage, heapManagersStorageEnd 307 308 void * heapBegin; // start of heap 309 void * heapEnd; // logical end of heap 310 size_t heapRemaining; // amount of storage not allocated in the current chunk 311 size_t pageSize; // architecture pagesize 312 size_t heapExpand; // sbrk advance 313 size_t mmapStart; // cross over point for mmap 314 unsigned int maxBucketsUsed; // maximum number of buckets in use 315 316 Heap * heapManagersList; // heap-list head 317 Heap * freeHeapManagersList; // free-list head 318 319 // Heap superblocks are not linked; heaps in superblocks are linked via intrusive links. 320 Heap * heapManagersStorage; // next heap to use in heap superblock 321 Heap * heapManagersStorageEnd; // logical heap outside of superblock's end 322 323 #ifdef __STATISTICS__ 324 HeapStatistics stats; // global stats for thread-local heaps to add there counters when exiting 325 unsigned long int threads_started, threads_exited; // counts threads that have started and exited 326 unsigned long int reused_heap, new_heap; // counts reusability of heaps 327 unsigned int sbrk_calls; 328 unsigned long long int sbrk_storage; 329 int stats_fd; 330 #endif // __STATISTICS__ 331 }; // HeapMaster 231 static inline size_t getKey( const Heap.FreeHeader & freeheader ) { return freeheader.blockSize; } 332 232 333 233 334 234 #ifdef FASTLOOKUP 335 enum { LookupSizes = 65_536 + sizeof(Heap.Storage) }; // number of fast lookup sizes235 enum { LookupSizes = 65_536 + sizeof(Heap.Storage) }; // number of fast lookup sizes 336 236 static unsigned char lookup[LookupSizes]; // O(1) lookup for small sizes 337 237 #endif // FASTLOOKUP 338 238 339 static volatile bool heapMasterBootFlag = false; // trigger for first heap 340 static HeapMaster heapMaster @= {}; // program global 341 342 static void heapMasterCtor(); 343 static void heapMasterDtor(); 344 static Heap * getHeap(); 239 static const off_t mmapFd = -1; // fake or actual fd for anonymous file 240 #ifdef __CFA_DEBUG__ 241 static bool heapBoot = 0; // detect recursion during boot 242 #endif // __CFA_DEBUG__ 345 243 346 244 … … 370 268 static_assert( NoBucketSizes == sizeof(bucketSizes) / sizeof(bucketSizes[0] ), "size of bucket array wrong" ); 371 269 372 373 // extern visibility, used by runtime kernel 374 libcfa_public size_t __page_size; // architecture pagesize 375 libcfa_public int __map_prot; // common mmap/mprotect protection 376 377 378 // Thread-local storage is allocated lazily when the storage is accessed. 379 static __thread size_t PAD1 CALIGN TLSMODEL __attribute__(( unused )); // protect false sharing 380 static __thread Heap * volatile heapManager CALIGN TLSMODEL; 381 static __thread size_t PAD2 CALIGN TLSMODEL __attribute__(( unused )); // protect further false sharing 382 383 384 // declare helper functions for HeapMaster 385 void noMemory(); // forward, called by "builtin_new" when malloc returns 0 386 387 388 // generic Bsearchl does not inline, so substitute with hand-coded binary-search. 389 inline __attribute__((always_inline)) 390 static size_t Bsearchl( unsigned int key, const unsigned int vals[], size_t dim ) { 391 size_t l = 0, m, h = dim; 392 while ( l < h ) { 393 m = (l + h) / 2; 394 if ( (unsigned int &)(vals[m]) < key ) { // cast away const 395 l = m + 1; 396 } else { 397 h = m; 398 } // if 399 } // while 400 return l; 401 } // Bsearchl 402 403 404 void heapMasterCtor() with( heapMaster ) { 405 // Singleton pattern to initialize heap master 406 407 verify( bucketSizes[0] == (16 + sizeof(Heap.Storage)) ); 408 409 __page_size = sysconf( _SC_PAGESIZE ); 410 __map_prot = PROT_READ | PROT_WRITE | PROT_EXEC; 411 412 ?{}( extLock ); 413 ?{}( mgrLock ); 414 415 char * end = (char *)sbrk( 0 ); 416 heapBegin = heapEnd = sbrk( (char *)ceiling2( (long unsigned int)end, libAlign() ) - end ); // move start of heap to multiple of alignment 417 heapRemaining = 0; 418 heapExpand = malloc_expansion(); 419 mmapStart = malloc_mmap_start(); 420 421 // find the closest bucket size less than or equal to the mmapStart size 422 maxBucketsUsed = Bsearchl( mmapStart, bucketSizes, NoBucketSizes ); // binary search 423 424 verify( (mmapStart >= pageSize) && (bucketSizes[NoBucketSizes - 1] >= mmapStart) ); 425 verify( maxBucketsUsed < NoBucketSizes ); // subscript failure ? 426 verify( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ? 427 428 heapManagersList = 0p; 429 freeHeapManagersList = 0p; 430 431 heapManagersStorage = 0p; 432 heapManagersStorageEnd = 0p; 433 434 #ifdef __STATISTICS__ 435 HeapStatisticsCtor( stats ); // clear statistic counters 436 threads_started = threads_exited = 0; 437 reused_heap = new_heap = 0; 438 sbrk_calls = sbrk_storage = 0; 439 stats_fd = STDERR_FILENO; 440 #endif // __STATISTICS__ 441 442 #ifdef FASTLOOKUP 443 for ( unsigned int i = 0, idx = 0; i < LookupSizes; i += 1 ) { 444 if ( i > bucketSizes[idx] ) idx += 1; 445 lookup[i] = idx; 446 verify( i <= bucketSizes[idx] ); 447 verify( (i <= 32 && idx == 0) || (i > bucketSizes[idx - 1]) ); 448 } // for 449 #endif // FASTLOOKUP 450 451 heapMasterBootFlag = true; 452 } // heapMasterCtor 453 454 455 #define NO_MEMORY_MSG "insufficient heap memory available to allocate %zd new bytes." 456 457 Heap * getHeap() with( heapMaster ) { 458 Heap * heap; 459 if ( freeHeapManagersList ) { // free heap for reused ? 460 heap = freeHeapManagersList; 461 freeHeapManagersList = heap->nextFreeHeapManager; 462 463 #ifdef __STATISTICS__ 464 reused_heap += 1; 465 #endif // __STATISTICS__ 466 } else { // free heap not found, create new 467 // Heap size is about 12K, FreeHeader (128 bytes because of cache alignment) * NoBucketSizes (91) => 128 heaps * 468 // 12K ~= 120K byte superblock. Where 128-heap superblock handles a medium sized multi-processor server. 469 size_t remaining = heapManagersStorageEnd - heapManagersStorage; // remaining free heaps in superblock 470 if ( ! heapManagersStorage || remaining != 0 ) { 471 // Each block of heaps is a multiple of the number of cores on the computer. 472 int HeapDim = get_nprocs(); // get_nprocs_conf does not work 473 size_t size = HeapDim * sizeof( Heap ); 474 475 heapManagersStorage = (Heap *)mmap( 0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0 ); 476 if ( unlikely( heapManagersStorage == (Heap *)MAP_FAILED ) ) { // failed ? 477 if ( errno == ENOMEM ) abort( NO_MEMORY_MSG, size ); // no memory 478 // Do not call strerror( errno ) as it may call malloc. 479 abort( "attempt to allocate block of heaps of size %zu bytes and mmap failed with errno %d.", size, errno ); 480 } // if 481 heapManagersStorageEnd = &heapManagersStorage[HeapDim]; // outside array 482 } // if 483 484 heap = heapManagersStorage; 485 heapManagersStorage = heapManagersStorage + 1; // bump next heap 486 487 #if defined( __STATISTICS__ ) || defined( __CFA_DEBUG__ ) 488 heap->nextHeapManager = heapManagersList; 489 #endif // __STATISTICS__ || __CFA_DEBUG__ 490 heapManagersList = heap; 491 492 #ifdef __STATISTICS__ 493 new_heap += 1; 494 #endif // __STATISTICS__ 495 496 with( *heap ) { 497 for ( unsigned int j = 0; j < NoBucketSizes; j += 1 ) { // initialize free lists 498 #ifdef OWNERSHIP 499 #ifdef RETURNSPIN 500 ?{}( freeLists[j].returnLock ); 501 #endif // RETURNSPIN 502 freeLists[j].returnList = 0p; 503 #endif // OWNERSHIP 504 freeLists[j].freeList = 0p; 505 freeLists[j].homeManager = heap; 506 freeLists[j].blockSize = bucketSizes[j]; 507 } // for 508 509 heapBuffer = 0p; 510 heapReserve = 0; 511 nextFreeHeapManager = 0p; 512 #ifdef __CFA_DEBUG__ 513 allocUnfreed = 0; 514 #endif // __CFA_DEBUG__ 515 } // with 516 } // if 517 return heap; 518 } // getHeap 519 520 521 void heapManagerCtor() libcfa_public { 522 if ( unlikely( ! heapMasterBootFlag ) ) heapMasterCtor(); 523 524 lock( heapMaster.mgrLock ); // protect heapMaster counters 525 526 // get storage for heap manager 527 528 heapManager = getHeap(); 529 530 #ifdef __STATISTICS__ 531 HeapStatisticsCtor( heapManager->stats ); // heap local 532 heapMaster.threads_started += 1; 533 #endif // __STATISTICS__ 534 535 unlock( heapMaster.mgrLock ); 536 } // heapManagerCtor 537 538 539 void heapManagerDtor() libcfa_public { 540 lock( heapMaster.mgrLock ); 541 542 // place heap on list of free heaps for reusability 543 heapManager->nextFreeHeapManager = heapMaster.freeHeapManagersList; 544 heapMaster.freeHeapManagersList = heapManager; 545 546 #ifdef __STATISTICS__ 547 heapMaster.threads_exited += 1; 548 #endif // __STATISTICS__ 549 550 // Do not set heapManager to NULL because it is used after Cforall is shutdown but before the program shuts down. 551 552 unlock( heapMaster.mgrLock ); 553 } // heapManagerDtor 270 // The constructor for heapManager is called explicitly in memory_startup. 271 static Heap heapManager __attribute__(( aligned (128) )) @= {}; // size of cache line to prevent false sharing 554 272 555 273 556 274 //####################### Memory Allocation Routines Helpers #################### 557 275 276 277 #ifdef __CFA_DEBUG__ 278 static size_t allocUnfreed; // running total of allocations minus frees 279 280 static void prtUnfreed() { 281 if ( allocUnfreed != 0 ) { 282 // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT. 283 char helpText[512]; 284 __cfaabi_bits_print_buffer( STDERR_FILENO, helpText, sizeof(helpText), 285 "CFA warning (UNIX pid:%ld) : program terminating with %zu(0x%zx) bytes of storage allocated but not freed.\n" 286 "Possible cause is unfreed storage allocated by the program or system/library routines called from the program.\n", 287 (long int)getpid(), allocUnfreed, allocUnfreed ); // always print the UNIX pid 288 } // if 289 } // prtUnfreed 558 290 559 291 extern int cfa_main_returned; // from interpose.cfa 560 292 extern "C" { 561 void memory_startup( void ) {562 if ( ! heapMasterBootFlag ) heapManagerCtor(); // sanity check563 } // memory_startup564 565 void memory_shutdown( void ) {566 heapManagerDtor();567 } // memory_shutdown568 569 293 void heapAppStart() { // called by __cfaabi_appready_startup 570 verify( heapManager ); 571 #ifdef __CFA_DEBUG__ 572 heapManager->allocUnfreed = 0; // clear prior allocation counts 573 #endif // __CFA_DEBUG__ 574 575 #ifdef __STATISTICS__ 576 HeapStatisticsCtor( heapManager->stats ); // clear prior statistic counters 577 #endif // __STATISTICS__ 294 allocUnfreed = 0; 578 295 } // heapAppStart 579 296 580 297 void heapAppStop() { // called by __cfaabi_appready_startdown 581 fclose( stdin ); fclose( stdout ); // free buffer storage 582 if ( ! cfa_main_returned ) return; // do not check unfreed storage if exit called 583 584 #ifdef __CFA_DEBUG__ 585 // allocUnfreed is set to 0 when a heap is created and it accumulates any unfreed storage during its multiple thread 586 // usages. At the end, add up each heap allocUnfreed value across all heaps to get the total unfreed storage. 587 long long int allocUnfreed = 0; 588 for ( Heap * heap = heapMaster.heapManagersList; heap; heap = heap->nextHeapManager ) { 589 allocUnfreed += heap->allocUnfreed; 590 } // for 591 592 allocUnfreed -= malloc_unfreed(); // subtract any user specified unfreed storage 593 if ( allocUnfreed > 0 ) { 594 // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT. 595 char helpText[512]; 596 __cfaabi_bits_print_buffer( STDERR_FILENO, helpText, sizeof(helpText), 597 "CFA warning (UNIX pid:%ld) : program terminating with %llu(0x%llx) bytes of storage allocated but not freed.\n" 598 "Possible cause is unfreed storage allocated by the program or system/library routines called from the program.\n", 599 (long int)getpid(), allocUnfreed, allocUnfreed ); // always print the UNIX pid 600 } // if 601 #endif // __CFA_DEBUG__ 298 fclose( stdin ); fclose( stdout ); 299 if ( cfa_main_returned ) prtUnfreed(); // do not check unfreed storage if exit called 602 300 } // heapAppStop 603 301 } // extern "C" 302 #endif // __CFA_DEBUG__ 604 303 605 304 606 305 #ifdef __STATISTICS__ 607 306 static HeapStatistics stats; // zero filled 307 static unsigned int sbrk_calls; 308 static unsigned long long int sbrk_storage; 309 // Statistics file descriptor (changed by malloc_stats_fd). 310 static int stats_fd = STDERR_FILENO; // default stderr 608 311 609 312 #define prtFmt \ … … 618 321 " realloc >0 calls %'u; 0 calls %'u; storage %'llu / %'llu bytes\n" \ 619 322 " free !null calls %'u; null calls %'u; storage %'llu / %'llu bytes\n" \ 620 " return pulls %'u; pushes %'u; storage %'llu / %'llu bytes\n" \ 621 " sbrk calls %'u; storage %'llu bytes\n" \ 622 " mmap calls %'u; storage %'llu / %'llu bytes\n" \ 623 " munmap calls %'u; storage %'llu / %'llu bytes\n" \ 624 " threads started %'lu; exited %'lu\n" \ 625 " heaps new %'lu; reused %'lu\n" 323 " sbrk calls %'u; storage %'llu bytes\n" \ 324 " mmap calls %'u; storage %'llu / %'llu bytes\n" \ 325 " munmap calls %'u; storage %'llu / %'llu bytes\n" \ 626 326 627 327 // Use "write" because streams may be shutdown when calls are made. 628 static int printStats( HeapStatistics & stats ) with( heapMaster, stats ) {// see malloc_stats328 static int printStats() { // see malloc_stats 629 329 char helpText[sizeof(prtFmt) + 1024]; // space for message and values 630 return __cfaabi_bits_print_buffer( stats_fd, helpText, sizeof(helpText), prtFmt, 631 malloc_calls, malloc_0_calls, malloc_storage_request, malloc_storage_alloc, 632 aalloc_calls, aalloc_0_calls, aalloc_storage_request, aalloc_storage_alloc, 633 calloc_calls, calloc_0_calls, calloc_storage_request, calloc_storage_alloc, 634 memalign_calls, memalign_0_calls, memalign_storage_request, memalign_storage_alloc, 635 amemalign_calls, amemalign_0_calls, amemalign_storage_request, amemalign_storage_alloc, 636 cmemalign_calls, cmemalign_0_calls, cmemalign_storage_request, cmemalign_storage_alloc, 637 resize_calls, resize_0_calls, resize_storage_request, resize_storage_alloc, 638 realloc_calls, realloc_0_calls, realloc_storage_request, realloc_storage_alloc, 639 free_calls, free_null_calls, free_storage_request, free_storage_alloc, 640 return_pulls, return_pushes, return_storage_request, return_storage_alloc, 330 return __cfaabi_bits_print_buffer( STDERR_FILENO, helpText, sizeof(helpText), prtFmt, 331 stats.malloc_calls, stats.malloc_0_calls, stats.malloc_storage_request, stats.malloc_storage_alloc, 332 stats.aalloc_calls, stats.aalloc_0_calls, stats.aalloc_storage_request, stats.aalloc_storage_alloc, 333 stats.calloc_calls, stats.calloc_0_calls, stats.calloc_storage_request, stats.calloc_storage_alloc, 334 stats.memalign_calls, stats.memalign_0_calls, stats.memalign_storage_request, stats.memalign_storage_alloc, 335 stats.amemalign_calls, stats.amemalign_0_calls, stats.amemalign_storage_request, stats.amemalign_storage_alloc, 336 stats.cmemalign_calls, stats.cmemalign_0_calls, stats.cmemalign_storage_request, stats.cmemalign_storage_alloc, 337 stats.resize_calls, stats.resize_0_calls, stats.resize_storage_request, stats.resize_storage_alloc, 338 stats.realloc_calls, stats.realloc_0_calls, stats.realloc_storage_request, stats.realloc_storage_alloc, 339 stats.free_calls, stats.free_null_calls, stats.free_storage_request, stats.free_storage_alloc, 641 340 sbrk_calls, sbrk_storage, 642 mmap_calls, mmap_storage_request, mmap_storage_alloc, 643 munmap_calls, munmap_storage_request, munmap_storage_alloc, 644 threads_started, threads_exited, 645 new_heap, reused_heap 341 stats.mmap_calls, stats.mmap_storage_request, stats.mmap_storage_alloc, 342 stats.munmap_calls, stats.munmap_storage_request, stats.munmap_storage_alloc 646 343 ); 647 344 } // printStats … … 661 358 "<total type=\"realloc\" >0 count=\"%'u;\" 0 count=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \ 662 359 "<total type=\"free\" !null=\"%'u;\" 0 null=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \ 663 "<total type=\"return\" pulls=\"%'u;\" 0 pushes=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \664 360 "<total type=\"sbrk\" count=\"%'u;\" size=\"%'llu\"/> bytes\n" \ 665 361 "<total type=\"mmap\" count=\"%'u;\" size=\"%'llu / %'llu\" / > bytes\n" \ 666 362 "<total type=\"munmap\" count=\"%'u;\" size=\"%'llu / %'llu\"/> bytes\n" \ 667 "<total type=\"threads\" started=\"%'lu;\" exited=\"%'lu\"/>\n" \668 "<total type=\"heaps\" new=\"%'lu;\" reused=\"%'lu\"/>\n" \669 363 "</malloc>" 670 364 671 static int printStatsXML( HeapStatistics & stats, FILE * stream ) with( heapMaster, stats ) {// see malloc_info365 static int printStatsXML( FILE * stream ) { // see malloc_info 672 366 char helpText[sizeof(prtFmtXML) + 1024]; // space for message and values 673 367 return __cfaabi_bits_print_buffer( fileno( stream ), helpText, sizeof(helpText), prtFmtXML, 674 malloc_calls, malloc_0_calls, malloc_storage_request, malloc_storage_alloc, 675 aalloc_calls, aalloc_0_calls, aalloc_storage_request, aalloc_storage_alloc, 676 calloc_calls, calloc_0_calls, calloc_storage_request, calloc_storage_alloc, 677 memalign_calls, memalign_0_calls, memalign_storage_request, memalign_storage_alloc, 678 amemalign_calls, amemalign_0_calls, amemalign_storage_request, amemalign_storage_alloc, 679 cmemalign_calls, cmemalign_0_calls, cmemalign_storage_request, cmemalign_storage_alloc, 680 resize_calls, resize_0_calls, resize_storage_request, resize_storage_alloc, 681 realloc_calls, realloc_0_calls, realloc_storage_request, realloc_storage_alloc, 682 free_calls, free_null_calls, free_storage_request, free_storage_alloc, 683 return_pulls, return_pushes, return_storage_request, return_storage_alloc, 368 stats.malloc_calls, stats.malloc_0_calls, stats.malloc_storage_request, stats.malloc_storage_alloc, 369 stats.aalloc_calls, stats.aalloc_0_calls, stats.aalloc_storage_request, stats.aalloc_storage_alloc, 370 stats.calloc_calls, stats.calloc_0_calls, stats.calloc_storage_request, stats.calloc_storage_alloc, 371 stats.memalign_calls, stats.memalign_0_calls, stats.memalign_storage_request, stats.memalign_storage_alloc, 372 stats.amemalign_calls, stats.amemalign_0_calls, stats.amemalign_storage_request, stats.amemalign_storage_alloc, 373 stats.cmemalign_calls, stats.cmemalign_0_calls, stats.cmemalign_storage_request, stats.cmemalign_storage_alloc, 374 stats.resize_calls, stats.resize_0_calls, stats.resize_storage_request, stats.resize_storage_alloc, 375 stats.realloc_calls, stats.realloc_0_calls, stats.realloc_storage_request, stats.realloc_storage_alloc, 376 stats.free_calls, stats.free_null_calls, stats.free_storage_request, stats.free_storage_alloc, 684 377 sbrk_calls, sbrk_storage, 685 mmap_calls, mmap_storage_request, mmap_storage_alloc, 686 munmap_calls, munmap_storage_request, munmap_storage_alloc, 687 threads_started, threads_exited, 688 new_heap, reused_heap 378 stats.mmap_calls, stats.mmap_storage_request, stats.mmap_storage_alloc, 379 stats.munmap_calls, stats.munmap_storage_request, stats.munmap_storage_alloc 689 380 ); 690 381 } // printStatsXML 691 692 static HeapStatistics & collectStats( HeapStatistics & stats ) with( heapMaster ) {693 lock( mgrLock );694 695 stats += heapMaster.stats;696 for ( Heap * heap = heapManagersList; heap; heap = heap->nextHeapManager ) {697 stats += heap->stats;698 } // for699 700 unlock( mgrLock );701 return stats;702 } // collectStats703 382 #endif // __STATISTICS__ 704 383 705 384 706 static bool setMmapStart( size_t value ) with( heapMaster ) { // true => mmapped, false => sbrk 385 // statically allocated variables => zero filled. 386 static size_t heapExpand; // sbrk advance 387 static size_t mmapStart; // cross over point for mmap 388 static unsigned int maxBucketsUsed; // maximum number of buckets in use 389 // extern visibility, used by runtime kernel 390 // would be cool to remove libcfa_public but it's needed for libcfathread 391 libcfa_public size_t __page_size; // architecture pagesize 392 libcfa_public int __map_prot; // common mmap/mprotect protection 393 394 395 // thunk problem 396 size_t Bsearchl( unsigned int key, const unsigned int * vals, size_t dim ) { 397 size_t l = 0, m, h = dim; 398 while ( l < h ) { 399 m = (l + h) / 2; 400 if ( (unsigned int &)(vals[m]) < key ) { // cast away const 401 l = m + 1; 402 } else { 403 h = m; 404 } // if 405 } // while 406 return l; 407 } // Bsearchl 408 409 410 static inline bool setMmapStart( size_t value ) { // true => mmapped, false => sbrk 707 411 if ( value < __page_size || bucketSizes[NoBucketSizes - 1] < value ) return false; 708 412 mmapStart = value; // set global 709 413 710 414 // find the closest bucket size less than or equal to the mmapStart size 711 maxBucketsUsed = Bsearchl( mmapStart, bucketSizes, NoBucketSizes ); // binary search712 verify( maxBucketsUsed < NoBucketSizes ); // subscript failure ?713 verify( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ?415 maxBucketsUsed = Bsearchl( (unsigned int)mmapStart, bucketSizes, NoBucketSizes ); // binary search 416 assert( maxBucketsUsed < NoBucketSizes ); // subscript failure ? 417 assert( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ? 714 418 return true; 715 419 } // setMmapStart … … 734 438 735 439 736 inline __attribute__((always_inline)) 737 static void checkAlign( size_t alignment ) { 440 static inline void checkAlign( size_t alignment ) { 738 441 if ( unlikely( alignment < libAlign() || ! is_pow2( alignment ) ) ) { 739 442 abort( "**** Error **** alignment %zu for memory allocation is less than %d and/or not a power of 2.", alignment, libAlign() ); … … 742 445 743 446 744 inline __attribute__((always_inline)) 745 static void checkHeader( bool check, const char name[], void * addr ) { 447 static inline void checkHeader( bool check, const char name[], void * addr ) { 746 448 if ( unlikely( check ) ) { // bad address ? 747 449 abort( "**** Error **** attempt to %s storage %p with address outside the heap.\n" … … 768 470 769 471 770 inline __attribute__((always_inline)) 771 static void fakeHeader( Heap.Storage.Header *& header, size_t & alignment ) { 472 static inline void fakeHeader( Heap.Storage.Header *& header, size_t & alignment ) { 772 473 if ( unlikely( AlignmentBit( header ) ) ) { // fake header ? 773 474 alignment = ClearAlignmentBit( header ); // clear flag from value … … 782 483 783 484 784 inline __attribute__((always_inline)) 785 static bool headers( const char name[] __attribute__(( unused )), void * addr, Heap.Storage.Header *& header, 786 Heap.FreeHeader *& freeHead, size_t & size, size_t & alignment ) with( heapMaster, *heapManager ) { 485 static inline bool headers( const char name[] __attribute__(( unused )), void * addr, Heap.Storage.Header *& header, 486 Heap.FreeHeader *& freeHead, size_t & size, size_t & alignment ) with( heapManager ) { 787 487 header = HeaderAddr( addr ); 788 488 … … 809 509 checkHeader( header < (Heap.Storage.Header *)heapBegin || (Heap.Storage.Header *)heapEnd < header, name, addr ); // bad address ? (offset could be + or -) 810 510 811 Heap * homeManager;812 511 if ( unlikely( freeHead == 0p || // freed and only free-list node => null link 813 512 // freed and link points at another free block not to a bucket in the bucket array. 814 (homeManager = freeHead->homeManager, freeHead < &homeManager->freeLists[0] || 815 &homeManager->freeLists[NoBucketSizes] <= freeHead ) ) ) { 513 freeHead < &freeLists[0] || &freeLists[NoBucketSizes] <= freeHead ) ) { 816 514 abort( "**** Error **** attempt to %s storage %p with corrupted header.\n" 817 515 "Possible cause is duplicate free on same block or overwriting of header information.", … … 823 521 } // headers 824 522 825 826 static void * master_extend( size_t size ) with( heapMaster ) { 827 lock( extLock ); 523 // #ifdef __CFA_DEBUG__ 524 // #if __SIZEOF_POINTER__ == 4 525 // #define MASK 0xdeadbeef 526 // #else 527 // #define MASK 0xdeadbeefdeadbeef 528 // #endif 529 // #define STRIDE size_t 530 531 // static void * Memset( void * addr, STRIDE size ) { // debug only 532 // if ( size % sizeof(STRIDE) != 0 ) abort( "Memset() : internal error, size %zd not multiple of %zd.", size, sizeof(STRIDE) ); 533 // if ( (STRIDE)addr % sizeof(STRIDE) != 0 ) abort( "Memset() : internal error, addr %p not multiple of %zd.", addr, sizeof(STRIDE) ); 534 535 // STRIDE * end = (STRIDE *)addr + size / sizeof(STRIDE); 536 // for ( STRIDE * p = (STRIDE *)addr; p < end; p += 1 ) *p = MASK; 537 // return addr; 538 // } // Memset 539 // #endif // __CFA_DEBUG__ 540 541 542 #define NO_MEMORY_MSG "insufficient heap memory available for allocating %zd new bytes." 543 544 static inline void * extend( size_t size ) with( heapManager ) { 545 lock( extlock __cfaabi_dbg_ctx2 ); 828 546 829 547 ptrdiff_t rem = heapRemaining - size; … … 831 549 // If the size requested is bigger than the current remaining storage, increase the size of the heap. 832 550 833 size_t increase = ceiling2( size > heapExpand ? size : heapExpand, libAlign());551 size_t increase = ceiling2( size > heapExpand ? size : heapExpand, __page_size ); 834 552 // Do not call abort or strerror( errno ) as they may call malloc. 835 if ( unlikely( sbrk( increase ) == (void *)-1 ) ) {// failed, no memory ?836 unlock( ext Lock );553 if ( sbrk( increase ) == (void *)-1 ) { // failed, no memory ? 554 unlock( extlock ); 837 555 __cfaabi_bits_print_nolock( STDERR_FILENO, NO_MEMORY_MSG, size ); 838 556 _exit( EXIT_FAILURE ); // give up 839 557 } // if 840 rem = heapRemaining + increase - size; 558 559 // Make storage executable for thunks. 560 if ( mprotect( (char *)heapEnd + heapRemaining, increase, __map_prot ) ) { 561 unlock( extlock ); 562 __cfaabi_bits_print_nolock( STDERR_FILENO, "extend() : internal error, mprotect failure, heapEnd:%p size:%zd, errno:%d.\n", heapEnd, increase, errno ); 563 _exit( EXIT_FAILURE ); 564 } // if 841 565 842 566 #ifdef __STATISTICS__ … … 844 568 sbrk_storage += increase; 845 569 #endif // __STATISTICS__ 570 571 #ifdef __CFA_DEBUG__ 572 // Set new memory to garbage so subsequent uninitialized usages might fail. 573 memset( (char *)heapEnd + heapRemaining, '\xde', increase ); 574 //Memset( (char *)heapEnd + heapRemaining, increase ); 575 #endif // __CFA_DEBUG__ 576 577 rem = heapRemaining + increase - size; 846 578 } // if 847 579 … … 849 581 heapRemaining = rem; 850 582 heapEnd = (char *)heapEnd + size; 851 852 unlock( extLock ); 583 unlock( extlock ); 853 584 return block; 854 } // master_extend 855 856 857 __attribute__(( noinline )) 858 static void * manager_extend( size_t size ) with( *heapManager ) { 859 ptrdiff_t rem = heapReserve - size; 860 861 if ( unlikely( rem < 0 ) ) { // negative 862 // If the size requested is bigger than the current remaining reserve, use the current reserve to populate 863 // smaller freeLists, and increase the reserve. 864 865 rem = heapReserve; // positive 866 867 if ( rem >= bucketSizes[0] ) { // minimal size ? otherwise ignore 868 size_t bucket; 869 #ifdef FASTLOOKUP 870 if ( likely( rem < LookupSizes ) ) bucket = lookup[rem]; 871 #endif // FASTLOOKUP 872 bucket = Bsearchl( rem, bucketSizes, heapMaster.maxBucketsUsed ); 873 verify( 0 <= bucket && bucket <= heapMaster.maxBucketsUsed ); 874 Heap.FreeHeader * freeHead = &(freeLists[bucket]); 875 876 // The remaining storage many not be bucket size, whereas all other allocations are. Round down to previous 877 // bucket size in this case. 878 if ( unlikely( freeHead->blockSize > (size_t)rem ) ) freeHead -= 1; 879 Heap.Storage * block = (Heap.Storage *)heapBuffer; 880 881 block->header.kind.real.next = freeHead->freeList; // push on stack 882 freeHead->freeList = block; 883 } // if 884 885 size_t increase = ceiling( size > ( heapMaster.heapExpand / 10 ) ? size : ( heapMaster.heapExpand / 10 ), libAlign() ); 886 heapBuffer = master_extend( increase ); 887 rem = increase - size; 888 } // if 889 890 Heap.Storage * block = (Heap.Storage *)heapBuffer; 891 heapReserve = rem; 892 heapBuffer = (char *)heapBuffer + size; 893 894 return block; 895 } // manager_extend 896 897 898 #define BOOT_HEAP_MANAGER \ 899 if ( unlikely( ! heapMasterBootFlag ) ) { \ 900 heapManagerCtor(); /* trigger for first heap */ \ 901 } /* if */ 902 903 #ifdef __STATISTICS__ 904 #define STAT_NAME __counter 905 #define STAT_PARM , unsigned int STAT_NAME 906 #define STAT_ARG( name ) , name 907 #define STAT_0_CNT( counter ) stats.counters[counter].calls_0 += 1 908 #else 909 #define STAT_NAME 910 #define STAT_PARM 911 #define STAT_ARG( name ) 912 #define STAT_0_CNT( counter ) 913 #endif // __STATISTICS__ 914 915 #define PROLOG( counter, ... ) \ 916 BOOT_HEAP_MANAGER; \ 917 if ( unlikely( size == 0 ) || /* 0 BYTE ALLOCATION RETURNS NULL POINTER */ \ 918 unlikely( size > ULONG_MAX - sizeof(Heap.Storage) ) ) { /* error check */ \ 919 STAT_0_CNT( counter ); \ 920 __VA_ARGS__; \ 921 return 0p; \ 922 } /* if */ 923 924 925 #define SCRUB_SIZE 1024lu 926 // Do not use '\xfe' for scrubbing because dereferencing an address composed of it causes a SIGSEGV *without* a valid IP 927 // pointer in the interrupt frame. 928 #define SCRUB '\xff' 929 930 static void * doMalloc( size_t size STAT_PARM ) libcfa_nopreempt with( *heapManager ) { 931 PROLOG( STAT_NAME ); 932 933 verify( heapManager ); 934 Heap.Storage * block; // pointer to new block of storage 585 } // extend 586 587 588 static inline void * doMalloc( size_t size ) with( heapManager ) { 589 Heap.Storage * block; // pointer to new block of storage 935 590 936 591 // Look up size in the size list. Make sure the user request includes space for the header that must be allocated 937 592 // along with the block and is a multiple of the alignment size. 593 938 594 size_t tsize = size + sizeof(Heap.Storage); 939 595 940 #ifdef __STATISTICS__ 941 stats.counters[STAT_NAME].calls += 1; 942 stats.counters[STAT_NAME].request += size; 943 #endif // __STATISTICS__ 944 945 #ifdef __CFA_DEBUG__ 946 allocUnfreed += size; 947 #endif // __CFA_DEBUG__ 948 949 if ( likely( tsize < heapMaster.mmapStart ) ) { // small size => sbrk 950 size_t bucket; 596 if ( likely( tsize < mmapStart ) ) { // small size => sbrk 597 size_t posn; 951 598 #ifdef FASTLOOKUP 952 if ( likely( tsize < LookupSizes ) ) bucket= lookup[tsize];599 if ( tsize < LookupSizes ) posn = lookup[tsize]; 953 600 else 954 601 #endif // FASTLOOKUP 955 bucket = Bsearchl( tsize, bucketSizes, heapMaster.maxBucketsUsed ); 956 verify( 0 <= bucket && bucket <= heapMaster.maxBucketsUsed ); 957 Heap.FreeHeader * freeHead = &freeLists[bucket]; 958 959 verify( freeHead <= &freeLists[heapMaster.maxBucketsUsed] ); // subscripting error ? 960 verify( tsize <= freeHead->blockSize ); // search failure ? 961 962 tsize = freeHead->blockSize; // total space needed for request 963 #ifdef __STATISTICS__ 964 stats.counters[STAT_NAME].alloc += tsize; 965 #endif // __STATISTICS__ 602 posn = Bsearchl( (unsigned int)tsize, bucketSizes, (size_t)maxBucketsUsed ); 603 Heap.FreeHeader * freeElem = &freeLists[posn]; 604 verify( freeElem <= &freeLists[maxBucketsUsed] ); // subscripting error ? 605 verify( tsize <= freeElem->blockSize ); // search failure ? 606 tsize = freeElem->blockSize; // total space needed for request 966 607 967 608 // Spin until the lock is acquired for this particular size of block. 968 609 969 610 #if BUCKETLOCK == SPINLOCK 970 block = freeHead->freeList; // remove node from stack 611 lock( freeElem->lock __cfaabi_dbg_ctx2 ); 612 block = freeElem->freeList; // remove node from stack 971 613 #else 972 block = pop( free Head->freeList );614 block = pop( freeElem->freeList ); 973 615 #endif // BUCKETLOCK 974 616 if ( unlikely( block == 0p ) ) { // no free block ? 975 #ifdef OWNERSHIP 976 // Freelist for that size is empty, so carve it out of the heap, if there is enough left, or get some more 617 #if BUCKETLOCK == SPINLOCK 618 unlock( freeElem->lock ); 619 #endif // BUCKETLOCK 620 621 // Freelist for that size was empty, so carve it out of the heap if there's enough left, or get some more 977 622 // and then carve it off. 978 #ifdef RETURNSPIN 979 #if BUCKETLOCK == SPINLOCK 980 lock( freeHead->returnLock ); 981 block = freeHead->returnList; 982 freeHead->returnList = 0p; 983 unlock( freeHead->returnLock ); 984 #else 985 block = __atomic_exchange_n( &freeHead->returnList, nullptr, __ATOMIC_SEQ_CST ); 986 #endif // RETURNSPIN 987 988 if ( likely( block == 0p ) ) { // return list also empty? 989 #endif // OWNERSHIP 990 // Do not leave kernel thread as manager_extend accesses heapManager. 991 disable_interrupts(); 992 block = (Heap.Storage *)manager_extend( tsize ); // mutual exclusion on call 993 enable_interrupts( false ); 994 995 // OK TO BE PREEMPTED HERE AS heapManager IS NO LONGER ACCESSED. 996 997 #ifdef __CFA_DEBUG__ 998 // Scrub new memory so subsequent uninitialized usages might fail. Only scrub the first 1024 bytes. 999 memset( block->data, SCRUB, min( SCRUB_SIZE, tsize - sizeof(Heap.Storage) ) ); 1000 #endif // __CFA_DEBUG__ 1001 #endif // BUCKETLOCK 1002 #ifdef OWNERSHIP 1003 } else { // merge returnList into freeHead 1004 #ifdef __STATISTICS__ 1005 stats.return_pulls += 1; 1006 #endif // __STATISTICS__ 1007 1008 // OK TO BE PREEMPTED HERE AS heapManager IS NO LONGER ACCESSED. 1009 1010 freeHead->freeList = block->header.kind.real.next; 1011 } // if 1012 #endif // OWNERSHIP 623 624 block = (Heap.Storage *)extend( tsize ); // mutual exclusion on call 625 #if BUCKETLOCK == SPINLOCK 1013 626 } else { 1014 // Memory is scrubbed in doFree. 1015 freeHead->freeList = block->header.kind.real.next; 1016 } // if 1017 1018 block->header.kind.real.home = freeHead; // pointer back to free list of apropriate size 627 freeElem->freeList = block->header.kind.real.next; 628 unlock( freeElem->lock ); 629 #endif // BUCKETLOCK 630 } // if 631 632 block->header.kind.real.home = freeElem; // pointer back to free list of apropriate size 1019 633 } else { // large size => mmap 1020 634 if ( unlikely( size > ULONG_MAX - __page_size ) ) return 0p; 1021 635 tsize = ceiling2( tsize, __page_size ); // must be multiple of page size 1022 636 #ifdef __STATISTICS__ 1023 stats.counters[STAT_NAME].alloc += tsize; 1024 stats.mmap_calls += 1; 1025 stats.mmap_storage_request += size; 1026 stats.mmap_storage_alloc += tsize; 1027 #endif // __STATISTICS__ 1028 1029 disable_interrupts(); 1030 block = (Heap.Storage *)mmap( 0, tsize, __map_prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0 ); 1031 enable_interrupts( false ); 1032 1033 // OK TO BE PREEMPTED HERE AS heapManager IS NO LONGER ACCESSED. 1034 1035 if ( unlikely( block == (Heap.Storage *)MAP_FAILED ) ) { // failed ? 637 __atomic_add_fetch( &stats.mmap_calls, 1, __ATOMIC_SEQ_CST ); 638 __atomic_add_fetch( &stats.mmap_storage_request, size, __ATOMIC_SEQ_CST ); 639 __atomic_add_fetch( &stats.mmap_storage_alloc, tsize, __ATOMIC_SEQ_CST ); 640 #endif // __STATISTICS__ 641 642 block = (Heap.Storage *)mmap( 0, tsize, __map_prot, MAP_PRIVATE | MAP_ANONYMOUS, mmapFd, 0 ); 643 if ( block == (Heap.Storage *)MAP_FAILED ) { // failed ? 1036 644 if ( errno == ENOMEM ) abort( NO_MEMORY_MSG, tsize ); // no memory 1037 645 // Do not call strerror( errno ) as it may call malloc. 1038 abort( "attempt to allocate large object (> %zu) of size %zu bytes and mmap failed with errno %d.", size, heapMaster.mmapStart, errno ); 1039 } // if 646 abort( "(Heap &)0x%p.doMalloc() : internal error, mmap failure, size:%zu errno:%d.", &heapManager, tsize, errno ); 647 } //if 648 #ifdef __CFA_DEBUG__ 649 // Set new memory to garbage so subsequent uninitialized usages might fail. 650 memset( block, '\xde', tsize ); 651 //Memset( block, tsize ); 652 #endif // __CFA_DEBUG__ 1040 653 block->header.kind.real.blockSize = MarkMmappedBit( tsize ); // storage size for munmap 1041 1042 #ifdef __CFA_DEBUG__1043 // Scrub new memory so subsequent uninitialized usages might fail. Only scrub the first 1024 bytes. The rest of1044 // the storage set to 0 by mmap.1045 memset( block->data, SCRUB, min( SCRUB_SIZE, tsize - sizeof(Heap.Storage) ) );1046 #endif // __CFA_DEBUG__1047 654 } // if 1048 655 … … 1052 659 1053 660 #ifdef __CFA_DEBUG__ 661 __atomic_add_fetch( &allocUnfreed, tsize, __ATOMIC_SEQ_CST ); 1054 662 if ( traceHeap() ) { 1055 663 char helpText[64]; … … 1059 667 #endif // __CFA_DEBUG__ 1060 668 1061 // poll_interrupts(); // call rollforward1062 1063 669 return addr; 1064 670 } // doMalloc 1065 671 1066 672 1067 static void doFree( void * addr ) libcfa_nopreempt with( *heapManager ) { 1068 verify( addr ); 1069 1070 // detect free after thread-local storage destruction and use global stats in that case 673 static inline void doFree( void * addr ) with( heapManager ) { 674 #ifdef __CFA_DEBUG__ 675 if ( unlikely( heapManager.heapBegin == 0p ) ) { 676 abort( "doFree( %p ) : internal error, called before heap is initialized.", addr ); 677 } // if 678 #endif // __CFA_DEBUG__ 1071 679 1072 680 Heap.Storage.Header * header; 1073 Heap.FreeHeader * freeHead; 1074 size_t size, alignment; 1075 1076 bool mapped = headers( "free", addr, header, freeHead, size, alignment ); 1077 #if defined( __STATISTICS__ ) || defined( __CFA_DEBUG__ ) 1078 size_t rsize = header->kind.real.size; // optimization 1079 #endif // __STATISTICS__ || __CFA_DEBUG__ 1080 1081 #ifdef __STATISTICS__ 1082 stats.free_storage_request += rsize; 1083 stats.free_storage_alloc += size; 1084 #endif // __STATISTICS__ 1085 1086 #ifdef __CFA_DEBUG__ 1087 allocUnfreed -= rsize; 1088 #endif // __CFA_DEBUG__ 1089 1090 if ( unlikely( mapped ) ) { // mmapped ? 1091 #ifdef __STATISTICS__ 1092 stats.munmap_calls += 1; 1093 stats.munmap_storage_request += rsize; 1094 stats.munmap_storage_alloc += size; 1095 #endif // __STATISTICS__ 1096 1097 // OK TO BE PREEMPTED HERE AS heapManager IS NO LONGER ACCESSED. 1098 1099 // Does not matter where this storage is freed. 1100 if ( unlikely( munmap( header, size ) == -1 ) ) { 1101 // Do not call strerror( errno ) as it may call malloc. 1102 abort( "attempt to deallocate large object %p and munmap failed with errno %d.\n" 1103 "Possible cause is invalid delete pointer: either not allocated or with corrupt header.", 1104 addr, errno ); 681 Heap.FreeHeader * freeElem; 682 size_t size, alignment; // not used (see realloc) 683 684 if ( headers( "free", addr, header, freeElem, size, alignment ) ) { // mmapped ? 685 #ifdef __STATISTICS__ 686 __atomic_add_fetch( &stats.munmap_calls, 1, __ATOMIC_SEQ_CST ); 687 __atomic_add_fetch( &stats.munmap_storage_request, header->kind.real.size, __ATOMIC_SEQ_CST ); 688 __atomic_add_fetch( &stats.munmap_storage_alloc, size, __ATOMIC_SEQ_CST ); 689 #endif // __STATISTICS__ 690 if ( munmap( header, size ) == -1 ) { 691 abort( "Attempt to deallocate storage %p not allocated or with corrupt header.\n" 692 "Possible cause is invalid pointer.", 693 addr ); 1105 694 } // if 1106 695 } else { 1107 696 #ifdef __CFA_DEBUG__ 1108 // memset is NOT always inlined! 1109 disable_interrupts(); 1110 // Scrub old memory so subsequent usages might fail. Only scrub the first/last SCRUB_SIZE bytes. 1111 char * data = ((Heap.Storage *)header)->data; // data address 1112 size_t dsize = size - sizeof(Heap.Storage); // data size 1113 if ( dsize <= SCRUB_SIZE * 2 ) { 1114 memset( data, SCRUB, dsize ); // scrub all 1115 } else { 1116 memset( data, SCRUB, SCRUB_SIZE ); // scrub front 1117 memset( data + dsize - SCRUB_SIZE, SCRUB, SCRUB_SIZE ); // scrub back 1118 } // if 1119 enable_interrupts( false ); 697 // Set free memory to garbage so subsequent usages might fail. 698 memset( ((Heap.Storage *)header)->data, '\xde', freeElem->blockSize - sizeof( Heap.Storage ) ); 699 //Memset( ((Heap.Storage *)header)->data, freeElem->blockSize - sizeof( Heap.Storage ) ); 1120 700 #endif // __CFA_DEBUG__ 1121 701 1122 if ( likely( heapManager == freeHead->homeManager ) ) { // belongs to this thread 1123 header->kind.real.next = freeHead->freeList; // push on stack 1124 freeHead->freeList = (Heap.Storage *)header; 1125 } else { // return to thread owner 1126 verify( heapManager ); 1127 1128 #ifdef OWNERSHIP 1129 #ifdef RETURNSPIN 1130 lock( freeHead->returnLock ); 1131 header->kind.real.next = freeHead->returnList; // push to bucket return list 1132 freeHead->returnList = (Heap.Storage *)header; 1133 unlock( freeHead->returnLock ); 1134 #else // lock free 1135 header->kind.real.next = freeHead->returnList; // link new node to top node 1136 // CAS resets header->kind.real.next = freeHead->returnList on failure 1137 while ( ! __atomic_compare_exchange_n( &freeHead->returnList, &header->kind.real.next, header, 1138 false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) ); 1139 #endif // RETURNSPIN 1140 1141 #else // no OWNERSHIP 1142 1143 freeHead = &heap->freeLists[ClearStickyBits( header->kind.real.home ) - &freeHead->homeManager->freeLists[0]]; 1144 header->kind.real.next = freeHead->freeList; // push on stack 1145 freeHead->freeList = (Heap.Storage *)header; 1146 #endif // ! OWNERSHIP 1147 1148 #ifdef __U_STATISTICS__ 1149 stats.return_pushes += 1; 1150 stats.return_storage_request += rsize; 1151 stats.return_storage_alloc += size; 1152 #endif // __U_STATISTICS__ 1153 1154 // OK TO BE PREEMPTED HERE AS heapManager IS NO LONGER ACCESSED. 1155 } // if 702 #ifdef __STATISTICS__ 703 __atomic_add_fetch( &stats.free_calls, 1, __ATOMIC_SEQ_CST ); 704 __atomic_add_fetch( &stats.free_storage_request, header->kind.real.size, __ATOMIC_SEQ_CST ); 705 __atomic_add_fetch( &stats.free_storage_alloc, size, __ATOMIC_SEQ_CST ); 706 #endif // __STATISTICS__ 707 708 #if BUCKETLOCK == SPINLOCK 709 lock( freeElem->lock __cfaabi_dbg_ctx2 ); // acquire spin lock 710 header->kind.real.next = freeElem->freeList; // push on stack 711 freeElem->freeList = (Heap.Storage *)header; 712 unlock( freeElem->lock ); // release spin lock 713 #else 714 push( freeElem->freeList, *(Heap.Storage *)header ); 715 #endif // BUCKETLOCK 1156 716 } // if 1157 717 1158 718 #ifdef __CFA_DEBUG__ 719 __atomic_add_fetch( &allocUnfreed, -size, __ATOMIC_SEQ_CST ); 1159 720 if ( traceHeap() ) { 1160 721 char helpText[64]; … … 1163 724 } // if 1164 725 #endif // __CFA_DEBUG__ 1165 1166 // poll_interrupts(); // call rollforward1167 726 } // doFree 1168 727 1169 728 1170 s ize_t prtFree( Heap & manager ) with( manager ) {729 static size_t prtFree( Heap & manager ) with( manager ) { 1171 730 size_t total = 0; 1172 731 #ifdef __STATISTICS__ … … 1174 733 __cfaabi_bits_print_nolock( STDERR_FILENO, "\nBin lists (bin size : free blocks on list)\n" ); 1175 734 #endif // __STATISTICS__ 1176 for ( unsigned int i = 0; i < heapMaster.maxBucketsUsed; i += 1 ) {735 for ( unsigned int i = 0; i < maxBucketsUsed; i += 1 ) { 1177 736 size_t size = freeLists[i].blockSize; 1178 737 #ifdef __STATISTICS__ … … 1205 764 __cfaabi_bits_release(); 1206 765 #endif // __STATISTICS__ 1207 return (char *)heap Master.heapEnd - (char *)heapMaster.heapBegin - total;766 return (char *)heapEnd - (char *)heapBegin - total; 1208 767 } // prtFree 1209 768 1210 769 1211 #ifdef __STATISTICS__ 1212 static void incCalls( long int statName ) libcfa_nopreempt { 1213 heapManager->stats.counters[statName].calls += 1; 1214 } // incCalls 1215 1216 static void incZeroCalls( long int statName ) libcfa_nopreempt { 1217 heapManager->stats.counters[statName].calls_0 += 1; 1218 } // incZeroCalls 1219 #endif // __STATISTICS__ 1220 1221 #ifdef __CFA_DEBUG__ 1222 static void incUnfreed( size_t offset ) libcfa_nopreempt { 1223 heapManager->allocUnfreed += offset; 1224 } // incUnfreed 1225 #endif // __CFA_DEBUG__ 1226 1227 1228 static void * memalignNoStats( size_t alignment, size_t size STAT_PARM ) { 770 static void ?{}( Heap & manager ) with( manager ) { 771 __page_size = sysconf( _SC_PAGESIZE ); 772 __map_prot = PROT_READ | PROT_WRITE | PROT_EXEC; 773 774 for ( unsigned int i = 0; i < NoBucketSizes; i += 1 ) { // initialize the free lists 775 freeLists[i].blockSize = bucketSizes[i]; 776 } // for 777 778 #ifdef FASTLOOKUP 779 unsigned int idx = 0; 780 for ( unsigned int i = 0; i < LookupSizes; i += 1 ) { 781 if ( i > bucketSizes[idx] ) idx += 1; 782 lookup[i] = idx; 783 } // for 784 #endif // FASTLOOKUP 785 786 if ( ! setMmapStart( malloc_mmap_start() ) ) { 787 abort( "Heap : internal error, mmap start initialization failure." ); 788 } // if 789 heapExpand = malloc_expansion(); 790 791 char * end = (char *)sbrk( 0 ); 792 heapBegin = heapEnd = sbrk( (char *)ceiling2( (long unsigned int)end, __page_size ) - end ); // move start of heap to multiple of alignment 793 } // Heap 794 795 796 static void ^?{}( Heap & ) { 797 #ifdef __STATISTICS__ 798 if ( traceHeapTerm() ) { 799 printStats(); 800 // prtUnfreed() called in heapAppStop() 801 } // if 802 #endif // __STATISTICS__ 803 } // ~Heap 804 805 806 static void memory_startup( void ) __attribute__(( constructor( STARTUP_PRIORITY_MEMORY ) )); 807 void memory_startup( void ) { 808 #ifdef __CFA_DEBUG__ 809 if ( heapBoot ) { // check for recursion during system boot 810 abort( "boot() : internal error, recursively invoked during system boot." ); 811 } // if 812 heapBoot = true; 813 #endif // __CFA_DEBUG__ 814 815 //verify( heapManager.heapBegin != 0 ); 816 //heapManager{}; 817 if ( heapManager.heapBegin == 0p ) heapManager{}; // sanity check 818 } // memory_startup 819 820 static void memory_shutdown( void ) __attribute__(( destructor( STARTUP_PRIORITY_MEMORY ) )); 821 void memory_shutdown( void ) { 822 ^heapManager{}; 823 } // memory_shutdown 824 825 826 static inline void * mallocNoStats( size_t size ) { // necessary for malloc statistics 827 verify( heapManager.heapBegin != 0p ); // called before memory_startup ? 828 if ( unlikely( size ) == 0 ) return 0p; // 0 BYTE ALLOCATION RETURNS NULL POINTER 829 830 #if __SIZEOF_POINTER__ == 8 831 verify( size < ((typeof(size_t))1 << 48) ); 832 #endif // __SIZEOF_POINTER__ == 8 833 return doMalloc( size ); 834 } // mallocNoStats 835 836 837 static inline void * memalignNoStats( size_t alignment, size_t size ) { 838 if ( unlikely( size ) == 0 ) return 0p; // 0 BYTE ALLOCATION RETURNS NULL POINTER 839 840 #ifdef __CFA_DEBUG__ 1229 841 checkAlign( alignment ); // check alignment 1230 1231 // if alignment <= default alignment or size == 0, do normal malloc as two headers are unnecessary 1232 if ( unlikely( alignment <= libAlign() || size == 0 ) ) return doMalloc( size STAT_ARG( STAT_NAME ) ); 842 #endif // __CFA_DEBUG__ 843 844 // if alignment <= default alignment, do normal malloc as two headers are unnecessary 845 if ( unlikely( alignment <= libAlign() ) ) return mallocNoStats( size ); 1233 846 1234 847 // Allocate enough storage to guarantee an address on the alignment boundary, and sufficient space before it for … … 1241 854 // subtract libAlign() because it is already the minimum alignment 1242 855 // add sizeof(Storage) for fake header 1243 size_t offset = alignment - libAlign() + sizeof(Heap.Storage); 1244 char * addr = (char *)doMalloc( size + offset STAT_ARG( STAT_NAME ) ); 856 char * addr = (char *)mallocNoStats( size + alignment - libAlign() + sizeof(Heap.Storage) ); 1245 857 1246 858 // address in the block of the "next" alignment address … … 1248 860 1249 861 // address of header from malloc 1250 Heap.Storage.Header * realHeader = HeaderAddr( addr ); 1251 realHeader->kind.real.size = size; // correct size to eliminate above alignment offset 1252 #ifdef __CFA_DEBUG__ 1253 incUnfreed( -offset ); // adjustment off the offset from call to doMalloc 1254 #endif // __CFA_DEBUG__ 1255 1256 // address of fake header *before* the alignment location 862 Heap.Storage.Header * RealHeader = HeaderAddr( addr ); 863 RealHeader->kind.real.size = size; // correct size to eliminate above alignment offset 864 // address of fake header * before* the alignment location 1257 865 Heap.Storage.Header * fakeHeader = HeaderAddr( user ); 1258 1259 866 // SKULLDUGGERY: insert the offset to the start of the actual storage block and remember alignment 1260 fakeHeader->kind.fake.offset = (char *)fakeHeader - (char *) realHeader;867 fakeHeader->kind.fake.offset = (char *)fakeHeader - (char *)RealHeader; 1261 868 // SKULLDUGGERY: odd alignment implies fake header 1262 869 fakeHeader->kind.fake.alignment = MarkAlignmentBit( alignment ); … … 1273 880 // then malloc() returns a unique pointer value that can later be successfully passed to free(). 1274 881 void * malloc( size_t size ) libcfa_public { 1275 return doMalloc( size STAT_ARG( MALLOC ) ); 882 #ifdef __STATISTICS__ 883 if ( likely( size > 0 ) ) { 884 __atomic_add_fetch( &stats.malloc_calls, 1, __ATOMIC_SEQ_CST ); 885 __atomic_add_fetch( &stats.malloc_storage_request, size, __ATOMIC_SEQ_CST ); 886 } else { 887 __atomic_add_fetch( &stats.malloc_0_calls, 1, __ATOMIC_SEQ_CST ); 888 } // if 889 #endif // __STATISTICS__ 890 891 return mallocNoStats( size ); 1276 892 } // malloc 1277 893 … … 1279 895 // Same as malloc() except size bytes is an array of dim elements each of elemSize bytes. 1280 896 void * aalloc( size_t dim, size_t elemSize ) libcfa_public { 1281 return doMalloc( dim * elemSize STAT_ARG( AALLOC ) ); 897 size_t size = dim * elemSize; 898 #ifdef __STATISTICS__ 899 if ( likely( size > 0 ) ) { 900 __atomic_add_fetch( &stats.aalloc_calls, 1, __ATOMIC_SEQ_CST ); 901 __atomic_add_fetch( &stats.aalloc_storage_request, size, __ATOMIC_SEQ_CST ); 902 } else { 903 __atomic_add_fetch( &stats.aalloc_0_calls, 1, __ATOMIC_SEQ_CST ); 904 } // if 905 #endif // __STATISTICS__ 906 907 return mallocNoStats( size ); 1282 908 } // aalloc 1283 909 … … 1286 912 void * calloc( size_t dim, size_t elemSize ) libcfa_public { 1287 913 size_t size = dim * elemSize; 1288 char * addr = (char *)doMalloc( size STAT_ARG( CALLOC ) ); 1289 1290 if ( unlikely( addr == NULL ) ) return NULL; // stop further processing if 0p is returned 914 if ( unlikely( size ) == 0 ) { // 0 BYTE ALLOCATION RETURNS NULL POINTER 915 #ifdef __STATISTICS__ 916 __atomic_add_fetch( &stats.calloc_0_calls, 1, __ATOMIC_SEQ_CST ); 917 #endif // __STATISTICS__ 918 return 0p; 919 } // if 920 #ifdef __STATISTICS__ 921 __atomic_add_fetch( &stats.calloc_calls, 1, __ATOMIC_SEQ_CST ); 922 __atomic_add_fetch( &stats.calloc_storage_request, dim * elemSize, __ATOMIC_SEQ_CST ); 923 #endif // __STATISTICS__ 924 925 char * addr = (char *)mallocNoStats( size ); 1291 926 1292 927 Heap.Storage.Header * header; 1293 Heap.FreeHeader * free Head;928 Heap.FreeHeader * freeElem; 1294 929 size_t bsize, alignment; 1295 930 … … 1297 932 bool mapped = 1298 933 #endif // __CFA_DEBUG__ 1299 headers( "calloc", addr, header, free Head, bsize, alignment );934 headers( "calloc", addr, header, freeElem, bsize, alignment ); 1300 935 1301 936 #ifndef __CFA_DEBUG__ 1302 937 // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero. 1303 if ( likely( ! mapped ))938 if ( ! mapped ) 1304 939 #endif // __CFA_DEBUG__ 1305 940 // <-------0000000000000000000000000000UUUUUUUUUUUUUUUUUUUUUUUUU> bsize (bucket size) U => undefined … … 1317 952 // call to malloc(), alloc(), calloc() or realloc(). If the area pointed to was moved, a free(oaddr) is done. 1318 953 void * resize( void * oaddr, size_t size ) libcfa_public { 1319 if ( unlikely( oaddr == 0p ) ) { // => malloc( size ) 1320 return doMalloc( size STAT_ARG( RESIZE ) ); 1321 } // if 1322 1323 PROLOG( RESIZE, doFree( oaddr ) ); // => free( oaddr ) 954 // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned. 955 if ( unlikely( size == 0 ) ) { // special cases 956 #ifdef __STATISTICS__ 957 __atomic_add_fetch( &stats.resize_0_calls, 1, __ATOMIC_SEQ_CST ); 958 #endif // __STATISTICS__ 959 free( oaddr ); 960 return 0p; 961 } // if 962 #ifdef __STATISTICS__ 963 __atomic_add_fetch( &stats.resize_calls, 1, __ATOMIC_SEQ_CST ); 964 #endif // __STATISTICS__ 965 966 if ( unlikely( oaddr == 0p ) ) { 967 #ifdef __STATISTICS__ 968 __atomic_add_fetch( &stats.resize_storage_request, size, __ATOMIC_SEQ_CST ); 969 #endif // __STATISTICS__ 970 return mallocNoStats( size ); 971 } // if 1324 972 1325 973 Heap.Storage.Header * header; 1326 Heap.FreeHeader * free Head;974 Heap.FreeHeader * freeElem; 1327 975 size_t bsize, oalign; 1328 headers( "resize", oaddr, header, free Head, bsize, oalign );976 headers( "resize", oaddr, header, freeElem, bsize, oalign ); 1329 977 1330 978 size_t odsize = DataStorage( bsize, oaddr, header ); // data storage available in bucket … … 1332 980 if ( oalign == libAlign() && size <= odsize && odsize <= size * 2 ) { // allow 50% wasted storage for smaller size 1333 981 ClearZeroFillBit( header ); // no alignment and turn off 0 fill 1334 #ifdef __CFA_DEBUG__1335 incUnfreed( size - header->kind.real.size ); // adjustment off the size difference1336 #endif // __CFA_DEBUG__1337 982 header->kind.real.size = size; // reset allocation size 1338 #ifdef __STATISTICS__1339 incCalls( RESIZE );1340 #endif // __STATISTICS__1341 983 return oaddr; 1342 984 } // if 1343 985 986 #ifdef __STATISTICS__ 987 __atomic_add_fetch( &stats.resize_storage_request, size, __ATOMIC_SEQ_CST ); 988 #endif // __STATISTICS__ 989 1344 990 // change size, DO NOT preserve STICKY PROPERTIES. 1345 doFree( oaddr ); // free previous storage 1346 1347 return doMalloc( size STAT_ARG( RESIZE ) ); // create new area 991 free( oaddr ); 992 return mallocNoStats( size ); // create new area 1348 993 } // resize 1349 994 … … 1352 997 // the old and new sizes. 1353 998 void * realloc( void * oaddr, size_t size ) libcfa_public { 1354 if ( unlikely( oaddr == 0p ) ) { // => malloc( size ) 1355 return doMalloc( size STAT_ARG( REALLOC ) ); 1356 } // if 1357 1358 PROLOG( REALLOC, doFree( oaddr ) ); // => free( oaddr ) 999 // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned. 1000 if ( unlikely( size == 0 ) ) { // special cases 1001 #ifdef __STATISTICS__ 1002 __atomic_add_fetch( &stats.realloc_0_calls, 1, __ATOMIC_SEQ_CST ); 1003 #endif // __STATISTICS__ 1004 free( oaddr ); 1005 return 0p; 1006 } // if 1007 #ifdef __STATISTICS__ 1008 __atomic_add_fetch( &stats.realloc_calls, 1, __ATOMIC_SEQ_CST ); 1009 #endif // __STATISTICS__ 1010 1011 if ( unlikely( oaddr == 0p ) ) { 1012 #ifdef __STATISTICS__ 1013 __atomic_add_fetch( &stats.realloc_storage_request, size, __ATOMIC_SEQ_CST ); 1014 #endif // __STATISTICS__ 1015 return mallocNoStats( size ); 1016 } // if 1359 1017 1360 1018 Heap.Storage.Header * header; 1361 Heap.FreeHeader * free Head;1019 Heap.FreeHeader * freeElem; 1362 1020 size_t bsize, oalign; 1363 headers( "realloc", oaddr, header, free Head, bsize, oalign );1021 headers( "realloc", oaddr, header, freeElem, bsize, oalign ); 1364 1022 1365 1023 size_t odsize = DataStorage( bsize, oaddr, header ); // data storage available in bucket … … 1367 1025 bool ozfill = ZeroFillBit( header ); // old allocation zero filled 1368 1026 if ( unlikely( size <= odsize ) && odsize <= size * 2 ) { // allow up to 50% wasted storage 1369 #ifdef __CFA_DEBUG__ 1370 incUnfreed( size - header->kind.real.size ); // adjustment off the size difference 1371 #endif // __CFA_DEBUG__ 1372 header->kind.real.size = size; // reset allocation size 1027 header->kind.real.size = size; // reset allocation size 1373 1028 if ( unlikely( ozfill ) && size > osize ) { // previous request zero fill and larger ? 1374 1029 memset( (char *)oaddr + osize, '\0', size - osize ); // initialize added storage 1375 1030 } // if 1376 #ifdef __STATISTICS__1377 incCalls( REALLOC );1378 #endif // __STATISTICS__1379 1031 return oaddr; 1380 1032 } // if 1381 1033 1034 #ifdef __STATISTICS__ 1035 __atomic_add_fetch( &stats.realloc_storage_request, size, __ATOMIC_SEQ_CST ); 1036 #endif // __STATISTICS__ 1037 1382 1038 // change size and copy old content to new storage 1383 1039 1384 1040 void * naddr; 1385 if ( likely( oalign <= libAlign() ) ) { // previous request not aligned ?1386 naddr = doMalloc( size STAT_ARG( REALLOC ) );// create new area1041 if ( likely( oalign == libAlign() ) ) { // previous request not aligned ? 1042 naddr = mallocNoStats( size ); // create new area 1387 1043 } else { 1388 naddr = memalignNoStats( oalign, size STAT_ARG( REALLOC ) ); // create new aligned area 1389 } // if 1390 1391 headers( "realloc", naddr, header, freeHead, bsize, oalign ); 1392 // To preserve prior fill, the entire bucket must be copied versus the size. 1044 naddr = memalignNoStats( oalign, size ); // create new aligned area 1045 } // if 1046 1047 headers( "realloc", naddr, header, freeElem, bsize, oalign ); 1393 1048 memcpy( naddr, oaddr, min( osize, size ) ); // copy bytes 1394 doFree( oaddr ); // free previous storage1049 free( oaddr ); 1395 1050 1396 1051 if ( unlikely( ozfill ) ) { // previous request zero fill ? … … 1412 1067 // Same as malloc() except the memory address is a multiple of alignment, which must be a power of two. (obsolete) 1413 1068 void * memalign( size_t alignment, size_t size ) libcfa_public { 1414 return memalignNoStats( alignment, size STAT_ARG( MEMALIGN ) ); 1069 #ifdef __STATISTICS__ 1070 if ( likely( size > 0 ) ) { 1071 __atomic_add_fetch( &stats.memalign_calls, 1, __ATOMIC_SEQ_CST ); 1072 __atomic_add_fetch( &stats.memalign_storage_request, size, __ATOMIC_SEQ_CST ); 1073 } else { 1074 __atomic_add_fetch( &stats.memalign_0_calls, 1, __ATOMIC_SEQ_CST ); 1075 } // if 1076 #endif // __STATISTICS__ 1077 1078 return memalignNoStats( alignment, size ); 1415 1079 } // memalign 1416 1080 … … 1418 1082 // Same as aalloc() with memory alignment. 1419 1083 void * amemalign( size_t alignment, size_t dim, size_t elemSize ) libcfa_public { 1420 return memalignNoStats( alignment, dim * elemSize STAT_ARG( AMEMALIGN ) ); 1084 size_t size = dim * elemSize; 1085 #ifdef __STATISTICS__ 1086 if ( likely( size > 0 ) ) { 1087 __atomic_add_fetch( &stats.cmemalign_calls, 1, __ATOMIC_SEQ_CST ); 1088 __atomic_add_fetch( &stats.cmemalign_storage_request, size, __ATOMIC_SEQ_CST ); 1089 } else { 1090 __atomic_add_fetch( &stats.cmemalign_0_calls, 1, __ATOMIC_SEQ_CST ); 1091 } // if 1092 #endif // __STATISTICS__ 1093 1094 return memalignNoStats( alignment, size ); 1421 1095 } // amemalign 1422 1096 … … 1425 1099 void * cmemalign( size_t alignment, size_t dim, size_t elemSize ) libcfa_public { 1426 1100 size_t size = dim * elemSize; 1427 char * addr = (char *)memalignNoStats( alignment, size STAT_ARG( CMEMALIGN ) ); 1428 1429 if ( unlikely( addr == NULL ) ) return NULL; // stop further processing if 0p is returned 1101 if ( unlikely( size ) == 0 ) { // 0 BYTE ALLOCATION RETURNS NULL POINTER 1102 #ifdef __STATISTICS__ 1103 __atomic_add_fetch( &stats.cmemalign_0_calls, 1, __ATOMIC_SEQ_CST ); 1104 #endif // __STATISTICS__ 1105 return 0p; 1106 } // if 1107 #ifdef __STATISTICS__ 1108 __atomic_add_fetch( &stats.cmemalign_calls, 1, __ATOMIC_SEQ_CST ); 1109 __atomic_add_fetch( &stats.cmemalign_storage_request, dim * elemSize, __ATOMIC_SEQ_CST ); 1110 #endif // __STATISTICS__ 1111 1112 char * addr = (char *)memalignNoStats( alignment, size ); 1430 1113 1431 1114 Heap.Storage.Header * header; 1432 Heap.FreeHeader * free Head;1115 Heap.FreeHeader * freeElem; 1433 1116 size_t bsize; 1434 1117 … … 1436 1119 bool mapped = 1437 1120 #endif // __CFA_DEBUG__ 1438 headers( "cmemalign", addr, header, free Head, bsize, alignment );1121 headers( "cmemalign", addr, header, freeElem, bsize, alignment ); 1439 1122 1440 1123 // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero. … … 1486 1169 // 0p, no operation is performed. 1487 1170 void free( void * addr ) libcfa_public { 1488 // verify( heapManager );1489 1490 1171 if ( unlikely( addr == 0p ) ) { // special case 1491 1172 #ifdef __STATISTICS__ 1492 if ( heapManager ) 1493 incZeroCalls( FREE ); 1173 __atomic_add_fetch( &stats.free_null_calls, 1, __ATOMIC_SEQ_CST ); 1494 1174 #endif // __STATISTICS__ 1175 1176 // #ifdef __CFA_DEBUG__ 1177 // if ( traceHeap() ) { 1178 // #define nullmsg "Free( 0x0 ) size:0\n" 1179 // // Do not debug print free( 0p ), as it can cause recursive entry from sprintf. 1180 // __cfaabi_dbg_write( nullmsg, sizeof(nullmsg) - 1 ); 1181 // } // if 1182 // #endif // __CFA_DEBUG__ 1495 1183 return; 1496 } // if 1497 1498 #ifdef __STATISTICS__ 1499 incCalls( FREE ); 1500 #endif // __STATISTICS__ 1501 1502 doFree( addr ); // handles heapManager == nullptr 1184 } // exit 1185 1186 doFree( addr ); 1503 1187 } // free 1504 1188 … … 1543 1227 if ( unlikely( addr == 0p ) ) return 0; // null allocation has 0 size 1544 1228 Heap.Storage.Header * header; 1545 Heap.FreeHeader * free Head;1229 Heap.FreeHeader * freeElem; 1546 1230 size_t bsize, alignment; 1547 1231 1548 headers( "malloc_usable_size", addr, header, free Head, bsize, alignment );1232 headers( "malloc_usable_size", addr, header, freeElem, bsize, alignment ); 1549 1233 return DataStorage( bsize, addr, header ); // data storage in bucket 1550 1234 } // malloc_usable_size … … 1554 1238 void malloc_stats( void ) libcfa_public { 1555 1239 #ifdef __STATISTICS__ 1556 HeapStatistics stats; 1557 HeapStatisticsCtor( stats ); 1558 if ( printStats( collectStats( stats ) ) == -1 ) { 1559 #else 1560 #define MALLOC_STATS_MSG "malloc_stats statistics disabled.\n" 1561 if ( write( STDERR_FILENO, MALLOC_STATS_MSG, sizeof( MALLOC_STATS_MSG ) - 1 /* size includes '\0' */ ) == -1 ) { 1562 #endif // __STATISTICS__ 1563 abort( "write failed in malloc_stats" ); 1564 } // if 1240 printStats(); 1241 if ( prtFree() ) prtFree( heapManager ); 1242 #endif // __STATISTICS__ 1565 1243 } // malloc_stats 1566 1244 … … 1569 1247 int malloc_stats_fd( int fd __attribute__(( unused )) ) libcfa_public { 1570 1248 #ifdef __STATISTICS__ 1571 int temp = heapMaster.stats_fd;1572 heapMaster.stats_fd = fd;1249 int temp = stats_fd; 1250 stats_fd = fd; 1573 1251 return temp; 1574 1252 #else … … 1584 1262 if ( options != 0 ) { errno = EINVAL; return -1; } 1585 1263 #ifdef __STATISTICS__ 1586 HeapStatistics stats; 1587 HeapStatisticsCtor( stats ); 1588 return printStatsXML( collectStats( stats ), stream ); // returns bytes written or -1 1264 return printStatsXML( stream ); 1589 1265 #else 1590 1266 return 0; // unsupported … … 1599 1275 choose( option ) { 1600 1276 case M_TOP_PAD: 1601 heap Master.heapExpand = ceiling2( value, __page_size );1277 heapExpand = ceiling2( value, __page_size ); 1602 1278 return 1; 1603 1279 case M_MMAP_THRESHOLD: … … 1643 1319 // Must have CFA linkage to overload with C linkage realloc. 1644 1320 void * resize( void * oaddr, size_t nalign, size_t size ) libcfa_public { 1645 if ( unlikely( oaddr == 0p ) ) { // => malloc( size ) 1646 return memalignNoStats( nalign, size STAT_ARG( RESIZE ) ); 1647 } // if 1648 1649 PROLOG( RESIZE, doFree( oaddr ) ); // => free( oaddr ) 1321 // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned. 1322 if ( unlikely( size == 0 ) ) { // special cases 1323 #ifdef __STATISTICS__ 1324 __atomic_add_fetch( &stats.resize_0_calls, 1, __ATOMIC_SEQ_CST ); 1325 #endif // __STATISTICS__ 1326 free( oaddr ); 1327 return 0p; 1328 } // if 1329 1330 if ( unlikely( nalign < libAlign() ) ) nalign = libAlign(); // reset alignment to minimum 1331 #ifdef __CFA_DEBUG__ 1332 else checkAlign( nalign ); // check alignment 1333 #endif // __CFA_DEBUG__ 1334 1335 if ( unlikely( oaddr == 0p ) ) { 1336 #ifdef __STATISTICS__ 1337 __atomic_add_fetch( &stats.resize_calls, 1, __ATOMIC_SEQ_CST ); 1338 __atomic_add_fetch( &stats.resize_storage_request, size, __ATOMIC_SEQ_CST ); 1339 #endif // __STATISTICS__ 1340 return memalignNoStats( nalign, size ); 1341 } // if 1650 1342 1651 1343 // Attempt to reuse existing alignment. … … 1655 1347 1656 1348 if ( unlikely( isFakeHeader ) ) { 1657 checkAlign( nalign ); // check alignment1658 1349 oalign = ClearAlignmentBit( header ); // old alignment 1659 1350 if ( unlikely( (uintptr_t)oaddr % nalign == 0 // lucky match ? … … 1662 1353 ) ) { 1663 1354 HeaderAddr( oaddr )->kind.fake.alignment = MarkAlignmentBit( nalign ); // update alignment (could be the same) 1664 Heap.FreeHeader * free Head;1355 Heap.FreeHeader * freeElem; 1665 1356 size_t bsize, oalign; 1666 headers( "resize", oaddr, header, free Head, bsize, oalign );1357 headers( "resize", oaddr, header, freeElem, bsize, oalign ); 1667 1358 size_t odsize = DataStorage( bsize, oaddr, header ); // data storage available in bucket 1668 1359 … … 1670 1361 HeaderAddr( oaddr )->kind.fake.alignment = MarkAlignmentBit( nalign ); // update alignment (could be the same) 1671 1362 ClearZeroFillBit( header ); // turn off 0 fill 1672 #ifdef __CFA_DEBUG__1673 incUnfreed( size - header->kind.real.size ); // adjustment off the size difference1674 #endif // __CFA_DEBUG__1675 1363 header->kind.real.size = size; // reset allocation size 1676 #ifdef __STATISTICS__1677 incCalls( RESIZE );1678 #endif // __STATISTICS__1679 1364 return oaddr; 1680 1365 } // if … … 1685 1370 } // if 1686 1371 1372 #ifdef __STATISTICS__ 1373 __atomic_add_fetch( &stats.resize_storage_request, size, __ATOMIC_SEQ_CST ); 1374 #endif // __STATISTICS__ 1375 1687 1376 // change size, DO NOT preserve STICKY PROPERTIES. 1688 doFree( oaddr ); // free previous storage1689 return memalignNoStats( nalign, size STAT_ARG( RESIZE ) );// create new aligned area1377 free( oaddr ); 1378 return memalignNoStats( nalign, size ); // create new aligned area 1690 1379 } // resize 1691 1380 1692 1381 1693 1382 void * realloc( void * oaddr, size_t nalign, size_t size ) libcfa_public { 1694 if ( unlikely( oaddr == 0p ) ) { // => malloc( size ) 1695 return memalignNoStats( nalign, size STAT_ARG( REALLOC ) ); 1696 } // if 1697 1698 PROLOG( REALLOC, doFree( oaddr ) ); // => free( oaddr ) 1383 // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned. 1384 if ( unlikely( size == 0 ) ) { // special cases 1385 #ifdef __STATISTICS__ 1386 __atomic_add_fetch( &stats.realloc_0_calls, 1, __ATOMIC_SEQ_CST ); 1387 #endif // __STATISTICS__ 1388 free( oaddr ); 1389 return 0p; 1390 } // if 1391 1392 if ( unlikely( nalign < libAlign() ) ) nalign = libAlign(); // reset alignment to minimum 1393 #ifdef __CFA_DEBUG__ 1394 else checkAlign( nalign ); // check alignment 1395 #endif // __CFA_DEBUG__ 1396 1397 if ( unlikely( oaddr == 0p ) ) { 1398 #ifdef __STATISTICS__ 1399 __atomic_add_fetch( &stats.realloc_calls, 1, __ATOMIC_SEQ_CST ); 1400 __atomic_add_fetch( &stats.realloc_storage_request, size, __ATOMIC_SEQ_CST ); 1401 #endif // __STATISTICS__ 1402 return memalignNoStats( nalign, size ); 1403 } // if 1699 1404 1700 1405 // Attempt to reuse existing alignment. … … 1703 1408 size_t oalign; 1704 1409 if ( unlikely( isFakeHeader ) ) { 1705 checkAlign( nalign ); // check alignment1706 1410 oalign = ClearAlignmentBit( header ); // old alignment 1707 1411 if ( unlikely( (uintptr_t)oaddr % nalign == 0 // lucky match ? … … 1717 1421 } // if 1718 1422 1719 Heap.FreeHeader * freeHead; 1423 #ifdef __STATISTICS__ 1424 __atomic_add_fetch( &stats.realloc_calls, 1, __ATOMIC_SEQ_CST ); 1425 __atomic_add_fetch( &stats.realloc_storage_request, size, __ATOMIC_SEQ_CST ); 1426 #endif // __STATISTICS__ 1427 1428 Heap.FreeHeader * freeElem; 1720 1429 size_t bsize; 1721 headers( "realloc", oaddr, header, free Head, bsize, oalign );1430 headers( "realloc", oaddr, header, freeElem, bsize, oalign ); 1722 1431 1723 1432 // change size and copy old content to new storage … … 1726 1435 bool ozfill = ZeroFillBit( header ); // old allocation zero filled 1727 1436 1728 void * naddr = memalignNoStats( nalign, size STAT_ARG( REALLOC ) );// create new aligned area1729 1730 headers( "realloc", naddr, header, free Head, bsize, oalign );1437 void * naddr = memalignNoStats( nalign, size ); // create new aligned area 1438 1439 headers( "realloc", naddr, header, freeElem, bsize, oalign ); 1731 1440 memcpy( naddr, oaddr, min( osize, size ) ); // copy bytes 1732 doFree( oaddr ); // free previous storage1441 free( oaddr ); 1733 1442 1734 1443 if ( unlikely( ozfill ) ) { // previous request zero fill ? … … 1742 1451 1743 1452 1744 void * reallocarray( void * oaddr, size_t nalign, size_t dim, size_t elemSize ) __THROW {1745 return realloc( oaddr, nalign, dim * elemSize );1746 } // reallocarray1747 1748 1749 1453 // Local Variables: // 1750 1454 // tab-width: 4 // -
libcfa/src/heap.hfa
r4f102fa ra55472cc 10 10 // Created On : Tue May 26 11:23:55 2020 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T ue Oct 4 19:08:55 202213 // Update Count : 2 312 // Last Modified On : Thu Apr 21 22:52:25 2022 13 // Update Count : 21 14 14 // 15 15 … … 30 30 bool checkFreeOff(); 31 31 32 // supported mallopt options 33 #ifndef M_MMAP_THRESHOLD 34 #define M_MMAP_THRESHOLD (-1) 35 #endif // M_MMAP_THRESHOLD 36 37 #ifndef M_TOP_PAD 38 #define M_TOP_PAD (-2) 39 #endif // M_TOP_PAD 40 32 41 extern "C" { 33 42 // New allocation operations. … … 40 49 size_t malloc_size( void * addr ); 41 50 int malloc_stats_fd( int fd ); 51 size_t malloc_usable_size( void * addr ); 42 52 size_t malloc_expansion(); // heap expansion size (bytes) 43 53 size_t malloc_mmap_start(); // crossover allocation size from sbrk to mmap -
libcfa/src/startup.cfa
r4f102fa ra55472cc 10 10 // Created On : Tue Jul 24 16:21:57 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Oct 6 13:51:57202213 // Update Count : 5 712 // Last Modified On : Mon Jan 17 16:41:54 2022 13 // Update Count : 55 14 14 // 15 15 … … 24 24 25 25 extern "C" { 26 void __cfaabi_memory_startup( void ) __attribute__(( constructor( STARTUP_PRIORITY_MEMORY ) ));27 void __cfaabi_memory_startup( void ) {28 extern void memory_startup();29 memory_startup();30 } // __cfaabi_memory_startup31 32 void __cfaabi_memory_shutdown( void ) __attribute__(( destructor( STARTUP_PRIORITY_MEMORY ) ));33 void __cfaabi_memory_shutdown( void ) {34 extern void memory_shutdown();35 memory_shutdown();36 } // __cfaabi_memory_shutdown37 38 26 void __cfaabi_appready_startup( void ) __attribute__(( constructor( STARTUP_PRIORITY_APPREADY ) )); 39 27 void __cfaabi_appready_startup( void ) { 40 28 tzset(); // initialize time global variables 29 #ifdef __CFA_DEBUG__ 41 30 extern void heapAppStart(); 42 31 heapAppStart(); 32 #endif // __CFA_DEBUG__ 43 33 } // __cfaabi_appready_startup 44 34 45 35 void __cfaabi_appready_shutdown( void ) __attribute__(( destructor( STARTUP_PRIORITY_APPREADY ) )); 46 36 void __cfaabi_appready_shutdown( void ) { 37 #ifdef __CFA_DEBUG__ 47 38 extern void heapAppStop(); 48 39 heapAppStop(); 40 #endif // __CFA_DEBUG__ 49 41 } // __cfaabi_appready_shutdown 50 42 -
libcfa/src/stdhdr/assert.h
r4f102fa ra55472cc 10 10 // Created On : Mon Jul 4 23:25:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Oct 9 21:28:22 202213 // Update Count : 1 612 // Last Modified On : Tue Feb 4 12:58:49 2020 13 // Update Count : 15 14 14 // 15 15 … … 31 31 #endif 32 32 33 #if ! defined(NDEBUG) && (defined(__CFA_DEBUG__) || defined(__CFA_VERIFY__))33 #if !defined(NDEBUG) && (defined(__CFA_DEBUG__) || defined(__CFA_VERIFY__)) 34 34 #define __CFA_WITH_VERIFY__ 35 35 #define verify(x) assert(x) -
tests/.expect/alloc.txt
r4f102fa ra55472cc 35 35 CFA realloc array alloc, fill 36 36 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 37 CFA realloc array alloc, 538 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0xdededede 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x539 CFA realloc array alloc, 540 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef41 CFA realloc array alloc, 542 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x5 0x543 37 44 38 C memalign 42 42.5 -
tests/alloc.cfa
r4f102fa ra55472cc 10 10 // Created On : Wed Feb 3 07:56:22 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Jul 29 10:57:02 202213 // Update Count : 43 612 // Last Modified On : Mon Apr 18 17:13:52 2022 13 // Update Count : 433 14 14 // 15 15 … … 154 154 printf( "\n" ); 155 155 // do not free 156 156 #if 0 // FIX ME 157 157 ip = alloc( 5 * dim, ip`realloc, 5`fill ); // CFA realloc array alloc, 5 158 158 printf( "CFA realloc array alloc, 5\n" ); … … 171 171 for ( i; 5 * dim ) { printf( "%#x ", ip[i] ); } 172 172 printf( "\n" ); 173 173 #endif // 0 174 174 free( ip ); 175 175 -
tests/alloc2.cfa
r4f102fa ra55472cc 1 #include <fstream.hfa> // sout2 1 #include <malloc.h> // malloc_usable_size 3 2 #include <stdint.h> // uintptr_t … … 5 4 #include <string.h> // memcmp 6 5 6 int last_failed; 7 7 int tests_total; 8 8 int tests_failed; … … 13 13 void test_base( void * ip, size_t size, size_t align ) { 14 14 tests_total += 1; 15 // sout | "DEBUG: starting test" | tests_total;15 // printf( "DEBUG: starting test %d\n", tests_total); 16 16 bool passed = (malloc_size( ip ) == size) && (malloc_usable_size( ip ) >= size) && (malloc_alignment( ip ) == align) && ((uintptr_t)ip % align == 0); 17 17 if ( ! passed ) { 18 sout | "base failed test" | tests_total | "ip" | ip | "size" | size | "align" | align | "but got size" | malloc_size( ip ) | "usable" | malloc_usable_size( ip ) | "align" | malloc_alignment( ip);18 printf( "failed test %3d: %4zu %4zu but got %4zu ( %3zu ) %4zu\n", tests_total, size, align, malloc_size( ip ), malloc_usable_size( ip ), malloc_alignment( ip ) ); 19 19 tests_failed += 1; 20 20 } // if 21 // sout | "DEBUG: done test" | tests_total;21 // printf( "DEBUG: done test %d\n", tests_total); 22 22 } 23 23 24 24 void test_fill( void * ip_, size_t start, size_t end, char fill ) { 25 25 tests_total += 1; 26 // sout | "DEBUG: starting test" | tests_total;26 // printf( "DEBUG: starting test %d\n", tests_total ); 27 27 bool passed = true; 28 28 char * ip = (char *) ip_; 29 29 for ( i; start ~ end ) passed = passed && (ip[i] == fill); 30 30 if ( ! passed ) { 31 sout | "fill1 failed test" | tests_total | "fill C";31 printf( "failed test %3d: fill C\n", tests_total ); 32 32 tests_failed += 1; 33 33 } // if 34 // sout | "DEBUG: done test" | tests_total;34 // printf( "DEBUG: done test %d\n", tests_total ); 35 35 } 36 36 37 37 void test_fill( void * ip_, size_t start, size_t end, int fill ) { 38 38 tests_total += 1; 39 // sout | "DEBUG: starting test" tests_total;39 // printf( "DEBUG: starting test %d\n", tests_total ); 40 40 bool passed = true; 41 41 int * ip = (int *)ip_; 42 for ( i; start ~ end ) passed = passed && (ip[i] == fill);42 for (i; start ~ end ) passed = passed && (ip[i] == fill); 43 43 if ( ! passed ) { 44 sout | "fill2 failed test" | tests_total | "fill int";44 printf( "failed test %3d: fill int\n", tests_total ); 45 45 tests_failed += 1; 46 46 } // if 47 // sout | "DEBUG: done test" | tests_total;47 // printf( "DEBUG: done test %d\n", tests_total ); 48 48 } 49 49 50 50 void test_fill( void * ip_, size_t start, size_t end, int * fill ) { 51 51 tests_total += 1; 52 // sout | "DEBUG: starting test" | tests_total;52 // printf( "DEBUG: starting test %d\n", tests_total ); 53 53 bool passed = memcmp((void*)((uintptr_t )ip_ + start ), (void*)fill, end ) == 0; 54 54 if ( ! passed ) { 55 sout | "fill3 failed test" | tests_total | "fill int A";55 printf( "failed test %3d: fill int A\n", tests_total ); 56 56 tests_failed += 1; 57 57 } // if 58 // sout | "DEBUG: done test" | tests_total;58 // printf( "DEBUG: done test %d\n", tests_total ); 59 59 } 60 60 61 61 void test_fill( void * ip_, size_t start, size_t end, T1 fill ) { 62 62 tests_total += 1; 63 // sout | "DEBUG: starting test" | tests_total;63 // printf( "DEBUG: starting test %d\n", tests_total ); 64 64 bool passed = true; 65 65 T1 * ip = (T1 *) ip_; 66 66 for ( i; start ~ end ) passed = passed && (ip[i].data == fill.data ); 67 67 if ( ! passed ) { 68 sout | "fill4 failed test" | tests_total | "fill T1";68 printf( "failed test %3d: fill T1\n", tests_total ); 69 69 tests_failed += 1; 70 70 } // if 71 // sout | "DEBUG: done test" | tests_total;71 // printf( "DEBUG: done test %d\n", tests_total ); 72 72 } 73 73 74 74 void test_fill( void * ip_, size_t start, size_t end, T1 * fill ) { 75 75 tests_total += 1; 76 // sout | "DEBUG: starting test" | tests_total;76 // printf( "DEBUG: starting test %d\n", tests_total ); 77 77 bool passed = memcmp( (void*)((uintptr_t )ip_ + start ), (void*)fill, end ) == 0; 78 78 if ( ! passed ) { 79 sout | "fill5 failed test" | tests_total | "fill T1 A";79 printf( "failed test %3d: fill T1 A\n", tests_total ); 80 80 tests_failed += 1; 81 81 } // if 82 // sout | "DEBUG: done test" | tests_total;82 // printf( "DEBUG: done test %d\n", tests_total ); 83 83 } 84 84 85 85 void test_use( int * ip, size_t dim ) { 86 86 tests_total += 1; 87 // sout | "DEBUG: starting test" | tests_total;87 // printf( "DEBUG: starting test %d\n", tests_total ); 88 88 bool passed = true; 89 89 for ( i; 0 ~ dim ) ip[i] = 0xdeadbeef; 90 90 for ( i; 0 ~ dim ) passed = passed && (ip[i] == 0xdeadbeef); 91 91 if ( ! passed ) { 92 sout | "use1 failed test" | tests_total | "use int";92 printf( "failed test %3d: use int\n", tests_total ); 93 93 tests_failed += 1; 94 94 } // if 95 // sout | "DEBUG: done test" | tests_total;95 // printf( "DEBUG: done test %d\n", tests_total ); 96 96 } 97 97 98 98 void test_use( T1 * ip, size_t dim ) { 99 99 tests_total += 1; 100 // sout | "DEBUG: starting test" | tests_total;100 // printf( "DEBUG: starting test %d\n", tests_total ); 101 101 bool passed = true; 102 102 for ( i; 0 ~ dim ) ip[i].data = 0xdeadbeef; 103 103 for ( i; 0 ~ dim ) passed = passed && (ip[i].data == 0xdeadbeef); 104 104 if ( ! passed ) { 105 sout | "use2 failed test" | tests_total | "use T1";105 printf( "failed test %3d: use T1\n", tests_total ); 106 106 tests_failed += 1; 107 107 } // if 108 // sout | "DEBUG: done test" | tests_total;108 // printf( "DEBUG: done test %d\n", tests_total ); 109 109 } 110 110 … … 117 117 char FillC = 'a'; 118 118 int * FillA = calloc( dim / 4 ); 119 120 119 T1 FillT1 = { FillT }; 121 120 T1 * FillT1A = (T1 *)(void *) malloc( (dim / 4) * sizeof(T1) ); … … 130 129 // testing alloc 131 130 131 last_failed = -1; 132 132 tests_total = 0; 133 133 tests_failed = 0; … … 153 153 free( ip ); 154 154 155 ip = alloc( 0p`resize );155 ip = alloc( ((double *)0p)`resize ); 156 156 test_base( ip, elemSize, libAlign ); 157 157 test_use( ip, elemSize / elemSize ); … … 495 495 free( ip ); 496 496 497 if ( tests_failed == 0 ) sout | "PASSED alloc tests" | nl | nl;498 else sout | "failed alloc tests :" | tests_failed | tests_total | nl | nl;499 500 // testing alloc ( aligned struct)497 if ( tests_failed == 0 ) printf( "PASSED alloc tests\n\n" ); 498 else printf( "failed alloc tests : %d/%d\n\n", tests_failed, tests_total ); 499 500 // testing alloc ( aligned struct ) 501 501 502 502 elemSize = sizeof(T1); 503 503 size = dim * elemSize; 504 last_failed = -1; 504 505 tests_total = 0; 505 506 tests_failed = 0; … … 867 868 free( t1p ); 868 869 869 if ( tests_failed == 0) sout | "PASSED alloc tests (aligned struct)" | nl | nl;870 else sout | "failed alloc tests ( aligned struct ) :" | tests_failed | tests_total | nl;871 872 sout | "(if applicable) alignment error below indicates memory trashing caused by test_use." | nl | nl;870 if ( tests_failed == 0) printf( "PASSED alloc tests (aligned struct)\n\n"); 871 else printf( "failed alloc tests ( aligned struct ) : %d/%d\n\n", tests_failed, tests_total ); 872 873 printf( "(if applicable) alignment error below indicates memory trashing caused by test_use.\n\n"); 873 874 free( FillA ); 874 875 free( FillT1A ); -
tests/malloc.cfa
r4f102fa ra55472cc 1 #include < fstream.hfa> // sout1 #include <assert.h> 2 2 #include <malloc.h> // malloc_usable_size 3 3 #include <stdint.h> // uintptr_t 4 #include <stdlib.h> // posix_memalign 5 #include <fstream.hfa> 4 6 #include <stdlib.hfa> // access C malloc, realloc 5 7 #include <unistd.h> // getpagesize … … 8 10 int tests_failed; 9 11 size_t tAlign = 32; 10 struct S1 { int d ata; } __attribute__((aligned(32)));12 struct S1 { int d1; } __attribute__((aligned(32))); 11 13 typedef struct S1 T1; 12 14 13 void test_base( void * ip, size_t size, size_t align ) {15 void test_base( void * ip, size_t size, size_t align) { 14 16 tests_total += 1; 15 bool passed = (malloc_size( ip ) == size) && (malloc_usable_size( ip ) >= size) && (malloc_alignment( ip) == align) && ((uintptr_t)ip % align == 0);16 if ( ! passed) {17 sout | "base failed test" | tests_total | "ip" | ip | "size" | size | "align" | align | "but got size" | malloc_size( ip ) | "usable" | malloc_usable_size( ip ) | "align" | malloc_alignment( ip);17 bool passed = (malloc_size(ip) == size) && (malloc_usable_size(ip) >= size) && (malloc_alignment(ip) == align) && ((uintptr_t)ip % align == 0); 18 if (!passed) { 19 printf("failed test %2d: %4lu %4lu but got %4lu ( %3lu ) %4lu\n", tests_total, size, align, malloc_size(ip), malloc_usable_size(ip), malloc_alignment(ip)); 18 20 tests_failed += 1; 19 } // if21 } 20 22 } 21 23 22 void test_fill( void * ip_, size_t start, size_t end, char fill ) {24 void test_fill( void * ip_, size_t start, size_t end, char fill) { 23 25 tests_total += 1; 24 26 bool passed = true; 25 27 char * ip = (char *) ip_; 26 for ( i; start ~ end) passed = passed && (ip[i] == fill);27 if ( ! passed) {28 sout | "fill1 failed test" | tests_total | "fill C";28 for (i; start ~ end) passed = passed && (ip[i] == fill); 29 if (!passed) { 30 printf("failed test %2d: fill\n", tests_total); 29 31 tests_failed += 1; 30 } // if32 } 31 33 } 32 34 33 void test_use( void * ip_ ) {35 void test_use( void * ip_) { 34 36 tests_total += 1; 35 37 bool passed = true; 36 38 int * ip = (int *) ip_; 37 size_t size = malloc_size( ip);38 for ( i; 0 ~ size ~ sizeof(int)) ip[i/sizeof(int)] = 0xdeadbeef;39 for ( i; 0 ~ size ~ sizeof(int)) passed = passed && (ip[i /sizeof(int)] == 0xdeadbeef);40 size_t usize = malloc_usable_size( ip);41 for ( i; size ~ usize ~ sizeof(int)) ip[i /sizeof(int)] = -1;42 for ( i; size ~ usize ~ sizeof(int)) passed = passed && (ip[i /sizeof(int)] == -1);43 if ( ! passed) {44 sout | "failed test" | tests_total | "use";39 size_t size = malloc_size(ip); 40 for (i; 0 ~ size ~ sizeof(int)) ip[i/sizeof(int)] = 0xdeadbeef; 41 for (i; 0 ~ size ~ sizeof(int)) passed = passed && (ip[i/sizeof(int)] == 0xdeadbeef); 42 size_t usize = malloc_usable_size(ip); 43 for (i; size ~ usize ~ sizeof(int)) ip[i/sizeof(int)] = -1; 44 for (i; size ~ usize ~ sizeof(int)) passed = passed && (ip[i/sizeof(int)] == -1); 45 if (!passed) { 46 printf("failed test %2d: use\n", tests_total); 45 47 tests_failed += 1; 46 48 } … … 48 50 49 51 int main( void ) { 50 enum { dim = 8, align = 64, libAlign = libAlign() };51 52 size_t elemSize = sizeof(int); 53 size_t dim = 8; 52 54 size_t size = dim * elemSize; 55 size_t align = 64; 56 const size_t libAlign = libAlign(); 53 57 char fill = '\xde'; 54 58 int * ip; 55 59 T1 * tp; 56 60 57 // testing C malloc61 // testing C malloc 58 62 59 63 tests_total = 0; 60 64 tests_failed = 0; 61 65 62 ip = (int *) malloc( size );63 test_base( ip, size, libAlign);64 test_use( ip);65 free( ip);66 67 ip = (int *) malloc( 0 );68 test_base( ip, 0, libAlign);69 test_use( ip);70 free( ip);71 72 ip = (int *) aalloc( dim, elemSize );73 test_base( ip, size, libAlign);74 test_use( ip);75 free( ip);76 77 ip = (int *) aalloc( 0, elemSize );78 test_base( ip, 0, libAlign);79 test_use( ip);80 free( ip);81 82 ip = (int *) aalloc( dim, 0 );83 test_base( ip, 0, libAlign);84 test_use( ip);85 free( ip);86 87 ip = (int *) aalloc( 0, 0 );88 test_base( ip, 0, libAlign);89 test_use( ip);90 free( ip);91 92 ip = (int *) calloc( dim, elemSize );93 test_base( ip, size, libAlign);94 test_fill( ip, 0, size, '\0');95 test_use( ip);96 free( ip);97 98 ip = (int *) calloc( 0, elemSize );99 test_base( ip, 0, libAlign);100 test_fill( ip, 0, 0, '\0');101 test_use( ip);102 free( ip);103 104 ip = (int *) calloc( dim, 0 );105 test_base( ip, 0, libAlign);106 test_fill( ip, 0, 0, '\0');107 test_use( ip);108 free( ip);109 110 ip = (int *) malloc( size );111 ip = (int *) resize(ip, size / 4 );112 test_base( ip, size / 4, libAlign);113 test_use( ip);114 free( ip);115 116 ip = (int *) malloc( size );117 ip = (int *) resize(ip, size * 4 );118 test_base( ip, size * 4, libAlign);119 test_use( ip);120 free( ip);121 122 ip = (int *) malloc( size );123 ip = (int *) resize(ip, 0 );124 test_base( ip, 0, libAlign);125 test_use( ip);126 free( ip);127 128 ip = (int *) resize( NULL, size );129 test_base( ip, size, libAlign);130 test_use( ip);131 free( ip);132 133 ip = (int *) resize( 0p, size );134 test_base( ip, size, libAlign);135 test_use( ip);136 free( ip);137 138 ip = (int *) calloc( dim, elemSize );139 ip = (int *) realloc(ip, size / 4 );140 test_base( ip, size / 4, libAlign);141 test_fill( ip, 0, size / 4, '\0');142 test_use( ip);143 free( ip);144 145 ip = (int *) calloc( dim, elemSize );146 ip = (int *) realloc(ip, size * 4 );147 test_base( ip, size * 4, libAlign);148 test_fill( ip, 0, size * 4, '\0');149 test_use( ip);150 free( ip);151 152 ip = (int *) calloc( dim, elemSize );153 ip = (int *) realloc(ip, 0 );154 test_base( ip, 0, libAlign);155 test_use( ip);156 free( ip);157 158 ip = (int *) realloc( NULL, size );159 test_base( ip, size , libAlign);160 test_use( ip);161 free( ip);162 163 ip = (int *) realloc( 0p, size );164 test_base( ip, size, libAlign);165 test_use( ip);166 free( ip);167 168 ip = (int *) memalign( align, size );169 test_base( ip, size, align);170 test_use( ip);171 free( ip);172 173 ip = (int *) memalign( align, 0 );174 test_base( ip, 0, libAlign);175 test_use( ip);176 free( ip);177 178 ip = (int *) amemalign( align, dim, elemSize );179 test_base( ip, size, align);180 test_use( ip);181 free( ip);182 183 ip = (int *) amemalign( align, 0, elemSize );184 test_base( ip, 0, libAlign);185 test_use( ip);186 free( ip);187 188 ip = (int *) amemalign( align, dim, 0 );189 test_base( ip, 0, libAlign);190 test_use( ip);191 free( ip);192 193 ip = (int *) cmemalign( align, dim, elemSize );194 test_base( ip, size, align);195 test_fill( ip, 0, size, '\0');196 test_use( ip);197 free( ip);198 199 ip = (int *) cmemalign( align, 0, elemSize );200 test_base( ip, 0, libAlign);201 test_use( ip);202 free( ip);203 204 ip = (int *) cmemalign( align, dim, 0 );205 test_base( ip, 0, libAlign);206 test_use( ip);207 free( ip);208 209 ip = (int *) aligned_alloc( align, size );210 test_base( ip, size, align);211 test_use( ip);212 free( ip);213 214 ip = (int *) aligned_alloc( align, 0 );215 test_base( ip, 0, libAlign);216 test_use( ip);217 free( ip);218 219 posix_memalign( (void **) &ip, align, size );220 test_base( ip, size, align);221 test_use( ip);222 free( ip);223 224 posix_memalign( (void **) &ip, align, 0 );225 test_base( ip, 0, libAlign);226 test_use( ip);227 free( ip);228 229 ip = (int *) valloc( size );230 test_base( ip, size, getpagesize());231 test_use( ip);232 free( ip);233 234 ip = (int *) valloc( 0 );235 test_base( ip, 0, libAlign);236 test_use( ip);237 free( ip);238 239 ip = (int *) pvalloc( getpagesize() * 3 / 2 );240 test_base( ip, getpagesize() * 2, getpagesize());241 test_use( ip);242 free( ip);243 244 ip = (int *) pvalloc( 0 );245 test_base( ip, 0, libAlign);246 test_use( ip);247 free( ip);248 249 ip = (int *) malloc( size );250 ip = (int *) resize(ip, libAlign, size / 2 );251 test_base( ip, size / 2, libAlign);252 test_use( ip);253 free( ip);254 255 ip = (int *) aligned_alloc( align, size );256 ip = (int *) resize(ip, align, size / 2 );257 test_base( ip, size / 2, align);258 test_use( ip);259 free( ip);260 261 ip = (int *) malloc( size );262 ip = (int *) resize(ip, align, size / 4 );263 test_base( ip, size / 4, align);264 test_use( ip);265 free( ip);266 267 ip = (int *) malloc( size );268 ip = (int *) resize(ip, align, 0 );269 test_base( ip, 0, libAlign);270 test_use( ip);271 free( ip);272 273 ip = (int *) resize( NULL, align, size );274 test_base( ip, size, align);275 test_use( ip);276 free( ip);277 278 ip = (int *) resize( 0p, align, size );279 test_base( ip, size, align);280 test_use( ip);281 free( ip);282 283 ip = (int *) calloc( dim, elemSize );284 ip = (int *) realloc(ip, libAlign, size / 2 );285 test_base( ip, size / 2, libAlign);286 test_fill( ip, 0, size / 2, '\0');287 test_use( ip);288 free( ip);289 290 ip = (int *) cmemalign( align, dim, elemSize );291 ip = (int *) realloc(ip, align, size / 2 );292 test_base( ip, size / 2, align);293 test_fill( ip, 0, size / 2, '\0');294 test_use( ip);295 free( ip);296 297 ip = (int *) calloc( dim, elemSize );298 ip = (int *) realloc(ip, align, size / 4 );299 test_base( ip, size / 4, align);300 test_fill( ip, 0, size / 4, '\0');301 test_use( ip);302 free( ip);303 304 ip = (int *) calloc( dim, elemSize );305 ip = (int *) realloc( ip, libAlign, size * 4 );306 test_base( ip, size * 4, libAlign);307 test_fill( ip, 0, size * 4, '\0');308 test_use( ip);309 free( ip);310 311 ip = (int *) calloc( dim, elemSize );312 ip = (int *) realloc(ip, align, 0 );313 test_base( ip, 0, libAlign);314 test_use( ip);315 free( ip);316 317 free( 0p ); // sanity check318 free( NULL ); // sanity check319 320 if (tests_failed == 0) sout | "PASSED C malloc tests" | nl | nl;321 else sout | "failed C malloc tests" | tests_failed | tests_total | nl | nl;66 ip = (int *) (void *) malloc( size ); 67 test_base(ip, size, libAlign); 68 test_use(ip); 69 free(ip); 70 71 ip = (int *) (void *) malloc( 0 ); 72 test_base(ip, 0, libAlign); 73 test_use(ip); 74 free(ip); 75 76 ip = (int *) (void *) aalloc( dim, elemSize ); 77 test_base(ip, size, libAlign); 78 test_use(ip); 79 free(ip); 80 81 ip = (int *) (void *) aalloc( 0, elemSize ); 82 test_base(ip, 0, libAlign); 83 test_use(ip); 84 free(ip); 85 86 ip = (int *) (void *) aalloc( dim, 0 ); 87 test_base(ip, 0, libAlign); 88 test_use(ip); 89 free(ip); 90 91 ip = (int *) (void *) aalloc( 0, 0 ); 92 test_base(ip, 0, libAlign); 93 test_use(ip); 94 free(ip); 95 96 ip = (int *) (void *) calloc( dim, elemSize ); 97 test_base(ip, size, libAlign); 98 test_fill(ip, 0, size, '\0'); 99 test_use(ip); 100 free(ip); 101 102 ip = (int *) (void *) calloc( 0, elemSize ); 103 test_base(ip, 0, libAlign); 104 test_fill(ip, 0, 0, '\0'); 105 test_use(ip); 106 free(ip); 107 108 ip = (int *) (void *) calloc( dim, 0 ); 109 test_base(ip, 0, libAlign); 110 test_fill(ip, 0, 0, '\0'); 111 test_use(ip); 112 free(ip); 113 114 ip = (int *) (void *) malloc( size ); 115 ip = (int *) (void *) resize( (void *) ip, size / 4 ); 116 test_base(ip, size / 4, libAlign); 117 test_use(ip); 118 free(ip); 119 120 ip = (int *) (void *) malloc( size ); 121 ip = (int *) (void *) resize( (void *) ip, size * 4 ); 122 test_base(ip, size * 4, libAlign); 123 test_use(ip); 124 free(ip); 125 126 ip = (int *) (void *) malloc( size ); 127 ip = (int *) (void *) resize( (void *) ip, 0 ); 128 test_base(ip, 0, libAlign); 129 test_use(ip); 130 free(ip); 131 132 ip = (int *) (void *) resize( NULL, size ); 133 test_base(ip, size, libAlign); 134 test_use(ip); 135 free(ip); 136 137 ip = (int *) (void *) resize( 0p, size ); 138 test_base(ip, size, libAlign); 139 test_use(ip); 140 free(ip); 141 142 ip = (int *) (void *) calloc( dim, elemSize ); 143 ip = (int *) (void *) realloc( (void *) ip, size / 4 ); 144 test_base(ip, size / 4, libAlign); 145 test_fill(ip, 0, size / 4, '\0'); 146 test_use(ip); 147 free(ip); 148 149 ip = (int *) (void *) calloc( dim, elemSize ); 150 ip = (int *) (void *) realloc( (void *) ip, size * 4 ); 151 test_base(ip, size * 4, libAlign); 152 test_fill(ip, 0, size * 4, '\0'); 153 test_use(ip); 154 free(ip); 155 156 ip = (int *) (void *) calloc( dim, elemSize ); 157 ip = (int *) (void *) realloc( (void *) ip, 0 ); 158 test_base(ip, 0, libAlign); 159 test_use(ip); 160 free(ip); 161 162 ip = (int *) (void *) realloc( NULL, size ); 163 test_base(ip, size , libAlign); 164 test_use(ip); 165 free(ip); 166 167 ip = (int *) (void *) realloc( 0p, size ); 168 test_base(ip, size, libAlign); 169 test_use(ip); 170 free(ip); 171 172 ip = (int *) (void *) memalign( align, size ); 173 test_base(ip, size, align); 174 test_use(ip); 175 free(ip); 176 177 ip = (int *) (void *) memalign( align, 0 ); 178 test_base(ip, 0, libAlign); 179 test_use(ip); 180 free(ip); 181 182 ip = (int *) (void *) amemalign( align, dim, elemSize ); 183 test_base(ip, size, align); 184 test_use(ip); 185 free(ip); 186 187 ip = (int *) (void *) amemalign( align, 0, elemSize ); 188 test_base(ip, 0, libAlign); 189 test_use(ip); 190 free(ip); 191 192 ip = (int *) (void *) amemalign( align, dim, 0 ); 193 test_base(ip, 0, libAlign); 194 test_use(ip); 195 free(ip); 196 197 ip = (int *) (void *) cmemalign( align, dim, elemSize ); 198 test_base(ip, size, align); 199 test_fill(ip, 0, size, '\0'); 200 test_use(ip); 201 free(ip); 202 203 ip = (int *) (void *) cmemalign( align, 0, elemSize ); 204 test_base(ip, 0, libAlign); 205 test_use(ip); 206 free(ip); 207 208 ip = (int *) (void *) cmemalign( align, dim, 0 ); 209 test_base(ip, 0, libAlign); 210 test_use(ip); 211 free(ip); 212 213 ip = (int *) (void *) aligned_alloc( align, size ); 214 test_base(ip, size, align); 215 test_use(ip); 216 free(ip); 217 218 ip = (int *) (void *) aligned_alloc( align, 0 ); 219 test_base(ip, 0, libAlign); 220 test_use(ip); 221 free(ip); 222 223 (int) posix_memalign( (void **) &ip, align, size ); 224 test_base(ip, size, align); 225 test_use(ip); 226 free(ip); 227 228 (int) posix_memalign( (void **) &ip, align, 0 ); 229 test_base(ip, 0, libAlign); 230 test_use(ip); 231 free(ip); 232 233 ip = (int *) (void *) valloc( size ); 234 test_base(ip, size, getpagesize()); 235 test_use(ip); 236 free(ip); 237 238 ip = (int *) (void *) valloc( 0 ); 239 test_base(ip, 0, libAlign); 240 test_use(ip); 241 free(ip); 242 243 ip = (int *) (void *) pvalloc( getpagesize() * 3 / 2 ); 244 test_base(ip, getpagesize() * 2, getpagesize()); 245 test_use(ip); 246 free(ip); 247 248 ip = (int *) (void *) pvalloc( 0 ); 249 test_base(ip, 0, libAlign); 250 test_use(ip); 251 free(ip); 252 253 ip = (int *) (void *) malloc( size ); 254 ip = (int *) (void *) resize( (void *) ip, libAlign, size / 2 ); 255 test_base(ip, size / 2, libAlign); 256 test_use(ip); 257 free(ip); 258 259 ip = (int *) (void *) aligned_alloc( align, size ); 260 ip = (int *) (void *) resize( (void *) ip, align, size / 2 ); 261 test_base(ip, size / 2, align); 262 test_use(ip); 263 free(ip); 264 265 ip = (int *) (void *) malloc( size ); 266 ip = (int *) (void *) resize( (void *) ip, align, size / 4 ); 267 test_base(ip, size / 4, align); 268 test_use(ip); 269 free(ip); 270 271 ip = (int *) (void *) malloc( size ); 272 ip = (int *) (void *) resize( (void *) ip, align, 0 ); 273 test_base(ip, 0, libAlign); 274 test_use(ip); 275 free(ip); 276 277 ip = (int *) (void *) resize( NULL, align, size ); 278 test_base(ip, size, align); 279 test_use(ip); 280 free(ip); 281 282 ip = (int *) (void *) resize( 0p, align, size ); 283 test_base(ip, size, align); 284 test_use(ip); 285 free(ip); 286 287 ip = (int *) (void *) calloc( dim, elemSize ); 288 ip = (int *) (void *) realloc( (void *) ip, libAlign, size / 2 ); 289 test_base(ip, size / 2, libAlign); 290 test_fill(ip, 0, size / 2, '\0'); 291 test_use(ip); 292 free(ip); 293 294 ip = (int *) (void *) cmemalign( align, dim, elemSize ); 295 ip = (int *) (void *) realloc( (void *) ip, align, size / 2 ); 296 test_base(ip, size / 2, align); 297 test_fill(ip, 0, size / 2, '\0'); 298 test_use(ip); 299 free(ip); 300 301 ip = (int *) (void *) calloc( dim, elemSize ); 302 ip = (int *) (void *) realloc( (void *) ip, align, size / 4 ); 303 test_base(ip, size / 4, align); 304 test_fill(ip, 0, size / 4, '\0'); 305 test_use(ip); 306 free(ip); 307 308 ip = (int *) (void *) calloc( dim, elemSize ); 309 ip = (int *) (void *) realloc( (void *) ip, 0, size * 4 ); 310 test_base(ip, size * 4, libAlign); 311 test_fill(ip, 0, size * 4, '\0'); 312 test_use(ip); 313 free(ip); 314 315 ip = (int *) (void *) calloc( dim, elemSize ); 316 ip = (int *) (void *) realloc( (void *) ip, align, 0 ); 317 test_base(ip, 0, libAlign); 318 test_use(ip); 319 free(ip); 320 321 free( 0p ); // sanity check 322 free( NULL ); // sanity check 323 324 if (tests_failed == 0) printf("PASSED C malloc tests\n\n"); 325 else printf("failed C malloc tests : %d/%d\n\n", tests_failed, tests_total); 322 326 323 327 // testing CFA malloc … … 327 331 328 332 ip = malloc(); 329 test_base( ip, elemSize, libAlign);330 test_use( ip);331 free( ip);333 test_base(ip, elemSize, libAlign); 334 test_use(ip); 335 free(ip); 332 336 333 337 ip = aalloc( dim ); 334 test_base( ip, size, libAlign);335 test_use( ip);336 free( ip);338 test_base(ip, size, libAlign); 339 test_use(ip); 340 free(ip); 337 341 338 342 ip = aalloc( 0 ); 339 test_base( ip, 0, libAlign);340 test_use( ip);341 free( ip);343 test_base(ip, 0, libAlign); 344 test_use(ip); 345 free(ip); 342 346 343 347 ip = calloc( dim ); 344 test_base( ip, size, libAlign);345 test_fill( ip, 0, size, '\0');346 test_use( ip);347 free( ip);348 test_base(ip, size, libAlign); 349 test_fill(ip, 0, size, '\0'); 350 test_use(ip); 351 free(ip); 348 352 349 353 ip = calloc( 0 ); 350 test_base( ip, 0, libAlign);351 test_use( ip);352 free( ip);354 test_base(ip, 0, libAlign); 355 test_use(ip); 356 free(ip); 353 357 354 358 ip = aalloc( dim ); 355 359 ip = resize( ip, size / 4 ); 356 test_base( ip, size / 4, libAlign);357 test_use( ip);358 free( ip);360 test_base(ip, size / 4, libAlign); 361 test_use(ip); 362 free(ip); 359 363 360 364 ip = aalloc( dim ); 361 365 ip = resize( ip, size * 4 ); 362 test_base( ip, size * 4, libAlign);363 test_use( ip);364 free( ip);366 test_base(ip, size * 4, libAlign); 367 test_use(ip); 368 free(ip); 365 369 366 370 ip = aalloc( dim ); 367 371 ip = resize( ip, 0 ); 368 test_base( ip, 0, libAlign);369 test_use( ip);370 free( ip);371 372 ip = resize( 0p, size );373 test_base( ip, size, libAlign);374 test_use( ip);375 free( ip);376 377 ip = resize( 0p, size );378 test_base( ip, size, libAlign);379 test_use( ip);380 free( ip);372 test_base(ip, 0, libAlign); 373 test_use(ip); 374 free(ip); 375 376 ip = resize( (int*)0p, size ); 377 test_base(ip, size, libAlign); 378 test_use(ip); 379 free(ip); 380 381 ip = resize( (int*)0p, size ); 382 test_base(ip, size, libAlign); 383 test_use(ip); 384 free(ip); 381 385 382 386 ip = calloc( dim ); 383 387 ip = realloc( ip, size / 4 ); 384 test_base( ip, size / 4, libAlign);385 test_fill( ip, 0, size / 4, '\0');386 test_use( ip);387 free( ip);388 test_base(ip, size / 4, libAlign); 389 test_fill(ip, 0, size / 4, '\0'); 390 test_use(ip); 391 free(ip); 388 392 389 393 ip = calloc( dim ); 390 394 ip = realloc( ip, size * 4 ); 391 test_base( ip, size * 4, libAlign);392 test_fill( ip, 0, size, '\0');393 test_use( ip);394 free( ip);395 test_base(ip, size * 4, libAlign); 396 test_fill(ip, 0, size, '\0'); 397 test_use(ip); 398 free(ip); 395 399 396 400 ip = calloc( dim ); 397 401 ip = realloc( ip, 0 ); 398 test_base( ip, 0, libAlign);399 test_use( ip);400 free( ip);401 402 ip = realloc( 0p, size );403 test_base( ip, size , libAlign);404 test_use( ip);405 free( ip);406 407 ip = realloc( 0p, size );408 test_base( ip, size, libAlign);409 test_use( ip);410 free( ip);402 test_base(ip, 0, libAlign); 403 test_use(ip); 404 free(ip); 405 406 ip = realloc( (int*)0p, size ); 407 test_base(ip, size , libAlign); 408 test_use(ip); 409 free(ip); 410 411 ip = realloc( (int*)0p, size ); 412 test_base(ip, size, libAlign); 413 test_use(ip); 414 free(ip); 411 415 412 416 ip = memalign( align ); 413 test_base( ip, elemSize, align);414 test_use( ip);415 free( ip);417 test_base(ip, elemSize, align); 418 test_use(ip); 419 free(ip); 416 420 417 421 ip = amemalign( align, dim ); 418 test_base( ip, size, align);419 test_use( ip);420 free( ip);422 test_base(ip, size, align); 423 test_use(ip); 424 free(ip); 421 425 422 426 ip = amemalign( align, 0 ); 423 test_base( ip, 0, libAlign);424 test_use( ip);425 free( ip);427 test_base(ip, 0, libAlign); 428 test_use(ip); 429 free(ip); 426 430 427 431 ip = cmemalign( align, dim ); 428 test_base( ip, size, align);429 test_fill( ip, 0, size, '\0');430 test_use( ip);431 free( ip);432 test_base(ip, size, align); 433 test_fill(ip, 0, size, '\0'); 434 test_use(ip); 435 free(ip); 432 436 433 437 ip = cmemalign( align, 0 ); 434 test_base( ip, 0, libAlign);435 test_use( ip);436 free( ip);438 test_base(ip, 0, libAlign); 439 test_use(ip); 440 free(ip); 437 441 438 442 ip = aligned_alloc( align ); 439 test_base( ip, elemSize, align);440 test_use( ip);441 free( ip);442 443 posix_memalign( (int **) &ip, align );444 test_base( ip, elemSize, align);445 test_use( ip);446 free( ip);443 test_base(ip, elemSize, align); 444 test_use(ip); 445 free(ip); 446 447 (int) posix_memalign( (int **) &ip, align ); 448 test_base(ip, elemSize, align); 449 test_use(ip); 450 free(ip); 447 451 448 452 ip = valloc(); 449 test_base( ip, elemSize, getpagesize());450 test_use( ip);451 free( ip);453 test_base(ip, elemSize, getpagesize()); 454 test_use(ip); 455 free(ip); 452 456 453 457 ip = pvalloc(); 454 test_base( ip, getpagesize(), getpagesize());455 test_use( ip);456 free( ip);457 458 if (tests_failed == 0) sout | "PASSED CFA malloc tests" | nl | nl;459 else sout | "failed CFA malloc tests" | tests_failed | tests_total | nl | nl;458 test_base(ip, getpagesize(), getpagesize()); 459 test_use(ip); 460 free(ip); 461 462 if (tests_failed == 0) printf("PASSED CFA malloc tests\n\n"); 463 else printf("failed CFA malloc tests : %d/%d\n\n", tests_failed, tests_total); 460 464 461 465 // testing CFA malloc with aligned struct … … 467 471 468 472 tp = malloc(); 469 test_base( tp, elemSize, tAlign);470 test_use( tp);471 free( tp);473 test_base(tp, elemSize, tAlign ); 474 test_use(tp); 475 free(tp); 472 476 473 477 tp = aalloc( dim ); 474 test_base( tp, size, tAlign);475 test_use( tp);476 free( tp);478 test_base(tp, size, tAlign ); 479 test_use(tp); 480 free(tp); 477 481 478 482 tp = aalloc( 0 ); 479 test_base( tp, 0, libAlign);480 test_use( tp);481 free( tp);483 test_base(tp, 0, libAlign); 484 test_use(tp); 485 free(tp); 482 486 483 487 tp = calloc( dim ); 484 test_base( tp, size, tAlign);485 test_fill( tp, 0, size, '\0');486 test_use( tp);487 free( tp);488 test_base(tp, size, tAlign ); 489 test_fill(tp, 0, size, '\0'); 490 test_use(tp); 491 free(tp); 488 492 489 493 tp = calloc( 0 ); 490 test_base( tp, 0, libAlign);491 test_use( tp);492 free( tp);494 test_base(tp, 0, libAlign); 495 test_use(tp); 496 free(tp); 493 497 494 498 tp = aalloc( dim ); 495 499 tp = resize( tp, size / 4 ); 496 test_base( tp, size / 4, tAlign);497 test_use( tp);498 free( tp);500 test_base(tp, size / 4, tAlign ); 501 test_use(tp); 502 free(tp); 499 503 500 504 tp = malloc(); 501 505 tp = resize( tp, size * 4 ); 502 test_base( tp, size * 4, tAlign);503 test_use( tp);504 free( tp);506 test_base(tp, size * 4, tAlign ); 507 test_use(tp); 508 free(tp); 505 509 506 510 tp = aalloc( dim ); 507 511 tp = resize( tp, 0 ); 508 test_base( tp, 0, libAlign);509 test_use( tp);510 free( tp);512 test_base(tp, 0, libAlign); 513 test_use(tp); 514 free(tp); 511 515 512 516 tp = resize( (T1*)0p, size ); 513 test_base( tp, size, tAlign);514 test_use( tp);515 free( tp);517 test_base(tp, size, tAlign ); 518 test_use(tp); 519 free(tp); 516 520 517 521 tp = resize( (T1*)0p, size ); 518 test_base( tp, size, tAlign);519 test_use( tp);520 free( tp);522 test_base(tp, size, tAlign ); 523 test_use(tp); 524 free(tp); 521 525 522 526 tp = calloc( dim ); 523 527 tp = realloc( tp, size / 4 ); 524 test_base( tp, size / 4, tAlign);525 test_fill( tp, 0, size / 4, '\0');526 test_use( tp);527 free( tp);528 test_base(tp, size / 4, tAlign ); 529 test_fill(tp, 0, size / 4, '\0'); 530 test_use(tp); 531 free(tp); 528 532 529 533 tp = calloc( dim ); 530 534 tp = realloc( tp, size * 4 ); 531 test_base( tp, size * 4, tAlign);532 test_fill( tp, 0, size, '\0');533 test_use( tp);534 free( tp);535 test_base(tp, size * 4, tAlign ); 536 test_fill(tp, 0, size, '\0'); 537 test_use(tp); 538 free(tp); 535 539 536 540 tp = calloc( dim ); 537 541 tp = realloc( tp, 0 ); 538 test_base( tp, 0, libAlign);539 test_use( tp);540 free( tp);542 test_base(tp, 0, libAlign); 543 test_use(tp); 544 free(tp); 541 545 542 546 tp = realloc( (T1*)0p, size ); 543 test_base( tp, size , tAlign);544 test_use( tp);545 free( tp);547 test_base(tp, size , tAlign ); 548 test_use(tp); 549 free(tp); 546 550 547 551 tp = realloc( (T1*)0p, size ); 548 test_base( tp, size, tAlign);549 test_use( tp);550 free( tp);552 test_base(tp, size, tAlign ); 553 test_use(tp); 554 free(tp); 551 555 552 556 tp = memalign( align ); 553 test_base( tp, elemSize, align);554 test_use( tp);555 free( tp);557 test_base(tp, elemSize, align); 558 test_use(tp); 559 free(tp); 556 560 557 561 tp = amemalign( align, dim ); 558 test_base( tp, size, align);559 test_use( tp);560 free( tp);562 test_base(tp, size, align); 563 test_use(tp); 564 free(tp); 561 565 562 566 tp = amemalign( align, 0 ); 563 test_base( tp, 0, libAlign);564 test_use( tp);565 free( tp);567 test_base(tp, 0, libAlign); 568 test_use(tp); 569 free(tp); 566 570 567 571 tp = cmemalign( align, dim ); 568 test_base( tp, size, align);569 test_fill( tp, 0, size, '\0');570 test_use( tp);571 free( tp);572 test_base(tp, size, align); 573 test_fill(tp, 0, size, '\0'); 574 test_use(tp); 575 free(tp); 572 576 573 577 tp = cmemalign( align, 0 ); 574 test_base( tp, 0, libAlign);575 test_use( tp);576 free( tp);578 test_base(tp, 0, libAlign); 579 test_use(tp); 580 free(tp); 577 581 578 582 tp = aligned_alloc( align ); 579 test_base( tp, elemSize, align);580 test_use( tp);581 free( tp);582 583 posix_memalign( (T1 **)&tp, align );584 test_base( tp, elemSize, align);585 test_use( tp);586 free( tp);583 test_base(tp, elemSize, align); 584 test_use(tp); 585 free(tp); 586 587 (int) posix_memalign( (T1 **) &tp, align ); 588 test_base(tp, elemSize, align); 589 test_use(tp); 590 free(tp); 587 591 588 592 tp = valloc(); 589 test_base( tp, elemSize, getpagesize());590 test_use( tp);591 free( tp);593 test_base(tp, elemSize, getpagesize()); 594 test_use(tp); 595 free(tp); 592 596 593 597 tp = pvalloc(); 594 test_base( tp, getpagesize(), getpagesize() ); 595 test_use( tp ); 596 free( tp ); 597 598 if ( tests_failed == 0 ) sout | "PASSED CFA malloc tests (aligned struct)" | nl | nl; 599 else sout | "failed CFA malloc tests (aligned struct)" | tests_failed | tests_total | nl | nl; 598 test_base(tp, getpagesize(), getpagesize()); 599 test_use(tp); 600 free(tp); 601 602 if (tests_failed == 0) printf("PASSED CFA malloc tests (aligned struct)\n\n"); 603 else printf("failed CFA malloc tests (aligned struct) : %d/%d\n\n", tests_failed, tests_total); 604 605 return 0; 600 606 } 601 607
Note:
See TracChangeset
for help on using the changeset viewer.