memory.c revision e1c94d9d25db6b0dd7a5028ffee31d1057855d73
1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 6% M M EEEEE M M OOO RRRR Y Y % 7% MM MM E MM MM O O R R Y Y % 8% M M M EEE M M M O O RRRR Y % 9% M M E M M O O R R Y % 10% M M EEEEE M M OOO R R Y % 11% % 12% % 13% MagickCore Memory Allocation Methods % 14% % 15% Software Design % 16% Cristy % 17% July 1998 % 18% % 19% % 20% Copyright 1999-2015 ImageMagick Studio LLC, a non-profit organization % 21% dedicated to making software imaging solutions freely available. % 22% % 23% You may not use this file except in compliance with the License. You may % 24% obtain a copy of the License at % 25% % 26% http://www.imagemagick.org/script/license.php % 27% % 28% Unless required by applicable law or agreed to in writing, software % 29% distributed under the License is distributed on an "AS IS" BASIS, % 30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 31% See the License for the specific language governing permissions and % 32% limitations under the License. % 33% % 34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35% 36% Segregate our memory requirements from any program that calls our API. This 37% should help reduce the risk of others changing our program state or causing 38% memory corruption. 39% 40% Our custom memory allocation manager implements a best-fit allocation policy 41% using segregated free lists. It uses a linear distribution of size classes 42% for lower sizes and a power of two distribution of size classes at higher 43% sizes. It is based on the paper, "Fast Memory Allocation using Lazy Fits." 44% written by Yoo C. Chung. 45% 46% By default, ANSI memory methods are called (e.g. malloc). Use the 47% custom memory allocator by defining MAGICKCORE_ZERO_CONFIGURATION_SUPPORT 48% to allocate memory with private anonymous mapping rather than from the 49% heap. 50% 51*/ 52 53/* 54 Include declarations. 55*/ 56#include "MagickCore/studio.h" 57#include "MagickCore/blob.h" 58#include "MagickCore/blob-private.h" 59#include "MagickCore/exception.h" 60#include "MagickCore/exception-private.h" 61#include "MagickCore/memory_.h" 62#include "MagickCore/memory-private.h" 63#include "MagickCore/resource_.h" 64#include "MagickCore/semaphore.h" 65#include "MagickCore/string_.h" 66#include "MagickCore/utility-private.h" 67 68/* 69 Define declarations. 70*/ 71#define BlockFooter(block,size) \ 72 ((size_t *) ((char *) (block)+(size)-2*sizeof(size_t))) 73#define BlockHeader(block) ((size_t *) (block)-1) 74#define BlockSize 4096 75#define BlockThreshold 1024 76#define MaxBlockExponent 16 77#define MaxBlocks ((BlockThreshold/(4*sizeof(size_t)))+MaxBlockExponent+1) 78#define MaxSegments 1024 79#define MemoryGuard ((0xdeadbeef << 31)+0xdeafdeed) 80#define NextBlock(block) ((char *) (block)+SizeOfBlock(block)) 81#define NextBlockInList(block) (*(void **) (block)) 82#define PreviousBlock(block) ((char *) (block)-(*((size_t *) (block)-2))) 83#define PreviousBlockBit 0x01 84#define PreviousBlockInList(block) (*((void **) (block)+1)) 85#define SegmentSize (2*1024*1024) 86#define SizeMask (~0x01) 87#define SizeOfBlock(block) (*BlockHeader(block) & SizeMask) 88 89/* 90 Typedef declarations. 91*/ 92typedef enum 93{ 94 UndefinedVirtualMemory, 95 AlignedVirtualMemory, 96 MapVirtualMemory, 97 UnalignedVirtualMemory 98} VirtualMemoryType; 99 100typedef struct _DataSegmentInfo 101{ 102 void 103 *allocation, 104 *bound; 105 106 MagickBooleanType 107 mapped; 108 109 size_t 110 length; 111 112 struct _DataSegmentInfo 113 *previous, 114 *next; 115} DataSegmentInfo; 116 117typedef struct _MagickMemoryMethods 118{ 119 AcquireMemoryHandler 120 acquire_memory_handler; 121 122 ResizeMemoryHandler 123 resize_memory_handler; 124 125 DestroyMemoryHandler 126 destroy_memory_handler; 127} MagickMemoryMethods; 128 129struct _MemoryInfo 130{ 131 char 132 filename[MagickPathExtent]; 133 134 VirtualMemoryType 135 type; 136 137 size_t 138 length; 139 140 void 141 *blob; 142 143 size_t 144 signature; 145}; 146 147typedef struct _MemoryPool 148{ 149 size_t 150 allocation; 151 152 void 153 *blocks[MaxBlocks+1]; 154 155 size_t 156 number_segments; 157 158 DataSegmentInfo 159 *segments[MaxSegments], 160 segment_pool[MaxSegments]; 161} MemoryPool; 162 163/* 164 Global declarations. 165*/ 166#if defined _MSC_VER 167static void* MSCMalloc(size_t size) 168{ 169 return malloc(size); 170} 171static void* MSCRealloc(void* ptr, size_t size) 172{ 173 return realloc(ptr, size); 174} 175static void MSCFree(void* ptr) 176{ 177 free(ptr); 178} 179#endif 180 181static MagickMemoryMethods 182 memory_methods = 183 { 184#if defined _MSC_VER 185 (AcquireMemoryHandler) MSCMalloc, 186 (ResizeMemoryHandler) MSCRealloc, 187 (DestroyMemoryHandler) MSCFree 188#else 189 (AcquireMemoryHandler) malloc, 190 (ResizeMemoryHandler) realloc, 191 (DestroyMemoryHandler) free 192#endif 193 }; 194#if defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT) 195static MemoryPool 196 memory_pool; 197 198static SemaphoreInfo 199 *memory_semaphore = (SemaphoreInfo *) NULL; 200 201static volatile DataSegmentInfo 202 *free_segments = (DataSegmentInfo *) NULL; 203 204/* 205 Forward declarations. 206*/ 207static MagickBooleanType 208 ExpandHeap(size_t); 209#endif 210 211/* 212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 213% % 214% % 215% % 216% A c q u i r e A l i g n e d M e m o r y % 217% % 218% % 219% % 220%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 221% 222% AcquireAlignedMemory() returns a pointer to a block of memory at least size 223% bytes whose address is a multiple of 16*sizeof(void *). 224% 225% The format of the AcquireAlignedMemory method is: 226% 227% void *AcquireAlignedMemory(const size_t count,const size_t quantum) 228% 229% A description of each parameter follows: 230% 231% o count: the number of quantum elements to allocate. 232% 233% o quantum: the number of bytes in each quantum. 234% 235*/ 236MagickExport void *AcquireAlignedMemory(const size_t count,const size_t quantum) 237{ 238#define AlignedExtent(size,alignment) \ 239 (((size)+((alignment)-1)) & ~((alignment)-1)) 240 241 size_t 242 alignment, 243 extent, 244 size; 245 246 void 247 *memory; 248 249 size=count*quantum; 250 if ((count == 0) || (quantum != (size/count))) 251 { 252 errno=ENOMEM; 253 return((void *) NULL); 254 } 255 memory=NULL; 256 alignment=CACHE_LINE_SIZE; 257 extent=AlignedExtent(size,alignment); 258 if ((size == 0) || (alignment < sizeof(void *)) || (extent < size)) 259 return((void *) NULL); 260#if defined(MAGICKCORE_HAVE_POSIX_MEMALIGN) 261 if (posix_memalign(&memory,alignment,extent) != 0) 262 memory=NULL; 263#elif defined(MAGICKCORE_HAVE__ALIGNED_MALLOC) 264 memory=_aligned_malloc(extent,alignment); 265#else 266 { 267 void 268 *p; 269 270 extent=(size+alignment-1)+sizeof(void *); 271 if (extent > size) 272 { 273 p=malloc(extent); 274 if (p != NULL) 275 { 276 memory=(void *) AlignedExtent((size_t) p+sizeof(void *),alignment); 277 *((void **) memory-1)=p; 278 } 279 } 280 } 281#endif 282 return(memory); 283} 284 285#if defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT) 286/* 287%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 288% % 289% % 290% % 291+ A c q u i r e B l o c k % 292% % 293% % 294% % 295%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 296% 297% AcquireBlock() returns a pointer to a block of memory at least size bytes 298% suitably aligned for any use. 299% 300% The format of the AcquireBlock method is: 301% 302% void *AcquireBlock(const size_t size) 303% 304% A description of each parameter follows: 305% 306% o size: the size of the memory in bytes to allocate. 307% 308*/ 309 310static inline size_t AllocationPolicy(size_t size) 311{ 312 register size_t 313 blocksize; 314 315 /* 316 The linear distribution. 317 */ 318 assert(size != 0); 319 assert(size % (4*sizeof(size_t)) == 0); 320 if (size <= BlockThreshold) 321 return(size/(4*sizeof(size_t))); 322 /* 323 Check for the largest block size. 324 */ 325 if (size > (size_t) (BlockThreshold*(1L << (MaxBlockExponent-1L)))) 326 return(MaxBlocks-1L); 327 /* 328 Otherwise use a power of two distribution. 329 */ 330 blocksize=BlockThreshold/(4*sizeof(size_t)); 331 for ( ; size > BlockThreshold; size/=2) 332 blocksize++; 333 assert(blocksize > (BlockThreshold/(4*sizeof(size_t)))); 334 assert(blocksize < (MaxBlocks-1L)); 335 return(blocksize); 336} 337 338static inline void InsertFreeBlock(void *block,const size_t i) 339{ 340 register void 341 *next, 342 *previous; 343 344 size_t 345 size; 346 347 size=SizeOfBlock(block); 348 previous=(void *) NULL; 349 next=memory_pool.blocks[i]; 350 while ((next != (void *) NULL) && (SizeOfBlock(next) < size)) 351 { 352 previous=next; 353 next=NextBlockInList(next); 354 } 355 PreviousBlockInList(block)=previous; 356 NextBlockInList(block)=next; 357 if (previous != (void *) NULL) 358 NextBlockInList(previous)=block; 359 else 360 memory_pool.blocks[i]=block; 361 if (next != (void *) NULL) 362 PreviousBlockInList(next)=block; 363} 364 365static inline void RemoveFreeBlock(void *block,const size_t i) 366{ 367 register void 368 *next, 369 *previous; 370 371 next=NextBlockInList(block); 372 previous=PreviousBlockInList(block); 373 if (previous == (void *) NULL) 374 memory_pool.blocks[i]=next; 375 else 376 NextBlockInList(previous)=next; 377 if (next != (void *) NULL) 378 PreviousBlockInList(next)=previous; 379} 380 381static void *AcquireBlock(size_t size) 382{ 383 register size_t 384 i; 385 386 register void 387 *block; 388 389 /* 390 Find free block. 391 */ 392 size=(size_t) (size+sizeof(size_t)+6*sizeof(size_t)-1) & -(4U*sizeof(size_t)); 393 i=AllocationPolicy(size); 394 block=memory_pool.blocks[i]; 395 while ((block != (void *) NULL) && (SizeOfBlock(block) < size)) 396 block=NextBlockInList(block); 397 if (block == (void *) NULL) 398 { 399 i++; 400 while (memory_pool.blocks[i] == (void *) NULL) 401 i++; 402 block=memory_pool.blocks[i]; 403 if (i >= MaxBlocks) 404 return((void *) NULL); 405 } 406 assert((*BlockHeader(NextBlock(block)) & PreviousBlockBit) == 0); 407 assert(SizeOfBlock(block) >= size); 408 RemoveFreeBlock(block,AllocationPolicy(SizeOfBlock(block))); 409 if (SizeOfBlock(block) > size) 410 { 411 size_t 412 blocksize; 413 414 void 415 *next; 416 417 /* 418 Split block. 419 */ 420 next=(char *) block+size; 421 blocksize=SizeOfBlock(block)-size; 422 *BlockHeader(next)=blocksize; 423 *BlockFooter(next,blocksize)=blocksize; 424 InsertFreeBlock(next,AllocationPolicy(blocksize)); 425 *BlockHeader(block)=size | (*BlockHeader(block) & ~SizeMask); 426 } 427 assert(size == SizeOfBlock(block)); 428 *BlockHeader(NextBlock(block))|=PreviousBlockBit; 429 memory_pool.allocation+=size; 430 return(block); 431} 432#endif 433 434/* 435%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 436% % 437% % 438% % 439% A c q u i r e M a g i c k M e m o r y % 440% % 441% % 442% % 443%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 444% 445% AcquireMagickMemory() returns a pointer to a block of memory at least size 446% bytes suitably aligned for any use. 447% 448% The format of the AcquireMagickMemory method is: 449% 450% void *AcquireMagickMemory(const size_t size) 451% 452% A description of each parameter follows: 453% 454% o size: the size of the memory in bytes to allocate. 455% 456*/ 457MagickExport void *AcquireMagickMemory(const size_t size) 458{ 459 register void 460 *memory; 461 462#if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT) 463 memory=memory_methods.acquire_memory_handler(size == 0 ? 1UL : size); 464#else 465 if (memory_semaphore == (SemaphoreInfo *) NULL) 466 ActivateSemaphoreInfo(&memory_semaphore); 467 if (free_segments == (DataSegmentInfo *) NULL) 468 { 469 LockSemaphoreInfo(memory_semaphore); 470 if (free_segments == (DataSegmentInfo *) NULL) 471 { 472 register ssize_t 473 i; 474 475 assert(2*sizeof(size_t) > (size_t) (~SizeMask)); 476 (void) ResetMagickMemory(&memory_pool,0,sizeof(memory_pool)); 477 memory_pool.allocation=SegmentSize; 478 memory_pool.blocks[MaxBlocks]=(void *) (-1); 479 for (i=0; i < MaxSegments; i++) 480 { 481 if (i != 0) 482 memory_pool.segment_pool[i].previous= 483 (&memory_pool.segment_pool[i-1]); 484 if (i != (MaxSegments-1)) 485 memory_pool.segment_pool[i].next=(&memory_pool.segment_pool[i+1]); 486 } 487 free_segments=(&memory_pool.segment_pool[0]); 488 } 489 UnlockSemaphoreInfo(memory_semaphore); 490 } 491 LockSemaphoreInfo(memory_semaphore); 492 memory=AcquireBlock(size == 0 ? 1UL : size); 493 if (memory == (void *) NULL) 494 { 495 if (ExpandHeap(size == 0 ? 1UL : size) != MagickFalse) 496 memory=AcquireBlock(size == 0 ? 1UL : size); 497 } 498 UnlockSemaphoreInfo(memory_semaphore); 499#endif 500 return(memory); 501} 502 503/* 504%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 505% % 506% % 507% % 508% A c q u i r e Q u a n t u m M e m o r y % 509% % 510% % 511% % 512%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 513% 514% AcquireQuantumMemory() returns a pointer to a block of memory at least 515% count * quantum bytes suitably aligned for any use. 516% 517% The format of the AcquireQuantumMemory method is: 518% 519% void *AcquireQuantumMemory(const size_t count,const size_t quantum) 520% 521% A description of each parameter follows: 522% 523% o count: the number of quantum elements to allocate. 524% 525% o quantum: the number of bytes in each quantum. 526% 527*/ 528MagickExport void *AcquireQuantumMemory(const size_t count,const size_t quantum) 529{ 530 size_t 531 size; 532 533 size=count*quantum; 534 if ((count == 0) || (quantum != (size/count))) 535 { 536 errno=ENOMEM; 537 return((void *) NULL); 538 } 539 return(AcquireMagickMemory(size)); 540} 541 542/* 543%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 544% % 545% % 546% % 547% A c q u i r e V i r t u a l M e m o r y % 548% % 549% % 550% % 551%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 552% 553% AcquireVirtualMemory() allocates a pointer to a block of memory at least size 554% bytes suitably aligned for any use. 555% 556% The format of the AcquireVirtualMemory method is: 557% 558% MemoryInfo *AcquireVirtualMemory(const size_t count,const size_t quantum) 559% 560% A description of each parameter follows: 561% 562% o count: the number of quantum elements to allocate. 563% 564% o quantum: the number of bytes in each quantum. 565% 566*/ 567MagickExport MemoryInfo *AcquireVirtualMemory(const size_t count, 568 const size_t quantum) 569{ 570 MemoryInfo 571 *memory_info; 572 573 size_t 574 length; 575 576 length=count*quantum; 577 if ((count == 0) || (quantum != (length/count))) 578 { 579 errno=ENOMEM; 580 return((MemoryInfo *) NULL); 581 } 582 memory_info=(MemoryInfo *) MagickAssumeAligned(AcquireAlignedMemory(1, 583 sizeof(*memory_info))); 584 if (memory_info == (MemoryInfo *) NULL) 585 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 586 (void) ResetMagickMemory(memory_info,0,sizeof(*memory_info)); 587 memory_info->length=length; 588 memory_info->signature=MagickCoreSignature; 589 if (AcquireMagickResource(MemoryResource,length) != MagickFalse) 590 { 591 memory_info->blob=AcquireAlignedMemory(1,length); 592 if (memory_info->blob != NULL) 593 memory_info->type=AlignedVirtualMemory; 594 else 595 RelinquishMagickResource(MemoryResource,length); 596 } 597 if ((memory_info->blob == NULL) && 598 (AcquireMagickResource(MapResource,length) != MagickFalse)) 599 { 600 /* 601 Heap memory failed, try anonymous memory mapping. 602 */ 603 memory_info->blob=MapBlob(-1,IOMode,0,length); 604 if (memory_info->blob != NULL) 605 memory_info->type=MapVirtualMemory; 606 else 607 RelinquishMagickResource(MapResource,length); 608 } 609 if ((memory_info->blob == NULL) && 610 (AcquireMagickResource(DiskResource,length) != MagickFalse)) 611 { 612 int 613 file; 614 615 /* 616 Anonymous memory mapping failed, try file-backed memory mapping. 617 */ 618 file=AcquireUniqueFileResource(memory_info->filename); 619 if (file == -1) 620 RelinquishMagickResource(DiskResource,length); 621 else 622 { 623 if ((lseek(file,length-1,SEEK_SET) < 0) || (write(file,"",1) != 1)) 624 RelinquishMagickResource(DiskResource,length); 625 else 626 { 627 if (AcquireMagickResource(MapResource,length) == MagickFalse) 628 RelinquishMagickResource(DiskResource,length); 629 else 630 { 631 memory_info->blob=MapBlob(file,IOMode,0,length); 632 if (memory_info->blob != NULL) 633 memory_info->type=MapVirtualMemory; 634 else 635 { 636 RelinquishMagickResource(MapResource,length); 637 RelinquishMagickResource(DiskResource,length); 638 } 639 } 640 } 641 (void) close(file); 642 } 643 } 644 if (memory_info->blob == NULL) 645 { 646 memory_info->blob=AcquireMagickMemory(length); 647 if (memory_info->blob != NULL) 648 memory_info->type=UnalignedVirtualMemory; 649 } 650 if (memory_info->blob == NULL) 651 memory_info=RelinquishVirtualMemory(memory_info); 652 return(memory_info); 653} 654 655/* 656%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 657% % 658% % 659% % 660% C o p y M a g i c k M e m o r y % 661% % 662% % 663% % 664%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 665% 666% CopyMagickMemory() copies size bytes from memory area source to the 667% destination. Copying between objects that overlap will take place 668% correctly. It returns destination. 669% 670% The format of the CopyMagickMemory method is: 671% 672% void *CopyMagickMemory(void *destination,const void *source, 673% const size_t size) 674% 675% A description of each parameter follows: 676% 677% o destination: the destination. 678% 679% o source: the source. 680% 681% o size: the size of the memory in bytes to allocate. 682% 683*/ 684MagickExport void *CopyMagickMemory(void *destination,const void *source, 685 const size_t size) 686{ 687 register const unsigned char 688 *p; 689 690 register unsigned char 691 *q; 692 693 assert(destination != (void *) NULL); 694 assert(source != (const void *) NULL); 695 p=(const unsigned char *) source; 696 q=(unsigned char *) destination; 697 if (((q+size) < p) || (q > (p+size))) 698 switch (size) 699 { 700 default: return(memcpy(destination,source,size)); 701 case 8: *q++=(*p++); 702 case 7: *q++=(*p++); 703 case 6: *q++=(*p++); 704 case 5: *q++=(*p++); 705 case 4: *q++=(*p++); 706 case 3: *q++=(*p++); 707 case 2: *q++=(*p++); 708 case 1: *q++=(*p++); 709 case 0: return(destination); 710 } 711 return(memmove(destination,source,size)); 712} 713 714/* 715%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 716% % 717% % 718% % 719+ D e s t r o y M a g i c k M e m o r y % 720% % 721% % 722% % 723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 724% 725% DestroyMagickMemory() deallocates memory associated with the memory manager. 726% 727% The format of the DestroyMagickMemory method is: 728% 729% DestroyMagickMemory(void) 730% 731*/ 732MagickExport void DestroyMagickMemory(void) 733{ 734#if defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT) 735 register ssize_t 736 i; 737 738 if (memory_semaphore == (SemaphoreInfo *) NULL) 739 ActivateSemaphoreInfo(&memory_semaphore); 740 LockSemaphoreInfo(memory_semaphore); 741 for (i=0; i < (ssize_t) memory_pool.number_segments; i++) 742 if (memory_pool.segments[i]->mapped == MagickFalse) 743 memory_methods.destroy_memory_handler( 744 memory_pool.segments[i]->allocation); 745 else 746 (void) UnmapBlob(memory_pool.segments[i]->allocation, 747 memory_pool.segments[i]->length); 748 free_segments=(DataSegmentInfo *) NULL; 749 (void) ResetMagickMemory(&memory_pool,0,sizeof(memory_pool)); 750 UnlockSemaphoreInfo(memory_semaphore); 751 RelinquishSemaphoreInfo(&memory_semaphore); 752#endif 753} 754 755#if defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT) 756/* 757%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 758% % 759% % 760% % 761+ E x p a n d H e a p % 762% % 763% % 764% % 765%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 766% 767% ExpandHeap() get more memory from the system. It returns MagickTrue on 768% success otherwise MagickFalse. 769% 770% The format of the ExpandHeap method is: 771% 772% MagickBooleanType ExpandHeap(size_t size) 773% 774% A description of each parameter follows: 775% 776% o size: the size of the memory in bytes we require. 777% 778*/ 779static MagickBooleanType ExpandHeap(size_t size) 780{ 781 DataSegmentInfo 782 *segment_info; 783 784 MagickBooleanType 785 mapped; 786 787 register ssize_t 788 i; 789 790 register void 791 *block; 792 793 size_t 794 blocksize; 795 796 void 797 *segment; 798 799 blocksize=((size+12*sizeof(size_t))+SegmentSize-1) & -SegmentSize; 800 assert(memory_pool.number_segments < MaxSegments); 801 segment=MapBlob(-1,IOMode,0,blocksize); 802 mapped=segment != (void *) NULL ? MagickTrue : MagickFalse; 803 if (segment == (void *) NULL) 804 segment=(void *) memory_methods.acquire_memory_handler(blocksize); 805 if (segment == (void *) NULL) 806 return(MagickFalse); 807 segment_info=(DataSegmentInfo *) free_segments; 808 free_segments=segment_info->next; 809 segment_info->mapped=mapped; 810 segment_info->length=blocksize; 811 segment_info->allocation=segment; 812 segment_info->bound=(char *) segment+blocksize; 813 i=(ssize_t) memory_pool.number_segments-1; 814 for ( ; (i >= 0) && (memory_pool.segments[i]->allocation > segment); i--) 815 memory_pool.segments[i+1]=memory_pool.segments[i]; 816 memory_pool.segments[i+1]=segment_info; 817 memory_pool.number_segments++; 818 size=blocksize-12*sizeof(size_t); 819 block=(char *) segment_info->allocation+4*sizeof(size_t); 820 *BlockHeader(block)=size | PreviousBlockBit; 821 *BlockFooter(block,size)=size; 822 InsertFreeBlock(block,AllocationPolicy(size)); 823 block=NextBlock(block); 824 assert(block < segment_info->bound); 825 *BlockHeader(block)=2*sizeof(size_t); 826 *BlockHeader(NextBlock(block))=PreviousBlockBit; 827 return(MagickTrue); 828} 829#endif 830 831/* 832%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 833% % 834% % 835% % 836% G e t M a g i c k M e m o r y M e t h o d s % 837% % 838% % 839% % 840%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 841% 842% GetMagickMemoryMethods() gets the methods to acquire, resize, and destroy 843% memory. 844% 845% The format of the GetMagickMemoryMethods() method is: 846% 847% void GetMagickMemoryMethods(AcquireMemoryHandler *acquire_memory_handler, 848% ResizeMemoryHandler *resize_memory_handler, 849% DestroyMemoryHandler *destroy_memory_handler) 850% 851% A description of each parameter follows: 852% 853% o acquire_memory_handler: method to acquire memory (e.g. malloc). 854% 855% o resize_memory_handler: method to resize memory (e.g. realloc). 856% 857% o destroy_memory_handler: method to destroy memory (e.g. free). 858% 859*/ 860MagickExport void GetMagickMemoryMethods( 861 AcquireMemoryHandler *acquire_memory_handler, 862 ResizeMemoryHandler *resize_memory_handler, 863 DestroyMemoryHandler *destroy_memory_handler) 864{ 865 assert(acquire_memory_handler != (AcquireMemoryHandler *) NULL); 866 assert(resize_memory_handler != (ResizeMemoryHandler *) NULL); 867 assert(destroy_memory_handler != (DestroyMemoryHandler *) NULL); 868 *acquire_memory_handler=memory_methods.acquire_memory_handler; 869 *resize_memory_handler=memory_methods.resize_memory_handler; 870 *destroy_memory_handler=memory_methods.destroy_memory_handler; 871} 872 873/* 874%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 875% % 876% % 877% % 878% G e t V i r t u a l M e m o r y B l o b % 879% % 880% % 881% % 882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 883% 884% GetVirtualMemoryBlob() returns the virtual memory blob associated with the 885% specified MemoryInfo structure. 886% 887% The format of the GetVirtualMemoryBlob method is: 888% 889% void *GetVirtualMemoryBlob(const MemoryInfo *memory_info) 890% 891% A description of each parameter follows: 892% 893% o memory_info: The MemoryInfo structure. 894*/ 895MagickExport void *GetVirtualMemoryBlob(const MemoryInfo *memory_info) 896{ 897 assert(memory_info != (const MemoryInfo *) NULL); 898 assert(memory_info->signature == MagickCoreSignature); 899 return(memory_info->blob); 900} 901 902/* 903%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 904% % 905% % 906% % 907% R e l i n q u i s h A l i g n e d M e m o r y % 908% % 909% % 910% % 911%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 912% 913% RelinquishAlignedMemory() frees memory acquired with AcquireAlignedMemory() 914% or reuse. 915% 916% The format of the RelinquishAlignedMemory method is: 917% 918% void *RelinquishAlignedMemory(void *memory) 919% 920% A description of each parameter follows: 921% 922% o memory: A pointer to a block of memory to free for reuse. 923% 924*/ 925MagickExport void *RelinquishAlignedMemory(void *memory) 926{ 927 if (memory == (void *) NULL) 928 return((void *) NULL); 929#if defined(MAGICKCORE_HAVE_POSIX_MEMALIGN) 930 free(memory); 931#elif defined(MAGICKCORE_HAVE__ALIGNED_MALLOC) 932 _aligned_free(memory); 933#else 934 free(*((void **) memory-1)); 935#endif 936 return(NULL); 937} 938 939/* 940%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 941% % 942% % 943% % 944% R e l i n q u i s h M a g i c k M e m o r y % 945% % 946% % 947% % 948%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 949% 950% RelinquishMagickMemory() frees memory acquired with AcquireMagickMemory() 951% or AcquireQuantumMemory() for reuse. 952% 953% The format of the RelinquishMagickMemory method is: 954% 955% void *RelinquishMagickMemory(void *memory) 956% 957% A description of each parameter follows: 958% 959% o memory: A pointer to a block of memory to free for reuse. 960% 961*/ 962MagickExport void *RelinquishMagickMemory(void *memory) 963{ 964 if (memory == (void *) NULL) 965 return((void *) NULL); 966#if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT) 967 memory_methods.destroy_memory_handler(memory); 968#else 969 LockSemaphoreInfo(memory_semaphore); 970 assert((SizeOfBlock(memory) % (4*sizeof(size_t))) == 0); 971 assert((*BlockHeader(NextBlock(memory)) & PreviousBlockBit) != 0); 972 if ((*BlockHeader(memory) & PreviousBlockBit) == 0) 973 { 974 void 975 *previous; 976 977 /* 978 Coalesce with previous adjacent block. 979 */ 980 previous=PreviousBlock(memory); 981 RemoveFreeBlock(previous,AllocationPolicy(SizeOfBlock(previous))); 982 *BlockHeader(previous)=(SizeOfBlock(previous)+SizeOfBlock(memory)) | 983 (*BlockHeader(previous) & ~SizeMask); 984 memory=previous; 985 } 986 if ((*BlockHeader(NextBlock(NextBlock(memory))) & PreviousBlockBit) == 0) 987 { 988 void 989 *next; 990 991 /* 992 Coalesce with next adjacent block. 993 */ 994 next=NextBlock(memory); 995 RemoveFreeBlock(next,AllocationPolicy(SizeOfBlock(next))); 996 *BlockHeader(memory)=(SizeOfBlock(memory)+SizeOfBlock(next)) | 997 (*BlockHeader(memory) & ~SizeMask); 998 } 999 *BlockFooter(memory,SizeOfBlock(memory))=SizeOfBlock(memory); 1000 *BlockHeader(NextBlock(memory))&=(~PreviousBlockBit); 1001 InsertFreeBlock(memory,AllocationPolicy(SizeOfBlock(memory))); 1002 UnlockSemaphoreInfo(memory_semaphore); 1003#endif 1004 return((void *) NULL); 1005} 1006 1007/* 1008%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1009% % 1010% % 1011% % 1012% R e l i n q u i s h V i r t u a l M e m o r y % 1013% % 1014% % 1015% % 1016%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1017% 1018% RelinquishVirtualMemory() frees memory acquired with AcquireVirtualMemory(). 1019% 1020% The format of the RelinquishVirtualMemory method is: 1021% 1022% MemoryInfo *RelinquishVirtualMemory(MemoryInfo *memory_info) 1023% 1024% A description of each parameter follows: 1025% 1026% o memory_info: A pointer to a block of memory to free for reuse. 1027% 1028*/ 1029MagickExport MemoryInfo *RelinquishVirtualMemory(MemoryInfo *memory_info) 1030{ 1031 assert(memory_info != (MemoryInfo *) NULL); 1032 assert(memory_info->signature == MagickCoreSignature); 1033 if (memory_info->blob != (void *) NULL) 1034 switch (memory_info->type) 1035 { 1036 case AlignedVirtualMemory: 1037 { 1038 memory_info->blob=RelinquishAlignedMemory(memory_info->blob); 1039 RelinquishMagickResource(MemoryResource,memory_info->length); 1040 break; 1041 } 1042 case MapVirtualMemory: 1043 { 1044 (void) UnmapBlob(memory_info->blob,memory_info->length); 1045 memory_info->blob=NULL; 1046 RelinquishMagickResource(MapResource,memory_info->length); 1047 if (*memory_info->filename != '\0') 1048 { 1049 (void) RelinquishUniqueFileResource(memory_info->filename); 1050 RelinquishMagickResource(DiskResource,memory_info->length); 1051 } 1052 break; 1053 } 1054 case UnalignedVirtualMemory: 1055 default: 1056 { 1057 memory_info->blob=RelinquishMagickMemory(memory_info->blob); 1058 break; 1059 } 1060 } 1061 memory_info->signature=(~MagickCoreSignature); 1062 memory_info=(MemoryInfo *) RelinquishAlignedMemory(memory_info); 1063 return(memory_info); 1064} 1065 1066/* 1067%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1068% % 1069% % 1070% % 1071% R e s e t M a g i c k M e m o r y % 1072% % 1073% % 1074% % 1075%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1076% 1077% ResetMagickMemory() fills the first size bytes of the memory area pointed to 1078% by memory with the constant byte c. 1079% 1080% The format of the ResetMagickMemory method is: 1081% 1082% void *ResetMagickMemory(void *memory,int byte,const size_t size) 1083% 1084% A description of each parameter follows: 1085% 1086% o memory: a pointer to a memory allocation. 1087% 1088% o byte: set the memory to this value. 1089% 1090% o size: size of the memory to reset. 1091% 1092*/ 1093MagickExport void *ResetMagickMemory(void *memory,int byte,const size_t size) 1094{ 1095 assert(memory != (void *) NULL); 1096 return(memset(memory,byte,size)); 1097} 1098 1099/* 1100%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1101% % 1102% % 1103% % 1104% R e s i z e M a g i c k M e m o r y % 1105% % 1106% % 1107% % 1108%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1109% 1110% ResizeMagickMemory() changes the size of the memory and returns a pointer to 1111% the (possibly moved) block. The contents will be unchanged up to the 1112% lesser of the new and old sizes. 1113% 1114% The format of the ResizeMagickMemory method is: 1115% 1116% void *ResizeMagickMemory(void *memory,const size_t size) 1117% 1118% A description of each parameter follows: 1119% 1120% o memory: A pointer to a memory allocation. 1121% 1122% o size: the new size of the allocated memory. 1123% 1124*/ 1125 1126#if defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT) 1127static inline void *ResizeBlock(void *block,size_t size) 1128{ 1129 register void 1130 *memory; 1131 1132 if (block == (void *) NULL) 1133 return(AcquireBlock(size)); 1134 memory=AcquireBlock(size); 1135 if (memory == (void *) NULL) 1136 return((void *) NULL); 1137 if (size <= (SizeOfBlock(block)-sizeof(size_t))) 1138 (void) memcpy(memory,block,size); 1139 else 1140 (void) memcpy(memory,block,SizeOfBlock(block)-sizeof(size_t)); 1141 memory_pool.allocation+=size; 1142 return(memory); 1143} 1144#endif 1145 1146MagickExport void *ResizeMagickMemory(void *memory,const size_t size) 1147{ 1148 register void 1149 *block; 1150 1151 if (memory == (void *) NULL) 1152 return(AcquireMagickMemory(size)); 1153#if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT) 1154 block=memory_methods.resize_memory_handler(memory,size == 0 ? 1UL : size); 1155 if (block == (void *) NULL) 1156 memory=RelinquishMagickMemory(memory); 1157#else 1158 LockSemaphoreInfo(memory_semaphore); 1159 block=ResizeBlock(memory,size == 0 ? 1UL : size); 1160 if (block == (void *) NULL) 1161 { 1162 if (ExpandHeap(size == 0 ? 1UL : size) == MagickFalse) 1163 { 1164 UnlockSemaphoreInfo(memory_semaphore); 1165 memory=RelinquishMagickMemory(memory); 1166 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 1167 } 1168 block=ResizeBlock(memory,size == 0 ? 1UL : size); 1169 assert(block != (void *) NULL); 1170 } 1171 UnlockSemaphoreInfo(memory_semaphore); 1172 memory=RelinquishMagickMemory(memory); 1173#endif 1174 return(block); 1175} 1176 1177/* 1178%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1179% % 1180% % 1181% % 1182% R e s i z e Q u a n t u m M e m o r y % 1183% % 1184% % 1185% % 1186%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1187% 1188% ResizeQuantumMemory() changes the size of the memory and returns a pointer 1189% to the (possibly moved) block. The contents will be unchanged up to the 1190% lesser of the new and old sizes. 1191% 1192% The format of the ResizeQuantumMemory method is: 1193% 1194% void *ResizeQuantumMemory(void *memory,const size_t count, 1195% const size_t quantum) 1196% 1197% A description of each parameter follows: 1198% 1199% o memory: A pointer to a memory allocation. 1200% 1201% o count: the number of quantum elements to allocate. 1202% 1203% o quantum: the number of bytes in each quantum. 1204% 1205*/ 1206MagickExport void *ResizeQuantumMemory(void *memory,const size_t count, 1207 const size_t quantum) 1208{ 1209 size_t 1210 size; 1211 1212 size=count*quantum; 1213 if ((count == 0) || (quantum != (size/count))) 1214 { 1215 memory=RelinquishMagickMemory(memory); 1216 errno=ENOMEM; 1217 return((void *) NULL); 1218 } 1219 return(ResizeMagickMemory(memory,size)); 1220} 1221 1222/* 1223%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1224% % 1225% % 1226% % 1227% S e t M a g i c k M e m o r y M e t h o d s % 1228% % 1229% % 1230% % 1231%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1232% 1233% SetMagickMemoryMethods() sets the methods to acquire, resize, and destroy 1234% memory. Your custom memory methods must be set prior to the 1235% MagickCoreGenesis() method. 1236% 1237% The format of the SetMagickMemoryMethods() method is: 1238% 1239% SetMagickMemoryMethods(AcquireMemoryHandler acquire_memory_handler, 1240% ResizeMemoryHandler resize_memory_handler, 1241% DestroyMemoryHandler destroy_memory_handler) 1242% 1243% A description of each parameter follows: 1244% 1245% o acquire_memory_handler: method to acquire memory (e.g. malloc). 1246% 1247% o resize_memory_handler: method to resize memory (e.g. realloc). 1248% 1249% o destroy_memory_handler: method to destroy memory (e.g. free). 1250% 1251*/ 1252MagickExport void SetMagickMemoryMethods( 1253 AcquireMemoryHandler acquire_memory_handler, 1254 ResizeMemoryHandler resize_memory_handler, 1255 DestroyMemoryHandler destroy_memory_handler) 1256{ 1257 /* 1258 Set memory methods. 1259 */ 1260 if (acquire_memory_handler != (AcquireMemoryHandler) NULL) 1261 memory_methods.acquire_memory_handler=acquire_memory_handler; 1262 if (resize_memory_handler != (ResizeMemoryHandler) NULL) 1263 memory_methods.resize_memory_handler=resize_memory_handler; 1264 if (destroy_memory_handler != (DestroyMemoryHandler) NULL) 1265 memory_methods.destroy_memory_handler=destroy_memory_handler; 1266} 1267