]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/memory.c
(no commit message)
[imagemagick] / MagickCore / memory.c
index e763fb1ed9977dbf4400731bd3b7eba90d001afa..1edb4ad96328af6cfe9e3faf2505183064983c63 100644 (file)
 %                     MagickCore Memory Allocation Methods                    %
 %                                                                             %
 %                              Software Design                                %
-%                                John Cristy                                  %
+%                                   Cristy                                    %
 %                                 July 1998                                   %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization      %
 %  dedicated to making software imaging solutions freely available.           %
 %                                                                             %
 %  You may not use this file except in compliance with the License.  You may  %
 #include "MagickCore/exception-private.h"
 #include "MagickCore/memory_.h"
 #include "MagickCore/memory-private.h"
+#include "MagickCore/resource_.h"
 #include "MagickCore/semaphore.h"
 #include "MagickCore/string_.h"
+#include "MagickCore/utility-private.h"
 \f
 /*
   Define declarations.
 /*
   Typedef declarations.
 */
+typedef enum
+{
+  UndefinedVirtualMemory,
+  AlignedVirtualMemory,
+  MapVirtualMemory,
+  UnalignedVirtualMemory
+} VirtualMemoryType;
+
 typedef struct _DataSegmentInfo
 {
   void
@@ -104,7 +114,37 @@ typedef struct _DataSegmentInfo
     *next;
 } DataSegmentInfo;
 
-typedef struct _MemoryInfo
+typedef struct _MagickMemoryMethods
+{
+  AcquireMemoryHandler
+    acquire_memory_handler;
+
+  ResizeMemoryHandler
+    resize_memory_handler;
+
+  DestroyMemoryHandler
+    destroy_memory_handler;
+} MagickMemoryMethods;
+
+struct _MemoryInfo
+{
+  char
+    filename[MaxTextExtent];
+
+  VirtualMemoryType
+    type;
+
+  size_t
+    length;
+
+  void
+    *blob;
+
+  size_t
+    signature;
+};
+
+typedef struct _MemoryPool
 {
   size_t
     allocation;
@@ -118,35 +158,42 @@ typedef struct _MemoryInfo
   DataSegmentInfo
     *segments[MaxSegments],
     segment_pool[MaxSegments];
-} MemoryInfo;
-
-typedef struct _MagickMemoryMethods
-{
-  AcquireMemoryHandler
-    acquire_memory_handler;
-
-  ResizeMemoryHandler
-    resize_memory_handler;
-
-  DestroyMemoryHandler
-    destroy_memory_handler;
-} MagickMemoryMethods;
-
+} MemoryPool;
 \f
 /*
   Global declarations.
 */
+#if defined _MSC_VER
+static void* MSCMalloc(size_t size)
+{
+  return malloc(size);
+}
+static void* MSCRealloc(void* ptr, size_t size)
+{
+  return realloc(ptr, size);
+}
+static void MSCFree(void* ptr)
+{
+  free(ptr);
+}
+#endif
+
 static MagickMemoryMethods
   memory_methods =
   {
+#if defined _MSC_VER
+    (AcquireMemoryHandler) MSCMalloc,
+    (ResizeMemoryHandler) MSCRealloc,
+    (DestroyMemoryHandler) MSCFree
+#else
     (AcquireMemoryHandler) malloc,
     (ResizeMemoryHandler) realloc,
     (DestroyMemoryHandler) free
+#endif
   };
-
 #if defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
-static MemoryInfo
-  memory_info;
+static MemoryPool
+  memory_pool;
 
 static SemaphoreInfo
   *memory_semaphore = (SemaphoreInfo *) NULL;
@@ -299,7 +346,7 @@ static inline void InsertFreeBlock(void *block,const size_t i)
 
   size=SizeOfBlock(block);
   previous=(void *) NULL;
-  next=memory_info.blocks[i];
+  next=memory_pool.blocks[i];
   while ((next != (void *) NULL) && (SizeOfBlock(next) < size))
   {
     previous=next;
@@ -310,7 +357,7 @@ static inline void InsertFreeBlock(void *block,const size_t i)
   if (previous != (void *) NULL)
     NextBlockInList(previous)=block;
   else
-    memory_info.blocks[i]=block;
+    memory_pool.blocks[i]=block;
   if (next != (void *) NULL)
     PreviousBlockInList(next)=block;
 }
@@ -324,7 +371,7 @@ static inline void RemoveFreeBlock(void *block,const size_t i)
   next=NextBlockInList(block);
   previous=PreviousBlockInList(block);
   if (previous == (void *) NULL)
-    memory_info.blocks[i]=next;
+    memory_pool.blocks[i]=next;
   else
     NextBlockInList(previous)=next;
   if (next != (void *) NULL)
@@ -344,15 +391,15 @@ static void *AcquireBlock(size_t size)
   */
   size=(size_t) (size+sizeof(size_t)+6*sizeof(size_t)-1) & -(4U*sizeof(size_t));
   i=AllocationPolicy(size);
-  block=memory_info.blocks[i];
+  block=memory_pool.blocks[i];
   while ((block != (void *) NULL) && (SizeOfBlock(block) < size))
     block=NextBlockInList(block);
   if (block == (void *) NULL)
     {
       i++;
-      while (memory_info.blocks[i] == (void *) NULL)
+      while (memory_pool.blocks[i] == (void *) NULL)
         i++;
-      block=memory_info.blocks[i];
+      block=memory_pool.blocks[i];
       if (i >= MaxBlocks)
         return((void *) NULL);
     }
@@ -379,7 +426,7 @@ static void *AcquireBlock(size_t size)
     }
   assert(size == SizeOfBlock(block));
   *BlockHeader(NextBlock(block))|=PreviousBlockBit;
-  memory_info.allocation+=size;
+  memory_pool.allocation+=size;
   return(block);
 }
 #endif
@@ -416,7 +463,7 @@ MagickExport void *AcquireMagickMemory(const size_t size)
   memory=memory_methods.acquire_memory_handler(size == 0 ? 1UL : size);
 #else
   if (memory_semaphore == (SemaphoreInfo *) NULL)
-    AcquireSemaphoreInfo(&memory_semaphore);
+    ActivateSemaphoreInfo(&memory_semaphore);
   if (free_segments == (DataSegmentInfo *) NULL)
     {
       LockSemaphoreInfo(memory_semaphore);
@@ -426,18 +473,18 @@ MagickExport void *AcquireMagickMemory(const size_t size)
             i;
 
           assert(2*sizeof(size_t) > (size_t) (~SizeMask));
-          (void) ResetMagickMemory(&memory_info,0,sizeof(memory_info));
-          memory_info.allocation=SegmentSize;
-          memory_info.blocks[MaxBlocks]=(void *) (-1);
+          (void) ResetMagickMemory(&memory_pool,0,sizeof(memory_pool));
+          memory_pool.allocation=SegmentSize;
+          memory_pool.blocks[MaxBlocks]=(void *) (-1);
           for (i=0; i < MaxSegments; i++)
           {
             if (i != 0)
-              memory_info.segment_pool[i].previous=
-                (&memory_info.segment_pool[i-1]);
+              memory_pool.segment_pool[i].previous=
+                (&memory_pool.segment_pool[i-1]);
             if (i != (MaxSegments-1))
-              memory_info.segment_pool[i].next=(&memory_info.segment_pool[i+1]);
+              memory_pool.segment_pool[i].next=(&memory_pool.segment_pool[i+1]);
           }
-          free_segments=(&memory_info.segment_pool[0]);
+          free_segments=(&memory_pool.segment_pool[0]);
         }
       UnlockSemaphoreInfo(memory_semaphore);
     }
@@ -497,6 +544,107 @@ MagickExport void *AcquireQuantumMemory(const size_t count,const size_t quantum)
 %                                                                             %
 %                                                                             %
 %                                                                             %
+%   A c q u i r e V i r t u a l M e m o r y                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireVirtualMemory() allocates a pointer to a block of memory at least size
+%  bytes suitably aligned for any use.
+%
+%  The format of the AcquireVirtualMemory method is:
+%
+%      MemoryInfo *AcquireVirtualMemory(const size_t count,const size_t quantum)
+%
+%  A description of each parameter follows:
+%
+%    o count: the number of quantum elements to allocate.
+%
+%    o quantum: the number of bytes in each quantum.
+%
+*/
+MagickExport MemoryInfo *AcquireVirtualMemory(const size_t count,
+  const size_t quantum)
+{
+  MemoryInfo
+    *memory_info;
+
+  size_t
+    length;
+
+  length=count*quantum;
+  if ((count == 0) || (quantum != (length/count)))
+    {
+      errno=ENOMEM;
+      return((MemoryInfo *) NULL);
+    }
+  memory_info=(MemoryInfo *) MagickAssumeAligned(AcquireAlignedMemory(1,
+    sizeof(*memory_info)));
+  if (memory_info == (MemoryInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(memory_info,0,sizeof(*memory_info));
+  memory_info->length=length;
+  memory_info->signature=MagickSignature;
+  if (AcquireMagickResource(MemoryResource,length) != MagickFalse)
+    {
+      memory_info->blob=AcquireAlignedMemory(1,length);
+      if (memory_info->blob != NULL)
+        memory_info->type=AlignedVirtualMemory;
+      else
+        RelinquishMagickResource(MemoryResource,length);
+    }
+  if ((memory_info->blob == NULL) &&
+      (AcquireMagickResource(MapResource,length) != MagickFalse))
+    {
+      /*
+        Heap memory failed, try anonymous memory mapping.
+      */
+      memory_info->blob=MapBlob(-1,IOMode,0,length);
+      if (memory_info->blob != NULL)
+        memory_info->type=MapVirtualMemory;
+      else
+        RelinquishMagickResource(MapResource,length);
+    }
+  if (memory_info->blob == NULL)
+    {
+      int
+        file;
+
+      /*
+        Anonymous memory mapping failed, try file-backed memory mapping.
+      */
+      file=AcquireUniqueFileResource(memory_info->filename);
+      if (file != -1)
+        {
+          if ((lseek(file,length-1,SEEK_SET) >= 0) && (write(file,"",1) == 1))
+            {
+              memory_info->blob=MapBlob(file,IOMode,0,length);
+              if (memory_info->blob != NULL)
+                {
+                  memory_info->type=MapVirtualMemory;
+                  (void) AcquireMagickResource(MapResource,length);
+                }
+            }
+          (void) close(file);
+        }
+    }
+  if (memory_info->blob == NULL)
+    {
+      memory_info->blob=AcquireMagickMemory(length);
+      if (memory_info->blob != NULL)
+        memory_info->type=UnalignedVirtualMemory;
+    }
+  if (memory_info->blob == NULL)
+    memory_info=RelinquishVirtualMemory(memory_info);
+  return(memory_info);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
 %   C o p y M a g i c k M e m o r y                                           %
 %                                                                             %
 %                                                                             %
@@ -576,19 +724,19 @@ MagickExport void DestroyMagickMemory(void)
     i;
 
   if (memory_semaphore == (SemaphoreInfo *) NULL)
-    AcquireSemaphoreInfo(&memory_semaphore);
+    ActivateSemaphoreInfo(&memory_semaphore);
   LockSemaphoreInfo(memory_semaphore);
   UnlockSemaphoreInfo(memory_semaphore);
-  for (i=0; i < (ssize_t) memory_info.number_segments; i++)
-    if (memory_info.segments[i]->mapped == MagickFalse)
+  for (i=0; i < (ssize_t) memory_pool.number_segments; i++)
+    if (memory_pool.segments[i]->mapped == MagickFalse)
       memory_methods.destroy_memory_handler(
-        memory_info.segments[i]->allocation);
+        memory_pool.segments[i]->allocation);
     else
-      (void) UnmapBlob(memory_info.segments[i]->allocation,
-        memory_info.segments[i]->length);
+      (void) UnmapBlob(memory_pool.segments[i]->allocation,
+        memory_pool.segments[i]->length);
   free_segments=(DataSegmentInfo *) NULL;
-  (void) ResetMagickMemory(&memory_info,0,sizeof(memory_info));
-  DestroySemaphoreInfo(&memory_semaphore);
+  (void) ResetMagickMemory(&memory_pool,0,sizeof(memory_pool));
+  RelinquishSemaphoreInfo(&memory_semaphore);
 #endif
 }
 \f
@@ -637,7 +785,7 @@ static MagickBooleanType ExpandHeap(size_t size)
     *segment;
 
   blocksize=((size+12*sizeof(size_t))+SegmentSize-1) & -SegmentSize;
-  assert(memory_info.number_segments < MaxSegments);
+  assert(memory_pool.number_segments < MaxSegments);
   segment=MapBlob(-1,IOMode,0,blocksize);
   mapped=segment != (void *) NULL ? MagickTrue : MagickFalse;
   if (segment == (void *) NULL)
@@ -650,11 +798,11 @@ static MagickBooleanType ExpandHeap(size_t size)
   segment_info->length=blocksize;
   segment_info->allocation=segment;
   segment_info->bound=(char *) segment+blocksize;
-  i=(ssize_t) memory_info.number_segments-1;
-  for ( ; (i >= 0) && (memory_info.segments[i]->allocation > segment); i--)
-    memory_info.segments[i+1]=memory_info.segments[i];
-  memory_info.segments[i+1]=segment_info;
-  memory_info.number_segments++;
+  i=(ssize_t) memory_pool.number_segments-1;
+  for ( ; (i >= 0) && (memory_pool.segments[i]->allocation > segment); i--)
+    memory_pool.segments[i+1]=memory_pool.segments[i];
+  memory_pool.segments[i+1]=segment_info;
+  memory_pool.number_segments++;
   size=blocksize-12*sizeof(size_t);
   block=(char *) segment_info->allocation+4*sizeof(size_t);
   *BlockHeader(block)=size | PreviousBlockBit;
@@ -715,6 +863,35 @@ MagickExport void GetMagickMemoryMethods(
 %                                                                             %
 %                                                                             %
 %                                                                             %
+%   G e t V i r t u a l M e m o r y B l o b                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetVirtualMemoryBlob() returns the virtual memory blob associated with the
+%  specified MemoryInfo structure.
+%
+%  The format of the GetVirtualMemoryBlob method is:
+%
+%      void *GetVirtualMemoryBlob(const MemoryInfo *memory_info)
+%
+%  A description of each parameter follows:
+%
+%    o memory_info: The MemoryInfo structure.
+*/
+MagickExport void *GetVirtualMemoryBlob(const MemoryInfo *memory_info)
+{
+  assert(memory_info != (const MemoryInfo *) NULL);
+  assert(memory_info->signature == MagickSignature);
+  return(memory_info->blob);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
 %   R e l i n q u i s h A l i g n e d M e m o r y                             %
 %                                                                             %
 %                                                                             %
@@ -820,6 +997,62 @@ MagickExport void *RelinquishMagickMemory(void *memory)
 %                                                                             %
 %                                                                             %
 %                                                                             %
+%   R e l i n q u i s h V i r t u a l M e m o r y                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RelinquishVirtualMemory() frees memory acquired with AcquireVirtualMemory().
+%
+%  The format of the RelinquishVirtualMemory method is:
+%
+%      MemoryInfo *RelinquishVirtualMemory(MemoryInfo *memory_info)
+%
+%  A description of each parameter follows:
+%
+%    o memory_info: A pointer to a block of memory to free for reuse.
+%
+*/
+MagickExport MemoryInfo *RelinquishVirtualMemory(MemoryInfo *memory_info)
+{
+  assert(memory_info != (MemoryInfo *) NULL);
+  assert(memory_info->signature == MagickSignature);
+  if (memory_info->blob != (void *) NULL)
+    switch (memory_info->type)
+    {
+      case AlignedVirtualMemory:
+      {
+        memory_info->blob=RelinquishAlignedMemory(memory_info->blob);
+        RelinquishMagickResource(MemoryResource,memory_info->length);
+        break;
+      }
+      case MapVirtualMemory:
+      {
+        (void) UnmapBlob(memory_info->blob,memory_info->length);
+        memory_info->blob=NULL;
+        RelinquishMagickResource(MapResource,memory_info->length);
+        if (*memory_info->filename != '\0')
+          (void) RelinquishUniqueFileResource(memory_info->filename);
+        break;
+      }
+      case UnalignedVirtualMemory:
+      default:
+      {
+        memory_info->blob=RelinquishMagickMemory(memory_info->blob);
+        break;
+      }
+    }
+  memory_info->signature=(~MagickSignature);
+  memory_info=(MemoryInfo *) RelinquishAlignedMemory(memory_info);
+  return(memory_info);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
 %   R e s e t M a g i c k M e m o r y                                         %
 %                                                                             %
 %                                                                             %
@@ -890,7 +1123,7 @@ static inline void *ResizeBlock(void *block,size_t size)
     (void) memcpy(memory,block,size);
   else
     (void) memcpy(memory,block,SizeOfBlock(block)-sizeof(size_t));
-  memory_info.allocation+=size;
+  memory_pool.allocation+=size;
   return(memory);
 }
 #endif