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