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