home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / POV-Ray 3.0.2 / src / MacSource / MemAlloc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-11-13  |  10.3 KB  |  420 lines  |  [TEXT/CWIE]

  1. /*==============================================================================
  2. Project:    POV
  3.  
  4. Version:    3
  5.  
  6. File:    MemAlloc.c
  7.  
  8. Description:
  9. Routines to handle the Mac-specific memory handling, by rerouting the POV_MALLOC
  10. style calls through to the appropriate routines.
  11. ------------------------------------------------------------------------------
  12. Author:
  13.     Eduard [esp] Schwan
  14. ------------------------------------------------------------------------------
  15.     from Persistence of Vision(tm) Ray Tracer
  16.     Copyright 1996 Persistence of Vision Team
  17. ------------------------------------------------------------------------------
  18.     NOTICE: This source code file is provided so that users may experiment
  19.     with enhancements to POV-Ray and to port the software to platforms other 
  20.     than those supported by the POV-Ray Team.  There are strict rules under
  21.     which you are permitted to use this file.  The rules are in the file
  22.     named POVLEGAL.DOC which should be distributed with this file. If 
  23.     POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  24.     Team Coordinator by leaving a message in CompuServe's Graphics Developer's
  25.     Forum.  The latest version of POV-Ray may be found there as well.
  26.  
  27.     This program is based on the popular DKB raytracer version 2.12.
  28.     DKBTrace was originally written by David K. Buck.
  29.     DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
  30. ------------------------------------------------------------------------------
  31. Change History:
  32. ==============================================================================*/
  33.  
  34. #define MEMALLOC_C
  35.  
  36. #include "MemAlloc.h"
  37. #include "Stdio_p2w.h"    // printf
  38.  
  39. #include "USERIO.H"    // Error
  40.  
  41. #include <types.h>
  42. #include <stdlib.h>    // malloc
  43. #include <string.h>    // strcpy, memset
  44. #include <memory.h>    // NewPtr
  45. #include <errors.h>    // memFullErr
  46. #include <ToolUtils.h> // watchCursor
  47.  
  48.  
  49. // =====================================================================
  50. // Configuration flags, change these to alter how memory is allocated.
  51. // NOTE: After extensive testing, here's what I've found:
  52. // With USE_NATIVE_MALLOC off (0), POV-Ray runs the fastest, but there's
  53. // a catch.  Most implementations of malloc/free seem to leave Mac
  54. // memory allocated, even though it is freed via free().  And although
  55. // the next render will re-use this space, two things happen... (1) because
  56. // this free-pool memory is not released, regular Mac memory cannot use the
  57. // space, so after the first render, you have permanently lost some heap
  58. // space, which could have been used by the offscreen image, etc.  and
  59. // (2) each time you render, a little extra free-pool space is used for some
  60. // reason (fragmentation?), meaning that during batch or animation renders,
  61. // you could eventually run out of memory. [esp]
  62. // =====================================================================
  63.  
  64. // turn this off to use C's malloc(), on for Mac's NewPtr()/NewHandle()
  65. // #define USE_NATIVE_MALLOC    1
  66.  
  67. #if (USE_NATIVE_MALLOC)
  68. // Use Mac's NewHandle() instead of NewPtr()
  69. // (only makes sense if USE_NATIVE_MALLOC is ON)
  70. #define USE_MEM_HANDLES    1
  71. #endif
  72.  
  73.  
  74.  
  75. // =====================================================================
  76. // undefine our earlier re-definitions of the stdlib calls,
  77. // so we can call them ourselves here.
  78. #undef malloc
  79. #undef calloc
  80. #undef realloc
  81. #undef free
  82.  
  83. // This defines the lowest free memory is allowed to get before
  84. // malloc & calloc fail.  This guarantees some free heap space for
  85. // error recovery.
  86. #define    MIN_SAFE_BYTES        100*1024L
  87.  
  88.  
  89. // Memory allocation tracking (Garbage Collection)
  90. static Handle        gReserveBuffer = NULL;
  91.  
  92. // Set to true to allocate temp memory (via UseTempMem(t/f) method)
  93. static Boolean        gUseTempMem = false;
  94.  
  95.  
  96. // =====================================================================
  97. void UseTempMem(int doIt)
  98. {
  99.     gUseTempMem = doIt;
  100. } // UseTempMem
  101.  
  102. // =====================================================================
  103. void AllocateSafetyBuffer(size_t reserve_size)
  104. {
  105. //    OSErr    anError;
  106.  
  107.     if (gReserveBuffer == NULL)
  108.     {
  109.         gReserveBuffer = NewHandle(reserve_size);
  110.         if (gReserveBuffer)
  111.         {
  112.             MoveHHi(gReserveBuffer);
  113.             // mark it so Macsbug snoopers know what it is
  114.             HLock(gReserveBuffer);
  115.             strcpy(*gReserveBuffer, "Safety Buffer");
  116.             HUnlock(gReserveBuffer);
  117.         }
  118.     }
  119. } // AllocateSafetyBuffer
  120.  
  121.  
  122. // =====================================================================
  123. void PurgeSafetyBuffer(void)
  124. {
  125.     if (gReserveBuffer)
  126.     {
  127.         DisposeHandle(gReserveBuffer);
  128.         gReserveBuffer = NULL;
  129.     }
  130. } // PurgeSafetyBuffer
  131.  
  132.  
  133. // =====================================================================
  134. // Return true if we've had to purge our safety buffer
  135. Boolean InLowMemoryMode(void)
  136. {
  137.     return gReserveBuffer == NULL;
  138. }
  139.  
  140.  
  141. // =====================================================================
  142. static void HandleOutOfMem(void)
  143. {
  144.     // We are most likely out of memory.  For now, we will free all the
  145.     // allocated memory, and exit back to the main loop with an error.
  146.     // We could be down to 5 or 10 bytes of available memory, and to do
  147.     // anything else (like return from malloc and let the caller handle it)
  148.     // risks a hard lockup or crash!  So, first, make sure there's room
  149.     // for loading dialogs & stuff in POV_reclaim(), by dumping the buffer memory.
  150.     PurgeSafetyBuffer();
  151.  
  152.     // open some more heap space
  153. // [esp] this is commented out in 3.0.1 to see if we handle lomem conditions better without it
  154. //    (void)CompactMem(FreeMem());
  155.  
  156.     // tell user we failed from here and exit out of all fn calls
  157.     // this is a POV-Ray USERIO.C call.
  158.     Error("Ran out of application memory; Increase POV-Ray application memory size.\n");
  159.  
  160.     // beep!
  161.     SysBeep(2);
  162.  
  163. } // HandleOutOfMem
  164.  
  165.  
  166. // =====================================================================
  167. void *Mac_malloc(size_t size)
  168. {
  169.     void        *myptr = NULL;
  170. #if USE_MEM_HANDLES
  171.     Handle        myhdl = NULL;
  172. #endif
  173.     Boolean        enoughMem;
  174.  
  175.     // free memory available?
  176.     if (gUseTempMem)
  177.         enoughMem = TempFreeMem() > MIN_SAFE_BYTES*2;
  178.     else
  179.         enoughMem = MaxBlock() > MIN_SAFE_BYTES;
  180.  
  181.     if (enoughMem)
  182.     {
  183.  
  184. #if USE_NATIVE_MALLOC
  185.  #if USE_MEM_HANDLES
  186.         OSErr    anError;
  187.         // use locked handles
  188.         if (gUseTempMem)
  189.         {
  190.             myhdl = TempNewHandle(size, &anError);
  191.         }
  192.         else
  193.             myhdl = NewHandle(size);
  194.  
  195.         if (myhdl)
  196.         {
  197.             if (gUseTempMem)
  198.                 HLock(myhdl);
  199.             else
  200.                 HLockHi(myhdl); // move it up and lock it down
  201.             anError = MemError();
  202.  
  203.             // it's really a handle, turn it into a pointer
  204.             myptr = *myhdl;
  205.         }
  206.  #else
  207.         // use regular pointers
  208.         if (gUseTempMem)
  209.             myptr = NewPtr(size);
  210.         else
  211.             myptr = NewPtr(size);
  212.  #endif // USE_MEM_HANDLES
  213. #else
  214.         // use Std C Lib allocator
  215.         myptr = malloc(size);
  216. #endif // USE_NATIVE_MALLOC
  217.     }
  218.  
  219.     // allocation was unsuccessful
  220.     if (myptr == NULL)
  221.         HandleOutOfMem();
  222.  
  223.     return myptr;
  224.  
  225. } // Mac_malloc
  226.  
  227.  
  228. // =====================================================================
  229. void *Mac_calloc(size_t nmemb, size_t size)
  230. {
  231.     void        *myptr = NULL;
  232. #if USE_MEM_HANDLES
  233.     Handle        myhdl = NULL;
  234. #endif
  235.     Boolean        enoughMem;
  236.  
  237.     if (gUseTempMem)
  238.         enoughMem = TempFreeMem() > MIN_SAFE_BYTES*2;
  239.     else
  240.         enoughMem = MaxBlock() > MIN_SAFE_BYTES;
  241.  
  242.     if (enoughMem)
  243.     {
  244.  
  245. #if USE_NATIVE_MALLOC
  246.  #if USE_MEM_HANDLES
  247.         // use locked handles
  248.         if (gUseTempMem)
  249.         {
  250.             OSErr    anError;
  251.             myhdl = TempNewHandle(nmemb*size, &anError);
  252.         }
  253.         else
  254.             myhdl = NewHandleClear(nmemb*size);
  255.  
  256.         if (myhdl)
  257.         {
  258.             if (gUseTempMem)
  259.             {
  260.                 HLock(myhdl);
  261.                 memset(*myhdl, 0, nmemb*size);
  262.             }
  263.             else
  264.                 HLockHi(myhdl); // move it up and lock it down
  265.             // it's really a handle, turn it into a pointer
  266.             myptr = *myhdl;
  267.         }
  268.  #else
  269.         // use regular pointers
  270.         if (gUseTempMem)
  271.             myptr = NewPtrClear(nmemb*size);
  272.         else
  273.             myptr = NewPtrClear(nmemb*size);
  274.  #endif // USE_MEM_HANDLES
  275. #else
  276.         myptr = calloc(nmemb,size);
  277. #endif // USE_NATIVE_MALLOC
  278.  
  279.     }
  280.  
  281.     // allocation was unsuccessful
  282.     if (myptr == NULL)
  283.         HandleOutOfMem();
  284.  
  285.     return myptr;
  286.  
  287. } // Mac_calloc
  288.  
  289.  
  290.  
  291. // =====================================================================
  292. void *Mac_realloc(void * p, size_t newsize)
  293. {
  294. #if USE_NATIVE_MALLOC
  295.     size_t        oldsize;
  296. #endif
  297. #if USE_MEM_HANDLES
  298.     Handle        myhdl = NULL;
  299. #endif
  300.     Boolean        enoughMem;
  301.     void        *myptr = NULL;
  302.  
  303.     // Warn user if nil pointer passed in!
  304.     if (p == NULL)
  305.     {
  306.         printf("## Warning! Ignoring an attempt to realloc a nil pointer!\n");
  307.         return NULL;
  308.     }
  309.  
  310.     if (gUseTempMem)
  311.         enoughMem = TempFreeMem() > MIN_SAFE_BYTES*2;
  312.     else
  313.         enoughMem = MaxBlock() > MIN_SAFE_BYTES;
  314.  
  315.     if (enoughMem)
  316.     {
  317. #if USE_NATIVE_MALLOC
  318.  
  319.  #if USE_MEM_HANDLES
  320.         // get previous size for shrink/grow check
  321.         if (gUseTempMem)
  322.             oldsize = GetHandleSize(RecoverHandle((Ptr)p));
  323.         else
  324.             oldsize = GetHandleSize(RecoverHandle((Ptr)p));
  325.  
  326.         // allocate new space... use locked handles
  327.         if (gUseTempMem)
  328.         {
  329.             OSErr    anError;
  330.             myhdl = TempNewHandle(newsize, &anError);
  331.         }
  332.         else
  333.             myhdl = NewHandle(newsize);
  334.  
  335.         // it's really a handle, turn it into a pointer
  336.         if (myhdl)
  337.         {
  338.             if (gUseTempMem)
  339.                 HLock(myhdl);
  340.             else
  341.                 HLockHi(myhdl); // move it up and lock it down
  342.             myptr = *(Handle)myhdl; // initialize it for later
  343.         }
  344.  #else
  345.         // get previous size for shrink/grow check
  346.         oldsize = GetPtrSize(p);
  347.         // allocate new space... use regular pointers
  348.         if (gUseTempMem)
  349.             myptr = NewPtr(newsize);
  350.         else
  351.             myptr = NewPtr(newsize);
  352.  #endif // USE_MEM_HANDLES
  353.  
  354.         if (myptr)
  355.         { 
  356.             // copy old contents into new space (trim if less space)
  357.             BlockMoveData(p, myptr, (oldsize<newsize)?oldsize:newsize);
  358.  
  359.             // now release old memory...
  360.             Mac_free(p);
  361.         }
  362. #else
  363.         // do the ANSI thing
  364.         myptr = realloc(p, newsize);
  365. #endif // USE_NATIVE_MALLOC
  366.     }
  367.  
  368.     // allocation was unsuccessful
  369.     if (myptr == NULL)
  370.         HandleOutOfMem();
  371.  
  372.     // let caller know the new pointer
  373.     return myptr;
  374.     
  375. } // Mac_realloc
  376.  
  377.  
  378. // =====================================================================
  379. void Mac_free(void *myptr)
  380. {
  381. #if USE_MEM_HANDLES
  382.      Handle        myhdl = NULL;
  383. #endif // USE_MEM_HANDLES
  384.  
  385.     if (myptr == NULL)
  386.     {
  387.         printf("## Warning! Ignoring an attempt to free a nil pointer!\n");
  388.     }
  389.     else
  390.     {
  391. #if USE_NATIVE_MALLOC
  392.  #if USE_MEM_HANDLES
  393.         // use Mac locked handles
  394.         // find it
  395.         if (gUseTempMem)
  396.             myhdl = RecoverHandle((Ptr)myptr);
  397.         else
  398.             myhdl = RecoverHandle((Ptr)myptr);
  399.         // dump it
  400.         if (myhdl)
  401.         {
  402.             DisposeHandle(myhdl);
  403.         }
  404.         else
  405.         {
  406.             printf("## Error %d!  Cannot recover handle from ptr! ($%lx)\n",
  407.                     MemError(), myptr);
  408.         }
  409.  #else
  410.         // use regular Mac pointers
  411.         DisposePtr(myptr);
  412.  #endif // USE_MEM_HANDLES
  413. #else
  414.         // The Std C library way...
  415.         free(myptr);
  416. #endif // USE_NATIVE_MALLOC
  417.     }
  418. } // Mac_free
  419.  
  420.