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