WizardsToolkit  1.0.7
memory.c
Go to the documentation of this file.
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 %                 The Wizard's Toolkit Memory Allocation Methods              %
00014 %                                                                             %
00015 %                              Software Design                                %
00016 %                                John Cristy                                  %
00017 %                                 July 1998                                   %
00018 %                                                                             %
00019 %                                                                             %
00020 %  Copyright 1999-2011 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.wizards-toolkit.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 WIZARDSTOOLKIT_EMBEDDABLE_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 "wizard/studio.h"
00057 #include "wizard/blob.h"
00058 #include "wizard/blob-private.h"
00059 #include "wizard/exception.h"
00060 #include "wizard/exception-private.h"
00061 #include "wizard/memory_.h"
00062 #include "wizard/semaphore.h"
00063 #include "wizard/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   WizardBooleanType
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 _WizardMemoryMethods
00124 {
00125   AcquireMemoryHandler
00126     acquire_memory_handler;
00127 
00128   ResizeMemoryHandler
00129     resize_memory_handler;
00130 
00131   DestroyMemoryHandler
00132     destroy_memory_handler;
00133 } WizardMemoryMethods;
00134 
00135 /*
00136   Global declarations.
00137 */
00138 static WizardMemoryMethods
00139   memory_methods =
00140   {
00141     (AcquireMemoryHandler) malloc,
00142     (ResizeMemoryHandler) realloc,
00143     (DestroyMemoryHandler) free
00144   };
00145 
00146 #if defined(WIZARDSTOOLKIT_EMBEDDABLE_SUPPORT)
00147 static MemoryInfo
00148   memory_info;
00149 
00150 static SemaphoreInfo
00151   *memory_semaphore = (SemaphoreInfo *) NULL;
00152 
00153 static volatile DataSegmentInfo
00154   *free_segments = (DataSegmentInfo *) NULL;
00155 
00156 /*
00157   Forward declarations.
00158 */
00159 static WizardBooleanType
00160   ExpandHeap(size_t);
00161 #endif
00162 
00163 /*
00164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00165 %                                                                             %
00166 %                                                                             %
00167 %                                                                             %
00168 %   A c q u i r e A l i g n e d M e m o r y                                   %
00169 %                                                                             %
00170 %                                                                             %
00171 %                                                                             %
00172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00173 %
00174 %  AcquireAlignedMemory() returns a pointer to a block of memory at least size
00175 %  bytes whose address is a multiple of 16*sizeof(void *).
00176 %
00177 %  The format of the AcquireAlignedMemory method is:
00178 %
00179 %      void *AcquireAlignedMemory(const size_t count,const size_t quantum)
00180 %
00181 %  A description of each parameter follows:
00182 %
00183 %    o count: the number of quantum elements to allocate.
00184 %
00185 %    o quantum: the number of bytes in each quantum.
00186 %
00187 */
00188 
00189 static inline size_t WizardMax(const size_t x,const size_t y)
00190 {
00191   if (x > y)
00192     return(x);
00193   return(y);
00194 }
00195 
00196 WizardExport void *AcquireAlignedMemory(const size_t count,const size_t quantum)
00197 {
00198   size_t
00199     size;
00200 
00201   size=count*quantum;
00202   if ((count == 0) || (quantum != (size/count)))
00203     {
00204       errno=ENOMEM;
00205       return((void *) NULL);
00206     }
00207 #if defined(WIZARDSTOOLKIT_HAVE_POSIX_MEMALIGN)
00208   {
00209     void
00210       *memory;
00211 
00212     if (posix_memalign(&memory,AlignedSize,WizardMax(size,AlignedSize)) == 0)
00213       return(memory);
00214   }
00215 #endif
00216   return(malloc(WizardMax(size,AlignedSize)));
00217 }
00218 
00219 #if defined(WIZARDSTOOLKIT_EMBEDDABLE_SUPPORT)
00220 /*
00221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00222 %                                                                             %
00223 %                                                                             %
00224 %                                                                             %
00225 +   A c q u i r e B l o c k                                                   %
00226 %                                                                             %
00227 %                                                                             %
00228 %                                                                             %
00229 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00230 %
00231 %  AcquireBlock() returns a pointer to a block of memory at least size bytes
00232 %  suitably aligned for any use.
00233 %
00234 %  The format of the AcquireBlock method is:
00235 %
00236 %      void *AcquireBlock(const size_t size)
00237 %
00238 %  A description of each parameter follows:
00239 %
00240 %    o size: the size of the memory in bytes to allocate.
00241 %
00242 */
00243 
00244 static inline size_t AllocationPolicy(size_t size)
00245 {
00246   register size_t
00247     blocksize;
00248 
00249   /*
00250     The linear distribution.
00251   */
00252   assert(size != 0);
00253   assert(size % (4*sizeof(size_t)) == 0);
00254   if (size <= BlockThreshold)
00255     return(size/(4*sizeof(size_t)));
00256   /*
00257     Check for the largest block size.
00258   */
00259   if (size > (size_t) (BlockThreshold*(1L << (MaxBlockExponent-1L))))
00260     return(MaxBlocks-1L);
00261   /*
00262     Otherwise use a power of two distribution.
00263   */
00264   blocksize=BlockThreshold/(4*sizeof(size_t));
00265   for ( ; size > BlockThreshold; size/=2)
00266     blocksize++;
00267   assert(blocksize > (BlockThreshold/(4*sizeof(size_t))));
00268   assert(blocksize < (MaxBlocks-1L));
00269   return(blocksize);
00270 }
00271 
00272 static inline void InsertFreeBlock(void *block,const size_t i)
00273 {
00274   register void
00275     *next,
00276     *previous;
00277 
00278   size_t
00279     size;
00280 
00281   size=SizeOfBlock(block);
00282   previous=(void *) NULL;
00283   next=memory_info.blocks[i];
00284   while ((next != (void *) NULL) && (SizeOfBlock(next) < size))
00285   {
00286     previous=next;
00287     next=NextBlockInList(next);
00288   }
00289   PreviousBlockInList(block)=previous;
00290   NextBlockInList(block)=next;
00291   if (previous != (void *) NULL)
00292     NextBlockInList(previous)=block;
00293   else
00294     memory_info.blocks[i]=block;
00295   if (next != (void *) NULL)
00296     PreviousBlockInList(next)=block;
00297 }
00298 
00299 static inline void RemoveFreeBlock(void *block,const size_t i)
00300 {
00301   register void
00302     *next,
00303     *previous;
00304 
00305   next=NextBlockInList(block);
00306   previous=PreviousBlockInList(block);
00307   if (previous == (void *) NULL)
00308     memory_info.blocks[i]=next;
00309   else
00310     NextBlockInList(previous)=next;
00311   if (next != (void *) NULL)
00312     PreviousBlockInList(next)=previous;
00313 }
00314 
00315 static void *AcquireBlock(size_t size)
00316 {
00317   register size_t
00318     i;
00319 
00320   register void
00321     *block;
00322 
00323   /*
00324     Find free block.
00325   */
00326   size=(size_t) (size+sizeof(size_t)+6*sizeof(size_t)-1) & -(4U*sizeof(size_t));
00327   i=AllocationPolicy(size);
00328   block=memory_info.blocks[i];
00329   while ((block != (void *) NULL) && (SizeOfBlock(block) < size))
00330     block=NextBlockInList(block);
00331   if (block == (void *) NULL)
00332     {
00333       i++;
00334       while (memory_info.blocks[i] == (void *) NULL)
00335         i++;
00336       block=memory_info.blocks[i];
00337       if (i >= MaxBlocks)
00338         return((void *) NULL);
00339     }
00340   assert((*BlockHeader(NextBlock(block)) & PreviousBlockBit) == 0);
00341   assert(SizeOfBlock(block) >= size);
00342   RemoveFreeBlock(block,AllocationPolicy(SizeOfBlock(block)));
00343   if (SizeOfBlock(block) > size)
00344     {
00345       size_t
00346         blocksize;
00347 
00348       void
00349         *next;
00350 
00351       /*
00352         Split block.
00353       */
00354       next=(char *) block+size;
00355       blocksize=SizeOfBlock(block)-size;
00356       *BlockHeader(next)=blocksize;
00357       *BlockFooter(next,blocksize)=blocksize;
00358       InsertFreeBlock(next,AllocationPolicy(blocksize));
00359       *BlockHeader(block)=size | (*BlockHeader(block) & ~SizeMask);
00360     }
00361   assert(size == SizeOfBlock(block));
00362   *BlockHeader(NextBlock(block))|=PreviousBlockBit;
00363   memory_info.allocation+=size;
00364   return(block);
00365 }
00366 #endif
00367 
00368 /*
00369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00370 %                                                                             %
00371 %                                                                             %
00372 %                                                                             %
00373 %   A c q u i r e W i z a r d M e m o r y                                     %
00374 %                                                                             %
00375 %                                                                             %
00376 %                                                                             %
00377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00378 %
00379 %  AcquireWizardMemory() returns a pointer to a block of memory at least size
00380 %  bytes suitably aligned for any use.
00381 %
00382 %  The format of the AcquireWizardMemory method is:
00383 %
00384 %      void *AcquireWizardMemory(const size_t size)
00385 %
00386 %  A description of each parameter follows:
00387 %
00388 %    o size: the size of the memory in bytes to allocate.
00389 %
00390 */
00391 WizardExport void *AcquireWizardMemory(const size_t size)
00392 {
00393   register void
00394     *memory;
00395 
00396 #if !defined(WIZARDSTOOLKIT_EMBEDDABLE_SUPPORT)
00397   memory=memory_methods.acquire_memory_handler(size == 0 ? 1UL : size);
00398 #else
00399   if (memory_semaphore == (SemaphoreInfo *) NULL)
00400     AcquireSemaphoreInfo(&memory_semaphore);
00401   if (free_segments == (DataSegmentInfo *) NULL)
00402     {
00403       LockSemaphoreInfo(memory_semaphore);
00404       if (free_segments == (DataSegmentInfo *) NULL)
00405         {
00406           register ssize_t
00407             i;
00408 
00409           assert(2*sizeof(size_t) > (size_t) (~SizeMask));
00410           (void) ResetWizardMemory(&memory_info,0,sizeof(memory_info));
00411           memory_info.allocation=SegmentSize;
00412           memory_info.blocks[MaxBlocks]=(void *) (-1);
00413           for (i=0; i < MaxSegments; i++)
00414           {
00415             if (i != 0)
00416               memory_info.segment_pool[i].previous=
00417                 (&memory_info.segment_pool[i-1]);
00418             if (i != (MaxSegments-1))
00419               memory_info.segment_pool[i].next=(&memory_info.segment_pool[i+1]);
00420           }
00421           free_segments=(&memory_info.segment_pool[0]);
00422         }
00423       UnlockSemaphoreInfo(memory_semaphore);
00424     }
00425   LockSemaphoreInfo(memory_semaphore);
00426   memory=AcquireBlock(size == 0 ? 1UL : size);
00427   if (memory == (void *) NULL)
00428     {
00429       if (ExpandHeap(size == 0 ? 1UL : size) != WizardFalse)
00430         memory=AcquireBlock(size == 0 ? 1UL : size);
00431     }
00432   UnlockSemaphoreInfo(memory_semaphore);
00433 #endif
00434   return(memory);
00435 }
00436 
00437 /*
00438 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00439 %                                                                             %
00440 %                                                                             %
00441 %                                                                             %
00442 %   A c q u i r e Q u a n t u m M e m o r y                                   %
00443 %                                                                             %
00444 %                                                                             %
00445 %                                                                             %
00446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00447 %
00448 %  AcquireQuantumMemory() returns a pointer to a block of memory at least
00449 %  count * quantum bytes suitably aligned for any use.
00450 %
00451 %  The format of the AcquireQuantumMemory method is:
00452 %
00453 %      void *AcquireQuantumMemory(const size_t count,const size_t quantum)
00454 %
00455 %  A description of each parameter follows:
00456 %
00457 %    o count: the number of quantum elements to allocate.
00458 %
00459 %    o quantum: the number of bytes in each quantum.
00460 %
00461 */
00462 WizardExport void *AcquireQuantumMemory(const size_t count,const size_t quantum)
00463 {
00464   size_t
00465     size;
00466 
00467   size=count*quantum;
00468   if ((count == 0) || (quantum != (size/count)))
00469     {
00470       errno=ENOMEM;
00471       return((void *) NULL);
00472     }
00473   return(AcquireWizardMemory(size));
00474 }
00475 
00476 /*
00477 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00478 %                                                                             %
00479 %                                                                             %
00480 %                                                                             %
00481 %   C o p y W i z a r d M e m o r y                                           %
00482 %                                                                             %
00483 %                                                                             %
00484 %                                                                             %
00485 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00486 %
00487 %  CopyWizardMemory() copies size bytes from memory area source to the
00488 %  destination.  Copying between objects that overlap will take place
00489 %  correctly.  It returns destination.
00490 %
00491 %  The format of the CopyWizardMemory method is:
00492 %
00493 %      void *CopyWizardMemory(void *destination,const void *source,
00494 %        const size_t size)
00495 %
00496 %  A description of each parameter follows:
00497 %
00498 %    o destination: the destination.
00499 %
00500 %    o source: the source.
00501 %
00502 %    o size: the size of the memory in bytes to allocate.
00503 %
00504 */
00505 WizardExport void *CopyWizardMemory(void *destination,const void *source,
00506   const size_t size)
00507 {
00508   register const unsigned char
00509     *p;
00510 
00511   register unsigned char
00512     *q;
00513 
00514   assert(destination != (void *) NULL);
00515   assert(source != (const void *) NULL);
00516   p=(const unsigned char *) source;
00517   q=(unsigned char *) destination;
00518   if (((q+size) < p) || (q > (p+size)))
00519     switch (size)
00520     {
00521       default: return(memcpy(destination,source,size));
00522       case 8: *q++=(*p++);
00523       case 7: *q++=(*p++);
00524       case 6: *q++=(*p++);
00525       case 5: *q++=(*p++);
00526       case 4: *q++=(*p++);
00527       case 3: *q++=(*p++);
00528       case 2: *q++=(*p++);
00529       case 1: *q++=(*p++);
00530       case 0: return(destination);
00531     }
00532   return(memmove(destination,source,size));
00533 }
00534 
00535 /*
00536 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00537 %                                                                             %
00538 %                                                                             %
00539 %                                                                             %
00540 +   D e s t r o y W i z a r d M e m o r y                                     %
00541 %                                                                             %
00542 %                                                                             %
00543 %                                                                             %
00544 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00545 %
00546 %  DestroyWizardMemory() deallocates memory associated with the memory manager.
00547 %
00548 %  The format of the DestroyWizardMemory method is:
00549 %
00550 %      DestroyWizardMemory(void)
00551 %
00552 */
00553 WizardExport void DestroyWizardMemory(void)
00554 {
00555 #if defined(WIZARDSTOOLKIT_EMBEDDABLE_SUPPORT)
00556   register ssize_t
00557     i;
00558 
00559   if (memory_semaphore == (SemaphoreInfo *) NULL)
00560     AcquireSemaphoreInfo(&memory_semaphore);
00561   LockSemaphoreInfo(memory_semaphore);
00562   UnlockSemaphoreInfo(memory_semaphore);
00563   for (i=0; i < (ssize_t) memory_info.number_segments; i++)
00564     if (memory_info.segments[i]->mapped == WizardFalse)
00565       memory_methods.destroy_memory_handler(
00566         memory_info.segments[i]->allocation);
00567     else
00568       (void) UnmapBlob(memory_info.segments[i]->allocation,
00569         memory_info.segments[i]->length);
00570   free_segments=(DataSegmentInfo *) NULL;
00571   (void) ResetWizardMemory(&memory_info,0,sizeof(memory_info));
00572   DestroySemaphoreInfo(&memory_semaphore);
00573 #endif
00574 }
00575 
00576 #if defined(WIZARDSTOOLKIT_EMBEDDABLE_SUPPORT)
00577 /*
00578 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00579 %                                                                             %
00580 %                                                                             %
00581 %                                                                             %
00582 +   E x p a n d H e a p                                                       %
00583 %                                                                             %
00584 %                                                                             %
00585 %                                                                             %
00586 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00587 %
00588 %  ExpandHeap() get more memory from the system.  It returns WizardTrue on
00589 %  success otherwise WizardFalse.
00590 %
00591 %  The format of the ExpandHeap method is:
00592 %
00593 %      WizardBooleanType ExpandHeap(size_t size)
00594 %
00595 %  A description of each parameter follows:
00596 %
00597 %    o size: the size of the memory in bytes we require.
00598 %
00599 */
00600 static WizardBooleanType ExpandHeap(size_t size)
00601 {
00602   DataSegmentInfo
00603     *segment_info;
00604 
00605   WizardBooleanType
00606     mapped;
00607 
00608   register ssize_t
00609     i;
00610 
00611   register void
00612     *block;
00613 
00614   size_t
00615     blocksize;
00616 
00617   void
00618     *segment;
00619 
00620   blocksize=((size+12*sizeof(size_t))+SegmentSize-1) & -SegmentSize;
00621   assert(memory_info.number_segments < MaxSegments);
00622   segment=MapBlob(-1,IOMode,0,blocksize);
00623   mapped=segment != (void *) NULL ? WizardTrue : WizardFalse;
00624   if (segment == (void *) NULL)
00625     segment=(void *) memory_methods.acquire_memory_handler(blocksize);
00626   if (segment == (void *) NULL)
00627     return(WizardFalse);
00628   segment_info=(DataSegmentInfo *) free_segments;
00629   free_segments=segment_info->next;
00630   segment_info->mapped=mapped;
00631   segment_info->length=blocksize;
00632   segment_info->allocation=segment;
00633   segment_info->bound=(char *) segment+blocksize;
00634   i=(ssize_t) memory_info.number_segments-1;
00635   for ( ; (i >= 0) && (memory_info.segments[i]->allocation > segment); i--)
00636     memory_info.segments[i+1]=memory_info.segments[i];
00637   memory_info.segments[i+1]=segment_info;
00638   memory_info.number_segments++;
00639   size=blocksize-12*sizeof(size_t);
00640   block=(char *) segment_info->allocation+4*sizeof(size_t);
00641   *BlockHeader(block)=size | PreviousBlockBit;
00642   *BlockFooter(block,size)=size;
00643   InsertFreeBlock(block,AllocationPolicy(size));
00644   block=NextBlock(block);
00645   assert(block < segment_info->bound);
00646   *BlockHeader(block)=2*sizeof(size_t);
00647   *BlockHeader(NextBlock(block))=PreviousBlockBit;
00648   return(WizardTrue);
00649 }
00650 #endif
00651 
00652 /*
00653 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00654 %                                                                             %
00655 %                                                                             %
00656 %                                                                             %
00657 %   G e t W i z a r d M e m o r y M e t h o d s                               %
00658 %                                                                             %
00659 %                                                                             %
00660 %                                                                             %
00661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00662 %
00663 %  GetWizardMemoryMethods() gets the methods to acquire, resize, and destroy
00664 %  memory.
00665 %
00666 %  The format of the GetWizardMemoryMethods() method is:
00667 %
00668 %      void GetWizardMemoryMethods(AcquireMemoryHandler *acquire_memory_handler,
00669 %        ResizeMemoryHandler *resize_memory_handler,
00670 %        DestroyMemoryHandler *destroy_memory_handler)
00671 %
00672 %  A description of each parameter follows:
00673 %
00674 %    o acquire_memory_handler: method to acquire memory (e.g. malloc).
00675 %
00676 %    o resize_memory_handler: method to resize memory (e.g. realloc).
00677 %
00678 %    o destroy_memory_handler: method to destroy memory (e.g. free).
00679 %
00680 */
00681 WizardExport void GetWizardMemoryMethods(
00682   AcquireMemoryHandler *acquire_memory_handler,
00683   ResizeMemoryHandler *resize_memory_handler,
00684   DestroyMemoryHandler *destroy_memory_handler)
00685 {
00686   assert(acquire_memory_handler != (AcquireMemoryHandler *) NULL);
00687   assert(resize_memory_handler != (ResizeMemoryHandler *) NULL);
00688   assert(destroy_memory_handler != (DestroyMemoryHandler *) NULL);
00689   *acquire_memory_handler=memory_methods.acquire_memory_handler;
00690   *resize_memory_handler=memory_methods.resize_memory_handler;
00691   *destroy_memory_handler=memory_methods.destroy_memory_handler;
00692 }
00693 
00694 /*
00695 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00696 %                                                                             %
00697 %                                                                             %
00698 %                                                                             %
00699 %   R e l i n q u i s h A l i g n e d M e m o r y                             %
00700 %                                                                             %
00701 %                                                                             %
00702 %                                                                             %
00703 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00704 %
00705 %  RelinquishAlignedMemory() frees memory acquired with AcquireAlignedMemory()
00706 %  or reuse.
00707 %
00708 %  The format of the RelinquishAlignedMemory method is:
00709 %
00710 %      void *RelinquishAlignedMemory(void *memory)
00711 %
00712 %  A description of each parameter follows:
00713 %
00714 %    o memory: A pointer to a block of memory to free for reuse.
00715 %
00716 */
00717 WizardExport void *RelinquishAlignedMemory(void *memory)
00718 {
00719   if (memory == (void *) NULL)
00720     return((void *) NULL);
00721   free(memory);
00722   return((void *) NULL);
00723 }
00724 
00725 /*
00726 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00727 %                                                                             %
00728 %                                                                             %
00729 %                                                                             %
00730 %   R e l i n q u i s h W i z a r d M e m o r y                               %
00731 %                                                                             %
00732 %                                                                             %
00733 %                                                                             %
00734 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00735 %
00736 %  RelinquishWizardMemory() zeros memory that has been allocated, frees it for
00737 %  reuse.
00738 %
00739 %  The format of the RelinquishWizardMemory method is:
00740 %
00741 %      void *RelinquishWizardMemory(void *memory)
00742 %
00743 %  A description of each parameter follows:
00744 %
00745 %    o memory: A pointer to a block of memory to free for reuse.
00746 %
00747 */
00748 WizardExport void *RelinquishWizardMemory(void *memory)
00749 {
00750   if (memory == (void *) NULL)
00751     return((void *) NULL);
00752 #if !defined(WIZARDSTOOLKIT_EMBEDDABLE_SUPPORT)
00753   memory_methods.destroy_memory_handler(memory);
00754 #else
00755   assert((SizeOfBlock(memory) % (4*sizeof(size_t))) == 0);
00756   assert((*BlockHeader(NextBlock(memory)) & PreviousBlockBit) != 0);
00757   LockSemaphoreInfo(memory_semaphore);
00758   if ((*BlockHeader(memory) & PreviousBlockBit) == 0)
00759     {
00760       void
00761         *previous;
00762 
00763       /*
00764         Coalesce with previous adjacent block.
00765       */
00766       previous=PreviousBlock(memory);
00767       RemoveFreeBlock(previous,AllocationPolicy(SizeOfBlock(previous)));
00768       *BlockHeader(previous)=(SizeOfBlock(previous)+SizeOfBlock(memory)) |
00769         (*BlockHeader(previous) & ~SizeMask);
00770       memory=previous;
00771     }
00772   if ((*BlockHeader(NextBlock(NextBlock(memory))) & PreviousBlockBit) == 0)
00773     {
00774       void
00775         *next;
00776 
00777       /*
00778         Coalesce with next adjacent block.
00779       */
00780       next=NextBlock(memory);
00781       RemoveFreeBlock(next,AllocationPolicy(SizeOfBlock(next)));
00782       *BlockHeader(memory)=(SizeOfBlock(memory)+SizeOfBlock(next)) |
00783         (*BlockHeader(memory) & ~SizeMask);
00784     }
00785   *BlockFooter(memory,SizeOfBlock(memory))=SizeOfBlock(memory);
00786   *BlockHeader(NextBlock(memory))&=(~PreviousBlockBit);
00787   InsertFreeBlock(memory,AllocationPolicy(SizeOfBlock(memory)));
00788   UnlockSemaphoreInfo(memory_semaphore);
00789 #endif
00790   return((void *) NULL);
00791 }
00792 
00793 /*
00794 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00795 %                                                                             %
00796 %                                                                             %
00797 %                                                                             %
00798 %   R e s e t W i z a r d M e m o r y                                         %
00799 %                                                                             %
00800 %                                                                             %
00801 %                                                                             %
00802 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00803 %
00804 %  ResetWizardMemory() fills the first size bytes of the memory area pointed to
00805 %  by memory with the constant byte c.
00806 %
00807 %  The format of the ResetWizardMemory method is:
00808 %
00809 %      void *ResetWizardMemory(void *memory,int byte,const size_t size)
00810 %
00811 %  A description of each parameter follows:
00812 %
00813 %    o memory: A pointer to a memory allocation.
00814 %
00815 %    o byte: Set the memory to this value.
00816 %
00817 %    o size: Size of the memory to reset.
00818 %
00819 */
00820 WizardExport void *ResetWizardMemory(void *memory,int byte,const size_t size)
00821 {
00822   assert(memory != (void *) NULL);
00823   return(memset(memory,byte,size));
00824 }
00825 
00826 /*
00827 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00828 %                                                                             %
00829 %                                                                             %
00830 %                                                                             %
00831 %   R e s i z e W i z a r d M e m o r y                                       %
00832 %                                                                             %
00833 %                                                                             %
00834 %                                                                             %
00835 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00836 %
00837 %  ResizeWizardMemory() changes the size of the memory and returns a pointer to
00838 %  the (possibly moved) block.  The contents will be unchanged up to the
00839 %  lesser of the new and old sizes.
00840 %
00841 %  The format of the ResizeWizardMemory method is:
00842 %
00843 %      void *ResizeWizardMemory(void *memory,const size_t size)
00844 %
00845 %  A description of each parameter follows:
00846 %
00847 %    o memory: A pointer to a memory allocation.
00848 %
00849 %    o size: the new size of the allocated memory.
00850 %
00851 */
00852 
00853 #if defined(WIZARDSTOOLKIT_EMBEDDABLE_SUPPORT)
00854 static inline void *ResizeBlock(void *block,size_t size)
00855 {
00856   register void
00857     *memory;
00858 
00859   if (block == (void *) NULL)
00860     return(AcquireBlock(size));
00861   memory=AcquireBlock(size);
00862   if (memory == (void *) NULL)
00863     return((void *) NULL);
00864   if (size <= (SizeOfBlock(block)-sizeof(size_t)))
00865     (void) memcpy(memory,block,size);
00866   else
00867     (void) memcpy(memory,block,SizeOfBlock(block)-sizeof(size_t));
00868   memory_info.allocation+=size;
00869   return(memory);
00870 }
00871 #endif
00872 
00873 WizardExport void *ResizeWizardMemory(void *memory,const size_t size)
00874 {
00875   register void
00876     *block;
00877 
00878   if (memory == (void *) NULL)
00879     return(AcquireWizardMemory(size));
00880 #if !defined(WIZARDSTOOLKIT_EMBEDDABLE_SUPPORT)
00881   block=memory_methods.resize_memory_handler(memory,size == 0 ? 1UL : size);
00882   if (block == (void *) NULL)
00883     memory=RelinquishWizardMemory(memory);
00884 #else
00885   LockSemaphoreInfo(memory_semaphore);
00886   block=ResizeBlock(memory,size == 0 ? 1UL : size);
00887   if (block == (void *) NULL)
00888     {
00889       if (ExpandHeap(size == 0 ? 1UL : size) == WizardFalse)
00890         {
00891           UnlockSemaphoreInfo(memory_semaphore);
00892           memory=RelinquishWizardMemory(memory);
00893           ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00894         }
00895       block=ResizeBlock(memory,size == 0 ? 1UL : size);
00896       assert(block != (void *) NULL);
00897     }
00898   UnlockSemaphoreInfo(memory_semaphore);
00899   memory=RelinquishWizardMemory(memory);
00900 #endif
00901   return(block);
00902 }
00903 
00904 /*
00905 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00906 %                                                                             %
00907 %                                                                             %
00908 %                                                                             %
00909 %   R e s i z e Q u a n t u m M e m o r y                                     %
00910 %                                                                             %
00911 %                                                                             %
00912 %                                                                             %
00913 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00914 %
00915 %  ResizeQuantumMemory() changes the size of the memory and returns a pointer
00916 %  to the (possibly moved) block.  The contents will be unchanged up to the
00917 %  lesser of the new and old sizes.
00918 %
00919 %  The format of the ResizeQuantumMemory method is:
00920 %
00921 %      void *ResizeQuantumMemory(void *memory,const size_t count,
00922 %        const size_t quantum)
00923 %
00924 %  A description of each parameter follows:
00925 %
00926 %    o memory: A pointer to a memory allocation.
00927 %
00928 %    o count: the number of quantum elements to allocate.
00929 %
00930 %    o quantum: the number of bytes in each quantum.
00931 %
00932 */
00933 WizardExport void *ResizeQuantumMemory(void *memory,const size_t count,
00934   const size_t quantum)
00935 {
00936   size_t
00937     size;
00938 
00939   size=count*quantum;
00940   if ((count == 0) || (quantum != (size/count)))
00941     {
00942       memory=RelinquishWizardMemory(memory);
00943       errno=ENOMEM;
00944       return((void *) NULL);
00945     }
00946   return(ResizeWizardMemory(memory,size));
00947 }
00948 
00949 /*
00950 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00951 %                                                                             %
00952 %                                                                             %
00953 %                                                                             %
00954 %   S e t W i z a r d M e m o r y M e t h o d s                               %
00955 %                                                                             %
00956 %                                                                             %
00957 %                                                                             %
00958 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00959 %
00960 %  SetWizardMemoryMethods() sets the methods to acquire, resize, and destroy
00961 %  memory.
00962 %
00963 %  The format of the SetWizardMemoryMethods() method is:
00964 %
00965 %      SetWizardMemoryMethods(AcquireMemoryHandler acquire_memory_handler,
00966 %        ResizeMemoryHandler resize_memory_handler,
00967 %        DestroyMemoryHandler destroy_memory_handler)
00968 %
00969 %  A description of each parameter follows:
00970 %
00971 %    o acquire_memory_handler: method to acquire memory (e.g. malloc).
00972 %
00973 %    o resize_memory_handler: method to resize memory (e.g. realloc).
00974 %
00975 %    o destroy_memory_handler: method to destroy memory (e.g. free).
00976 %
00977 */
00978 WizardExport void SetWizardMemoryMethods(
00979   AcquireMemoryHandler acquire_memory_handler,
00980   ResizeMemoryHandler resize_memory_handler,
00981   DestroyMemoryHandler destroy_memory_handler)
00982 {
00983   /*
00984     Set memory methods.
00985   */
00986   if (acquire_memory_handler != (AcquireMemoryHandler) NULL)
00987     memory_methods.acquire_memory_handler=acquire_memory_handler;
00988   if (resize_memory_handler != (ResizeMemoryHandler) NULL)
00989     memory_methods.resize_memory_handler=resize_memory_handler;
00990   if (destroy_memory_handler != (DestroyMemoryHandler) NULL)
00991     memory_methods.destroy_memory_handler=destroy_memory_handler;
00992 }