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