|
MagickCore
6.7.5
|
00001 /* 00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00003 % % 00004 % % 00005 % % 00006 % M M EEEEE M M OOO RRRR Y Y % 00007 % MM MM E MM MM O O R R Y Y % 00008 % M M M EEE M M M O O RRRR Y % 00009 % M M E M M O O R R Y % 00010 % M M EEEEE M M OOO R R Y % 00011 % % 00012 % % 00013 % MagickCore Memory Allocation Methods % 00014 % % 00015 % Software Design % 00016 % John Cristy % 00017 % July 1998 % 00018 % % 00019 % % 00020 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization % 00021 % dedicated to making software imaging solutions freely available. % 00022 % % 00023 % You may not use this file except in compliance with the License. You may % 00024 % obtain a copy of the License at % 00025 % % 00026 % http://www.imagemagick.org/script/license.php % 00027 % % 00028 % Unless required by applicable law or agreed to in writing, software % 00029 % distributed under the License is distributed on an "AS IS" BASIS, % 00030 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 00031 % See the License for the specific language governing permissions and % 00032 % limitations under the License. % 00033 % % 00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00035 % 00036 % Segregate our memory requirements from any program that calls our API. This 00037 % should help reduce the risk of others changing our program state or causing 00038 % memory corruption. 00039 % 00040 % Our custom memory allocation manager implements a best-fit allocation policy 00041 % using segregated free lists. It uses a linear distribution of size classes 00042 % for lower sizes and a power of two distribution of size classes at higher 00043 % sizes. It is based on the paper, "Fast Memory Allocation using Lazy Fits." 00044 % written by Yoo C. Chung. 00045 % 00046 % By default, ANSI memory methods are called (e.g. malloc). Use the 00047 % custom memory allocator by defining MAGICKCORE_ZERO_CONFIGURATION_SUPPORT 00048 % to allocate memory with private anonymous mapping rather than from the 00049 % heap. 00050 % 00051 */ 00052 00053 /* 00054 Include declarations. 00055 */ 00056 #include "MagickCore/studio.h" 00057 #include "MagickCore/blob.h" 00058 #include "MagickCore/blob-private.h" 00059 #include "MagickCore/exception.h" 00060 #include "MagickCore/exception-private.h" 00061 #include "MagickCore/memory_.h" 00062 #include "MagickCore/semaphore.h" 00063 #include "MagickCore/string_.h" 00064 00065 /* 00066 Define declarations. 00067 */ 00068 #define BlockFooter(block,size) \ 00069 ((size_t *) ((char *) (block)+(size)-2*sizeof(size_t))) 00070 #define BlockHeader(block) ((size_t *) (block)-1) 00071 #define BlockSize 4096 00072 #define BlockThreshold 1024 00073 #define AlignedSize (16*sizeof(void *)) 00074 #define MaxBlockExponent 16 00075 #define MaxBlocks ((BlockThreshold/(4*sizeof(size_t)))+MaxBlockExponent+1) 00076 #define MaxSegments 1024 00077 #define MemoryGuard ((0xdeadbeef << 31)+0xdeafdeed) 00078 #define NextBlock(block) ((char *) (block)+SizeOfBlock(block)) 00079 #define NextBlockInList(block) (*(void **) (block)) 00080 #define PreviousBlock(block) ((char *) (block)-(*((size_t *) (block)-2))) 00081 #define PreviousBlockBit 0x01 00082 #define PreviousBlockInList(block) (*((void **) (block)+1)) 00083 #define SegmentSize (2*1024*1024) 00084 #define SizeMask (~0x01) 00085 #define SizeOfBlock(block) (*BlockHeader(block) & SizeMask) 00086 00087 /* 00088 Typedef declarations. 00089 */ 00090 typedef struct _DataSegmentInfo 00091 { 00092 void 00093 *allocation, 00094 *bound; 00095 00096 MagickBooleanType 00097 mapped; 00098 00099 size_t 00100 length; 00101 00102 struct _DataSegmentInfo 00103 *previous, 00104 *next; 00105 } DataSegmentInfo; 00106 00107 typedef struct _MemoryInfo 00108 { 00109 size_t 00110 allocation; 00111 00112 void 00113 *blocks[MaxBlocks+1]; 00114 00115 size_t 00116 number_segments; 00117 00118 DataSegmentInfo 00119 *segments[MaxSegments], 00120 segment_pool[MaxSegments]; 00121 } MemoryInfo; 00122 00123 typedef struct _MagickMemoryMethods 00124 { 00125 AcquireMemoryHandler 00126 acquire_memory_handler; 00127 00128 ResizeMemoryHandler 00129 resize_memory_handler; 00130 00131 DestroyMemoryHandler 00132 destroy_memory_handler; 00133 } MagickMemoryMethods; 00134 00135 00136 /* 00137 Global declarations. 00138 */ 00139 static MagickMemoryMethods 00140 memory_methods = 00141 { 00142 (AcquireMemoryHandler) malloc, 00143 (ResizeMemoryHandler) realloc, 00144 (DestroyMemoryHandler) free 00145 }; 00146 00147 #if defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT) 00148 static MemoryInfo 00149 memory_info; 00150 00151 static SemaphoreInfo 00152 *memory_semaphore = (SemaphoreInfo *) NULL; 00153 00154 static volatile DataSegmentInfo 00155 *free_segments = (DataSegmentInfo *) NULL; 00156 00157 /* 00158 Forward declarations. 00159 */ 00160 static MagickBooleanType 00161 ExpandHeap(size_t); 00162 #endif 00163 00164 /* 00165 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00166 % % 00167 % % 00168 % % 00169 % A c q u i r e A l i g n e d M e m o r y % 00170 % % 00171 % % 00172 % % 00173 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00174 % 00175 % AcquireAlignedMemory() returns a pointer to a block of memory at least size 00176 % bytes whose address is a multiple of 16*sizeof(void *). 00177 % 00178 % The format of the AcquireAlignedMemory method is: 00179 % 00180 % void *AcquireAlignedMemory(const size_t count,const size_t quantum) 00181 % 00182 % A description of each parameter follows: 00183 % 00184 % o count: the number of quantum elements to allocate. 00185 % 00186 % o quantum: the number of bytes in each quantum. 00187 % 00188 */ 00189 00190 static inline size_t MagickMax(const size_t x,const size_t y) 00191 { 00192 if (x > y) 00193 return(x); 00194 return(y); 00195 } 00196 00197 MagickExport void *AcquireAlignedMemory(const size_t count,const size_t quantum) 00198 { 00199 size_t 00200 size; 00201 00202 size=count*quantum; 00203 if ((count == 0) || (quantum != (size/count))) 00204 { 00205 errno=ENOMEM; 00206 return((void *) NULL); 00207 } 00208 #if defined(MAGICKCORE_HAVE_POSIX_MEMALIGN) 00209 { 00210 void 00211 *memory; 00212 00213 if (posix_memalign(&memory,AlignedSize,MagickMax(size,AlignedSize)) == 0) 00214 return(memory); 00215 } 00216 #endif 00217 return(malloc(MagickMax(size,AlignedSize))); 00218 } 00219 00220 #if defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT) 00221 /* 00222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00223 % % 00224 % % 00225 % % 00226 + A c q u i r e B l o c k % 00227 % % 00228 % % 00229 % % 00230 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00231 % 00232 % AcquireBlock() returns a pointer to a block of memory at least size bytes 00233 % suitably aligned for any use. 00234 % 00235 % The format of the AcquireBlock method is: 00236 % 00237 % void *AcquireBlock(const size_t size) 00238 % 00239 % A description of each parameter follows: 00240 % 00241 % o size: the size of the memory in bytes to allocate. 00242 % 00243 */ 00244 00245 static inline size_t AllocationPolicy(size_t size) 00246 { 00247 register size_t 00248 blocksize; 00249 00250 /* 00251 The linear distribution. 00252 */ 00253 assert(size != 0); 00254 assert(size % (4*sizeof(size_t)) == 0); 00255 if (size <= BlockThreshold) 00256 return(size/(4*sizeof(size_t))); 00257 /* 00258 Check for the largest block size. 00259 */ 00260 if (size > (size_t) (BlockThreshold*(1L << (MaxBlockExponent-1L)))) 00261 return(MaxBlocks-1L); 00262 /* 00263 Otherwise use a power of two distribution. 00264 */ 00265 blocksize=BlockThreshold/(4*sizeof(size_t)); 00266 for ( ; size > BlockThreshold; size/=2) 00267 blocksize++; 00268 assert(blocksize > (BlockThreshold/(4*sizeof(size_t)))); 00269 assert(blocksize < (MaxBlocks-1L)); 00270 return(blocksize); 00271 } 00272 00273 static inline void InsertFreeBlock(void *block,const size_t i) 00274 { 00275 register void 00276 *next, 00277 *previous; 00278 00279 size_t 00280 size; 00281 00282 size=SizeOfBlock(block); 00283 previous=(void *) NULL; 00284 next=memory_info.blocks[i]; 00285 while ((next != (void *) NULL) && (SizeOfBlock(next) < size)) 00286 { 00287 previous=next; 00288 next=NextBlockInList(next); 00289 } 00290 PreviousBlockInList(block)=previous; 00291 NextBlockInList(block)=next; 00292 if (previous != (void *) NULL) 00293 NextBlockInList(previous)=block; 00294 else 00295 memory_info.blocks[i]=block; 00296 if (next != (void *) NULL) 00297 PreviousBlockInList(next)=block; 00298 } 00299 00300 static inline void RemoveFreeBlock(void *block,const size_t i) 00301 { 00302 register void 00303 *next, 00304 *previous; 00305 00306 next=NextBlockInList(block); 00307 previous=PreviousBlockInList(block); 00308 if (previous == (void *) NULL) 00309 memory_info.blocks[i]=next; 00310 else 00311 NextBlockInList(previous)=next; 00312 if (next != (void *) NULL) 00313 PreviousBlockInList(next)=previous; 00314 } 00315 00316 static void *AcquireBlock(size_t size) 00317 { 00318 register size_t 00319 i; 00320 00321 register void 00322 *block; 00323 00324 /* 00325 Find free block. 00326 */ 00327 size=(size_t) (size+sizeof(size_t)+6*sizeof(size_t)-1) & -(4U*sizeof(size_t)); 00328 i=AllocationPolicy(size); 00329 block=memory_info.blocks[i]; 00330 while ((block != (void *) NULL) && (SizeOfBlock(block) < size)) 00331 block=NextBlockInList(block); 00332 if (block == (void *) NULL) 00333 { 00334 i++; 00335 while (memory_info.blocks[i] == (void *) NULL) 00336 i++; 00337 block=memory_info.blocks[i]; 00338 if (i >= MaxBlocks) 00339 return((void *) NULL); 00340 } 00341 assert((*BlockHeader(NextBlock(block)) & PreviousBlockBit) == 0); 00342 assert(SizeOfBlock(block) >= size); 00343 RemoveFreeBlock(block,AllocationPolicy(SizeOfBlock(block))); 00344 if (SizeOfBlock(block) > size) 00345 { 00346 size_t 00347 blocksize; 00348 00349 void 00350 *next; 00351 00352 /* 00353 Split block. 00354 */ 00355 next=(char *) block+size; 00356 blocksize=SizeOfBlock(block)-size; 00357 *BlockHeader(next)=blocksize; 00358 *BlockFooter(next,blocksize)=blocksize; 00359 InsertFreeBlock(next,AllocationPolicy(blocksize)); 00360 *BlockHeader(block)=size | (*BlockHeader(block) & ~SizeMask); 00361 } 00362 assert(size == SizeOfBlock(block)); 00363 *BlockHeader(NextBlock(block))|=PreviousBlockBit; 00364 memory_info.allocation+=size; 00365 return(block); 00366 } 00367 #endif 00368 00369 /* 00370 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00371 % % 00372 % % 00373 % % 00374 % A c q u i r e M a g i c k M e m o r y % 00375 % % 00376 % % 00377 % % 00378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00379 % 00380 % AcquireMagickMemory() returns a pointer to a block of memory at least size 00381 % bytes suitably aligned for any use. 00382 % 00383 % The format of the AcquireMagickMemory method is: 00384 % 00385 % void *AcquireMagickMemory(const size_t size) 00386 % 00387 % A description of each parameter follows: 00388 % 00389 % o size: the size of the memory in bytes to allocate. 00390 % 00391 */ 00392 MagickExport void *AcquireMagickMemory(const size_t size) 00393 { 00394 register void 00395 *memory; 00396 00397 #if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT) 00398 memory=memory_methods.acquire_memory_handler(size == 0 ? 1UL : size); 00399 #else 00400 if (memory_semaphore == (SemaphoreInfo *) NULL) 00401 AcquireSemaphoreInfo(&memory_semaphore); 00402 if (free_segments == (DataSegmentInfo *) NULL) 00403 { 00404 LockSemaphoreInfo(memory_semaphore); 00405 if (free_segments == (DataSegmentInfo *) NULL) 00406 { 00407 register ssize_t 00408 i; 00409 00410 assert(2*sizeof(size_t) > (size_t) (~SizeMask)); 00411 (void) ResetMagickMemory(&memory_info,0,sizeof(memory_info)); 00412 memory_info.allocation=SegmentSize; 00413 memory_info.blocks[MaxBlocks]=(void *) (-1); 00414 for (i=0; i < MaxSegments; i++) 00415 { 00416 if (i != 0) 00417 memory_info.segment_pool[i].previous= 00418 (&memory_info.segment_pool[i-1]); 00419 if (i != (MaxSegments-1)) 00420 memory_info.segment_pool[i].next=(&memory_info.segment_pool[i+1]); 00421 } 00422 free_segments=(&memory_info.segment_pool[0]); 00423 } 00424 UnlockSemaphoreInfo(memory_semaphore); 00425 } 00426 LockSemaphoreInfo(memory_semaphore); 00427 memory=AcquireBlock(size == 0 ? 1UL : size); 00428 if (memory == (void *) NULL) 00429 { 00430 if (ExpandHeap(size == 0 ? 1UL : size) != MagickFalse) 00431 memory=AcquireBlock(size == 0 ? 1UL : size); 00432 } 00433 UnlockSemaphoreInfo(memory_semaphore); 00434 #endif 00435 return(memory); 00436 } 00437 00438 /* 00439 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00440 % % 00441 % % 00442 % % 00443 % A c q u i r e Q u a n t u m M e m o r y % 00444 % % 00445 % % 00446 % % 00447 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00448 % 00449 % AcquireQuantumMemory() returns a pointer to a block of memory at least 00450 % count * quantum bytes suitably aligned for any use. 00451 % 00452 % The format of the AcquireQuantumMemory method is: 00453 % 00454 % void *AcquireQuantumMemory(const size_t count,const size_t quantum) 00455 % 00456 % A description of each parameter follows: 00457 % 00458 % o count: the number of quantum elements to allocate. 00459 % 00460 % o quantum: the number of bytes in each quantum. 00461 % 00462 */ 00463 MagickExport void *AcquireQuantumMemory(const size_t count,const size_t quantum) 00464 { 00465 size_t 00466 size; 00467 00468 size=count*quantum; 00469 if ((count == 0) || (quantum != (size/count))) 00470 { 00471 errno=ENOMEM; 00472 return((void *) NULL); 00473 } 00474 return(AcquireMagickMemory(size)); 00475 } 00476 00477 /* 00478 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00479 % % 00480 % % 00481 % % 00482 % C o p y M a g i c k M e m o r y % 00483 % % 00484 % % 00485 % % 00486 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00487 % 00488 % CopyMagickMemory() copies size bytes from memory area source to the 00489 % destination. Copying between objects that overlap will take place 00490 % correctly. It returns destination. 00491 % 00492 % The format of the CopyMagickMemory method is: 00493 % 00494 % void *CopyMagickMemory(void *destination,const void *source, 00495 % const size_t size) 00496 % 00497 % A description of each parameter follows: 00498 % 00499 % o destination: the destination. 00500 % 00501 % o source: the source. 00502 % 00503 % o size: the size of the memory in bytes to allocate. 00504 % 00505 */ 00506 MagickExport void *CopyMagickMemory(void *destination,const void *source, 00507 const size_t size) 00508 { 00509 register const unsigned char 00510 *p; 00511 00512 register unsigned char 00513 *q; 00514 00515 assert(destination != (void *) NULL); 00516 assert(source != (const void *) NULL); 00517 p=(const unsigned char *) source; 00518 q=(unsigned char *) destination; 00519 if (((q+size) < p) || (q > (p+size))) 00520 switch (size) 00521 { 00522 default: return(memcpy(destination,source,size)); 00523 case 8: *q++=(*p++); 00524 case 7: *q++=(*p++); 00525 case 6: *q++=(*p++); 00526 case 5: *q++=(*p++); 00527 case 4: *q++=(*p++); 00528 case 3: *q++=(*p++); 00529 case 2: *q++=(*p++); 00530 case 1: *q++=(*p++); 00531 case 0: return(destination); 00532 } 00533 return(memmove(destination,source,size)); 00534 } 00535 00536 /* 00537 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00538 % % 00539 % % 00540 % % 00541 + D e s t r o y M a g i c k M e m o r y % 00542 % % 00543 % % 00544 % % 00545 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00546 % 00547 % DestroyMagickMemory() deallocates memory associated with the memory manager. 00548 % 00549 % The format of the DestroyMagickMemory method is: 00550 % 00551 % DestroyMagickMemory(void) 00552 % 00553 */ 00554 MagickExport void DestroyMagickMemory(void) 00555 { 00556 #if defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT) 00557 register ssize_t 00558 i; 00559 00560 if (memory_semaphore == (SemaphoreInfo *) NULL) 00561 AcquireSemaphoreInfo(&memory_semaphore); 00562 LockSemaphoreInfo(memory_semaphore); 00563 UnlockSemaphoreInfo(memory_semaphore); 00564 for (i=0; i < (ssize_t) memory_info.number_segments; i++) 00565 if (memory_info.segments[i]->mapped == MagickFalse) 00566 memory_methods.destroy_memory_handler( 00567 memory_info.segments[i]->allocation); 00568 else 00569 (void) UnmapBlob(memory_info.segments[i]->allocation, 00570 memory_info.segments[i]->length); 00571 free_segments=(DataSegmentInfo *) NULL; 00572 (void) ResetMagickMemory(&memory_info,0,sizeof(memory_info)); 00573 DestroySemaphoreInfo(&memory_semaphore); 00574 #endif 00575 } 00576 00577 #if defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT) 00578 /* 00579 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00580 % % 00581 % % 00582 % % 00583 + E x p a n d H e a p % 00584 % % 00585 % % 00586 % % 00587 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00588 % 00589 % ExpandHeap() get more memory from the system. It returns MagickTrue on 00590 % success otherwise MagickFalse. 00591 % 00592 % The format of the ExpandHeap method is: 00593 % 00594 % MagickBooleanType ExpandHeap(size_t size) 00595 % 00596 % A description of each parameter follows: 00597 % 00598 % o size: the size of the memory in bytes we require. 00599 % 00600 */ 00601 static MagickBooleanType ExpandHeap(size_t size) 00602 { 00603 DataSegmentInfo 00604 *segment_info; 00605 00606 MagickBooleanType 00607 mapped; 00608 00609 register ssize_t 00610 i; 00611 00612 register void 00613 *block; 00614 00615 size_t 00616 blocksize; 00617 00618 void 00619 *segment; 00620 00621 blocksize=((size+12*sizeof(size_t))+SegmentSize-1) & -SegmentSize; 00622 assert(memory_info.number_segments < MaxSegments); 00623 segment=MapBlob(-1,IOMode,0,blocksize); 00624 mapped=segment != (void *) NULL ? MagickTrue : MagickFalse; 00625 if (segment == (void *) NULL) 00626 segment=(void *) memory_methods.acquire_memory_handler(blocksize); 00627 if (segment == (void *) NULL) 00628 return(MagickFalse); 00629 segment_info=(DataSegmentInfo *) free_segments; 00630 free_segments=segment_info->next; 00631 segment_info->mapped=mapped; 00632 segment_info->length=blocksize; 00633 segment_info->allocation=segment; 00634 segment_info->bound=(char *) segment+blocksize; 00635 i=(ssize_t) memory_info.number_segments-1; 00636 for ( ; (i >= 0) && (memory_info.segments[i]->allocation > segment); i--) 00637 memory_info.segments[i+1]=memory_info.segments[i]; 00638 memory_info.segments[i+1]=segment_info; 00639 memory_info.number_segments++; 00640 size=blocksize-12*sizeof(size_t); 00641 block=(char *) segment_info->allocation+4*sizeof(size_t); 00642 *BlockHeader(block)=size | PreviousBlockBit; 00643 *BlockFooter(block,size)=size; 00644 InsertFreeBlock(block,AllocationPolicy(size)); 00645 block=NextBlock(block); 00646 assert(block < segment_info->bound); 00647 *BlockHeader(block)=2*sizeof(size_t); 00648 *BlockHeader(NextBlock(block))=PreviousBlockBit; 00649 return(MagickTrue); 00650 } 00651 #endif 00652 00653 /* 00654 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00655 % % 00656 % % 00657 % % 00658 % G e t M a g i c k M e m o r y M e t h o d s % 00659 % % 00660 % % 00661 % % 00662 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00663 % 00664 % GetMagickMemoryMethods() gets the methods to acquire, resize, and destroy 00665 % memory. 00666 % 00667 % The format of the GetMagickMemoryMethods() method is: 00668 % 00669 % void GetMagickMemoryMethods(AcquireMemoryHandler *acquire_memory_handler, 00670 % ResizeMemoryHandler *resize_memory_handler, 00671 % DestroyMemoryHandler *destroy_memory_handler) 00672 % 00673 % A description of each parameter follows: 00674 % 00675 % o acquire_memory_handler: method to acquire memory (e.g. malloc). 00676 % 00677 % o resize_memory_handler: method to resize memory (e.g. realloc). 00678 % 00679 % o destroy_memory_handler: method to destroy memory (e.g. free). 00680 % 00681 */ 00682 MagickExport void GetMagickMemoryMethods( 00683 AcquireMemoryHandler *acquire_memory_handler, 00684 ResizeMemoryHandler *resize_memory_handler, 00685 DestroyMemoryHandler *destroy_memory_handler) 00686 { 00687 assert(acquire_memory_handler != (AcquireMemoryHandler *) NULL); 00688 assert(resize_memory_handler != (ResizeMemoryHandler *) NULL); 00689 assert(destroy_memory_handler != (DestroyMemoryHandler *) NULL); 00690 *acquire_memory_handler=memory_methods.acquire_memory_handler; 00691 *resize_memory_handler=memory_methods.resize_memory_handler; 00692 *destroy_memory_handler=memory_methods.destroy_memory_handler; 00693 } 00694 00695 /* 00696 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00697 % % 00698 % % 00699 % % 00700 % R e l i n q u i s h A l i g n e d M e m o r y % 00701 % % 00702 % % 00703 % % 00704 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00705 % 00706 % RelinquishAlignedMemory() frees memory acquired with AcquireAlignedMemory() 00707 % or reuse. 00708 % 00709 % The format of the RelinquishAlignedMemory method is: 00710 % 00711 % void *RelinquishAlignedMemory(void *memory) 00712 % 00713 % A description of each parameter follows: 00714 % 00715 % o memory: A pointer to a block of memory to free for reuse. 00716 % 00717 */ 00718 MagickExport void *RelinquishAlignedMemory(void *memory) 00719 { 00720 if (memory == (void *) NULL) 00721 return((void *) NULL); 00722 free(memory); 00723 return((void *) NULL); 00724 } 00725 00726 /* 00727 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00728 % % 00729 % % 00730 % % 00731 % R e l i n q u i s h M a g i c k M e m o r y % 00732 % % 00733 % % 00734 % % 00735 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00736 % 00737 % RelinquishMagickMemory() frees memory acquired with AcquireMagickMemory() 00738 % or AcquireQuantumMemory() for reuse. 00739 % 00740 % The format of the RelinquishMagickMemory method is: 00741 % 00742 % void *RelinquishMagickMemory(void *memory) 00743 % 00744 % A description of each parameter follows: 00745 % 00746 % o memory: A pointer to a block of memory to free for reuse. 00747 % 00748 */ 00749 MagickExport void *RelinquishMagickMemory(void *memory) 00750 { 00751 if (memory == (void *) NULL) 00752 return((void *) NULL); 00753 #if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT) 00754 memory_methods.destroy_memory_handler(memory); 00755 #else 00756 LockSemaphoreInfo(memory_semaphore); 00757 assert((SizeOfBlock(memory) % (4*sizeof(size_t))) == 0); 00758 assert((*BlockHeader(NextBlock(memory)) & PreviousBlockBit) != 0); 00759 if ((*BlockHeader(memory) & PreviousBlockBit) == 0) 00760 { 00761 void 00762 *previous; 00763 00764 /* 00765 Coalesce with previous adjacent block. 00766 */ 00767 previous=PreviousBlock(memory); 00768 RemoveFreeBlock(previous,AllocationPolicy(SizeOfBlock(previous))); 00769 *BlockHeader(previous)=(SizeOfBlock(previous)+SizeOfBlock(memory)) | 00770 (*BlockHeader(previous) & ~SizeMask); 00771 memory=previous; 00772 } 00773 if ((*BlockHeader(NextBlock(NextBlock(memory))) & PreviousBlockBit) == 0) 00774 { 00775 void 00776 *next; 00777 00778 /* 00779 Coalesce with next adjacent block. 00780 */ 00781 next=NextBlock(memory); 00782 RemoveFreeBlock(next,AllocationPolicy(SizeOfBlock(next))); 00783 *BlockHeader(memory)=(SizeOfBlock(memory)+SizeOfBlock(next)) | 00784 (*BlockHeader(memory) & ~SizeMask); 00785 } 00786 *BlockFooter(memory,SizeOfBlock(memory))=SizeOfBlock(memory); 00787 *BlockHeader(NextBlock(memory))&=(~PreviousBlockBit); 00788 InsertFreeBlock(memory,AllocationPolicy(SizeOfBlock(memory))); 00789 UnlockSemaphoreInfo(memory_semaphore); 00790 #endif 00791 return((void *) NULL); 00792 } 00793 00794 /* 00795 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00796 % % 00797 % % 00798 % % 00799 % R e s e t M a g i c k M e m o r y % 00800 % % 00801 % % 00802 % % 00803 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00804 % 00805 % ResetMagickMemory() fills the first size bytes of the memory area pointed to 00806 % by memory with the constant byte c. 00807 % 00808 % The format of the ResetMagickMemory method is: 00809 % 00810 % void *ResetMagickMemory(void *memory,int byte,const size_t size) 00811 % 00812 % A description of each parameter follows: 00813 % 00814 % o memory: A pointer to a memory allocation. 00815 % 00816 % o byte: Set the memory to this value. 00817 % 00818 % o size: Size of the memory to reset. 00819 % 00820 */ 00821 MagickExport void *ResetMagickMemory(void *memory,int byte,const size_t size) 00822 { 00823 assert(memory != (void *) NULL); 00824 return(memset(memory,byte,size)); 00825 } 00826 00827 /* 00828 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00829 % % 00830 % % 00831 % % 00832 % R e s i z e M a g i c k M e m o r y % 00833 % % 00834 % % 00835 % % 00836 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00837 % 00838 % ResizeMagickMemory() changes the size of the memory and returns a pointer to 00839 % the (possibly moved) block. The contents will be unchanged up to the 00840 % lesser of the new and old sizes. 00841 % 00842 % The format of the ResizeMagickMemory method is: 00843 % 00844 % void *ResizeMagickMemory(void *memory,const size_t size) 00845 % 00846 % A description of each parameter follows: 00847 % 00848 % o memory: A pointer to a memory allocation. 00849 % 00850 % o size: the new size of the allocated memory. 00851 % 00852 */ 00853 00854 #if defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT) 00855 static inline void *ResizeBlock(void *block,size_t size) 00856 { 00857 register void 00858 *memory; 00859 00860 if (block == (void *) NULL) 00861 return(AcquireBlock(size)); 00862 memory=AcquireBlock(size); 00863 if (memory == (void *) NULL) 00864 return((void *) NULL); 00865 if (size <= (SizeOfBlock(block)-sizeof(size_t))) 00866 (void) memcpy(memory,block,size); 00867 else 00868 (void) memcpy(memory,block,SizeOfBlock(block)-sizeof(size_t)); 00869 memory_info.allocation+=size; 00870 return(memory); 00871 } 00872 #endif 00873 00874 MagickExport void *ResizeMagickMemory(void *memory,const size_t size) 00875 { 00876 register void 00877 *block; 00878 00879 if (memory == (void *) NULL) 00880 return(AcquireMagickMemory(size)); 00881 #if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT) 00882 block=memory_methods.resize_memory_handler(memory,size == 0 ? 1UL : size); 00883 if (block == (void *) NULL) 00884 memory=RelinquishMagickMemory(memory); 00885 #else 00886 LockSemaphoreInfo(memory_semaphore); 00887 block=ResizeBlock(memory,size == 0 ? 1UL : size); 00888 if (block == (void *) NULL) 00889 { 00890 if (ExpandHeap(size == 0 ? 1UL : size) == MagickFalse) 00891 { 00892 UnlockSemaphoreInfo(memory_semaphore); 00893 memory=RelinquishMagickMemory(memory); 00894 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 00895 } 00896 block=ResizeBlock(memory,size == 0 ? 1UL : size); 00897 assert(block != (void *) NULL); 00898 } 00899 UnlockSemaphoreInfo(memory_semaphore); 00900 memory=RelinquishMagickMemory(memory); 00901 #endif 00902 return(block); 00903 } 00904 00905 /* 00906 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00907 % % 00908 % % 00909 % % 00910 % R e s i z e Q u a n t u m M e m o r y % 00911 % % 00912 % % 00913 % % 00914 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00915 % 00916 % ResizeQuantumMemory() changes the size of the memory and returns a pointer 00917 % to the (possibly moved) block. The contents will be unchanged up to the 00918 % lesser of the new and old sizes. 00919 % 00920 % The format of the ResizeQuantumMemory method is: 00921 % 00922 % void *ResizeQuantumMemory(void *memory,const size_t count, 00923 % const size_t quantum) 00924 % 00925 % A description of each parameter follows: 00926 % 00927 % o memory: A pointer to a memory allocation. 00928 % 00929 % o count: the number of quantum elements to allocate. 00930 % 00931 % o quantum: the number of bytes in each quantum. 00932 % 00933 */ 00934 MagickExport void *ResizeQuantumMemory(void *memory,const size_t count, 00935 const size_t quantum) 00936 { 00937 size_t 00938 size; 00939 00940 size=count*quantum; 00941 if ((count == 0) || (quantum != (size/count))) 00942 { 00943 memory=RelinquishMagickMemory(memory); 00944 errno=ENOMEM; 00945 return((void *) NULL); 00946 } 00947 return(ResizeMagickMemory(memory,size)); 00948 } 00949 00950 /* 00951 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00952 % % 00953 % % 00954 % % 00955 % S e t M a g i c k M e m o r y M e t h o d s % 00956 % % 00957 % % 00958 % % 00959 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00960 % 00961 % SetMagickMemoryMethods() sets the methods to acquire, resize, and destroy 00962 % memory. 00963 % 00964 % The format of the SetMagickMemoryMethods() method is: 00965 % 00966 % SetMagickMemoryMethods(AcquireMemoryHandler acquire_memory_handler, 00967 % ResizeMemoryHandler resize_memory_handler, 00968 % DestroyMemoryHandler destroy_memory_handler) 00969 % 00970 % A description of each parameter follows: 00971 % 00972 % o acquire_memory_handler: method to acquire memory (e.g. malloc). 00973 % 00974 % o resize_memory_handler: method to resize memory (e.g. realloc). 00975 % 00976 % o destroy_memory_handler: method to destroy memory (e.g. free). 00977 % 00978 */ 00979 MagickExport void SetMagickMemoryMethods( 00980 AcquireMemoryHandler acquire_memory_handler, 00981 ResizeMemoryHandler resize_memory_handler, 00982 DestroyMemoryHandler destroy_memory_handler) 00983 { 00984 /* 00985 Set memory methods. 00986 */ 00987 if (acquire_memory_handler != (AcquireMemoryHandler) NULL) 00988 memory_methods.acquire_memory_handler=acquire_memory_handler; 00989 if (resize_memory_handler != (ResizeMemoryHandler) NULL) 00990 memory_methods.resize_memory_handler=resize_memory_handler; 00991 if (destroy_memory_handler != (DestroyMemoryHandler) NULL) 00992 memory_methods.destroy_memory_handler=destroy_memory_handler; 00993 }