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