tclMacAlloc.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:10k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * tclMacAlloc.c --
  3.  *
  4.  * This is a very fast storage allocator.  It allocates blocks of a
  5.  * small number of different sizes, and keeps free lists of each size.
  6.  * Blocks that don't exactly fit are passed up to the next larger size.
  7.  * Blocks over a certain size are directly allocated by calling NewPtr.
  8.  *
  9.  * Copyright (c) 1983 Regents of the University of California.
  10.  * Copyright (c) 1996-1997 Sun Microsystems, Inc.
  11.  *
  12.  * Portions contributed by Chris Kingsley, Jack Jansen and Ray Johnson
  13.  *.
  14.  * See the file "license.terms" for information on usage and redistribution
  15.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  16.  *
  17.  * RCS: @(#) $Id: tclMacAlloc.c,v 1.5 2001/11/23 01:27:09 das Exp $
  18.  */
  19. #include "tclInt.h"
  20. #include "tclMacInt.h"
  21. #include <Memory.h>
  22. #include <Gestalt.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. /*
  26.  * Flags that are used by ConfigureMemory to define how the allocator
  27.  * should work.  They can be or'd together.
  28.  */
  29. #define MEMORY_ALL_SYS 1 /* All memory should come from the system
  30. heap. */
  31. #define MEMORY_DONT_USE_TEMPMEM 2 /* Don't use temporary memory but system memory. */
  32. /*
  33.  * Amount of space to leave in the application heap for the Toolbox to work.
  34.  */
  35. #define TOOLBOX_SPACE (512 * 1024)
  36. static int memoryFlags = 0;
  37. static Handle toolGuardHandle = NULL;
  38. /* This handle must be around so that we don't
  39.  * have NewGWorld failures. This handle is
  40.  * purgeable. Before we allocate any blocks,
  41.  * we see if this handle is still around.
  42.  * If it is not, then we try to get it again.
  43.  * If we can get it, we lock it and try
  44.  * to do the normal allocation, unlocking on
  45.  * the way out. If we can't, we go to the
  46.  * system heap directly. */
  47. static int tclUseMemTracking = 0; /* Are we tracking memory allocations?
  48.    * On recent versions of the MacOS this
  49.    * is no longer necessary, as we can use
  50.    * temporary memory which is freed by the
  51.    * OS after a quit or crash. */
  52.    
  53. static size_t tclExtraHdlSize = 0; /* Size of extra memory allocated at the start
  54. * of each block when using memory tracking
  55. * ( == 0 otherwise) */
  56. /*
  57.  * The following typedef and variable are used to keep track of memory
  58.  * blocks that are allocated directly from the System Heap.  These chunks
  59.  * of memory must always be freed - even if we crash.
  60.  */
  61. typedef struct listEl {
  62.     Handle memoryHandle;
  63.     struct listEl * next;
  64.     struct listEl * prec;
  65. } ListEl;
  66. static ListEl * systemMemory = NULL;
  67. static ListEl * appMemory = NULL;
  68. /*
  69.  * Prototypes for functions used only in this file.
  70.  */
  71. static pascal void CleanUpExitProc _ANSI_ARGS_((void));
  72. void  ConfigureMemory _ANSI_ARGS_((int flags));
  73. void FreeAllMemory _ANSI_ARGS_((void));
  74. /*
  75.  *----------------------------------------------------------------------
  76.  *
  77.  * TclpSysRealloc --
  78.  *
  79.  * This function reallocates a chunk of system memory.  If the
  80.  * chunk is already big enough to hold the new block, then no
  81.  * allocation happens.
  82.  *
  83.  * Results:
  84.  * Returns a pointer to the newly allocated block.
  85.  *
  86.  * Side effects:
  87.  * May copy the contents of the original block to the new block
  88.  * and deallocate the original block.
  89.  *
  90.  *----------------------------------------------------------------------
  91.  */
  92. VOID *
  93. TclpSysRealloc(
  94.     VOID *oldPtr, /* Original block */
  95.     unsigned int size) /* New size of block. */
  96. {
  97.     Handle hand;
  98.     void *newPtr;
  99.     int maxsize;
  100.     OSErr err;
  101. if (tclUseMemTracking) {
  102.     hand = ((ListEl *) ((Ptr) oldPtr - tclExtraHdlSize))->memoryHandle;
  103.     } else {
  104.     hand = RecoverHandle((Ptr) oldPtr);
  105. }
  106.     maxsize = GetHandleSize(hand) - sizeof(Handle);
  107.     if (maxsize < size) {
  108.     HUnlock(hand);
  109.     SetHandleSize(hand,size + tclExtraHdlSize);
  110.     err = MemError();
  111.     HLock(hand);
  112.     if(err==noErr){
  113.      newPtr=(*hand + tclExtraHdlSize);
  114.     } else {
  115. newPtr = TclpSysAlloc(size, 1);
  116. if(newPtr!=NULL) {
  117. memmove(newPtr, oldPtr, maxsize);
  118. TclpSysFree(oldPtr);
  119. }
  120. }
  121.     } else {
  122. newPtr = oldPtr;
  123.     }
  124.     return newPtr;
  125. }
  126. /*
  127.  *----------------------------------------------------------------------
  128.  *
  129.  * TclpSysAlloc --
  130.  *
  131.  * Allocate a new block of memory free from the System.
  132.  *
  133.  * Results:
  134.  * Returns a pointer to a new block of memory.
  135.  *
  136.  * Side effects:
  137.  * May obtain memory from app or sys space.  Info is added to
  138.  * overhead lists etc.
  139.  *
  140.  *----------------------------------------------------------------------
  141.  */
  142. VOID *
  143. TclpSysAlloc(
  144.     long size, /* Size of block to allocate. */
  145.     int isBin) /* Is this a bin allocation? */
  146. {
  147.     Handle hand = NULL;
  148.     ListEl * newMemoryRecord;
  149. int isSysMem = 0;
  150. static int initialized=0;
  151. if (!initialized) {
  152. long response = 0;
  153. OSErr err = noErr;
  154. int useTempMem = 0;
  155. /* Check if we can use temporary memory */
  156. initialized=1;
  157. err = Gestalt(gestaltOSAttr, &response);
  158. if (err == noErr) {
  159.      useTempMem = response & (1 << gestaltRealTempMemory);
  160. }
  161. tclUseMemTracking = !useTempMem || (memoryFlags & MEMORY_DONT_USE_TEMPMEM);
  162. if(tclUseMemTracking) {
  163.     tclExtraHdlSize = sizeof(ListEl);
  164.     /*
  165.      * We are allocating memory directly from the system
  166.      * heap. We need to install an exit handle 
  167.      * to ensure the memory is cleaned up.
  168.      */
  169.     TclMacInstallExitToShellPatch(CleanUpExitProc);
  170. }
  171. }
  172.     if (!(memoryFlags & MEMORY_ALL_SYS)) {
  173.      /*
  174.       * If the guard handle has been purged, throw it away and try
  175.       * to allocate it again.
  176.       */
  177.      if ((toolGuardHandle != NULL) && (*toolGuardHandle == NULL)) {
  178.          DisposeHandle(toolGuardHandle);
  179.          toolGuardHandle = NULL;
  180.      }
  181.      /*
  182.       * If we have never allocated the guard handle, or it was purged
  183.       * and thrown away, then try to allocate it again.
  184.       */
  185.      if (toolGuardHandle == NULL) {
  186.          toolGuardHandle = NewHandle(TOOLBOX_SPACE);
  187.          if (toolGuardHandle != NULL) {
  188.           HLock(toolGuardHandle);
  189.           HPurge(toolGuardHandle);
  190.          }
  191.      }
  192. /*
  193.  * If we got the handle, lock it and do our allocation.
  194.  */
  195.      if (toolGuardHandle != NULL) {
  196.          HLock(toolGuardHandle);
  197.     hand = NewHandle(size + tclExtraHdlSize);
  198.     HUnlock(toolGuardHandle);
  199. }
  200.     }
  201.     if (hand == NULL) {
  202. /*
  203.  * Ran out of memory in application space.  Lets try to get
  204.  * more memory from system.  Otherwise, we return NULL to
  205.  * denote failure.
  206.  */
  207. if(!tclUseMemTracking) {
  208. /* Use Temporary Memory instead of System Heap when available */
  209. OSErr err;
  210. isBin = 1; /* always HLockHi TempMemHandles */
  211. hand = TempNewHandle(size + tclExtraHdlSize,&err);
  212. if(err!=noErr) { hand=NULL; }
  213. } else {
  214. /* Use system heap when tracking memory */
  215. isSysMem=1;
  216. isBin = 0;
  217. hand = NewHandleSys(size + tclExtraHdlSize);
  218. }
  219. }
  220. if (hand == NULL) {
  221.     return NULL;
  222. }
  223.     if (isBin) {
  224. HLockHi(hand);
  225.     } else {
  226. HLock(hand);
  227.     }
  228. if(tclUseMemTracking) {
  229. /* Only need to do this when tracking memory */
  230. newMemoryRecord = (ListEl *) *hand;
  231. newMemoryRecord->memoryHandle = hand;
  232. newMemoryRecord->prec = NULL;
  233. if(isSysMem) {
  234. newMemoryRecord->next = systemMemory;
  235. systemMemory = newMemoryRecord;
  236. } else {
  237. newMemoryRecord->next = appMemory;
  238. appMemory = newMemoryRecord;
  239. }
  240. if(newMemoryRecord->next!=NULL) {
  241. newMemoryRecord->next->prec=newMemoryRecord;
  242. }
  243. }
  244.     return (*hand + tclExtraHdlSize);
  245. }
  246. /*
  247.  *----------------------------------------------------------------------
  248.  *
  249.  * TclpSysFree --
  250.  *
  251.  * Free memory that we allocated back to the system.
  252.  *
  253.  * Results:
  254.  * None.
  255.  *
  256.  * Side effects:
  257.  * Memory is freed.
  258.  *
  259.  *----------------------------------------------------------------------
  260.  */
  261. void
  262. TclpSysFree(
  263.     void * ptr) /* Free this system memory. */
  264. {
  265. if(tclUseMemTracking) {
  266.     /* Only need to do this when tracking memory */
  267.     ListEl *memRecord;
  268.     memRecord = (ListEl *) ((Ptr) ptr - tclExtraHdlSize);
  269.     /* Remove current record from linked list */
  270.     if(memRecord->next!=NULL) {
  271.      memRecord->next->prec=memRecord->prec;
  272.     }
  273.     if(memRecord->prec!=NULL) {
  274.      memRecord->prec->next=memRecord->next;
  275.     }
  276.     if(memRecord==appMemory) {
  277.      appMemory=memRecord->next;
  278.     } else if(memRecord==systemMemory) {
  279.      systemMemory=memRecord->next;
  280.     }
  281.     DisposeHandle(memRecord->memoryHandle);
  282. } else {
  283.     DisposeHandle(RecoverHandle((Ptr) ptr));
  284. }
  285. }
  286. /*
  287.  *----------------------------------------------------------------------
  288.  *
  289.  * CleanUpExitProc --
  290.  *
  291.  * This procedure is invoked as an exit handler when ExitToShell
  292.  * is called.  It removes any memory that was allocated directly
  293.  * from the system heap.  This must be called when the application
  294.  * quits or the memory will never be freed.
  295.  *
  296.  * Results:
  297.  * None.
  298.  *
  299.  * Side effects:
  300.  * May free memory in the system heap.
  301.  *
  302.  *----------------------------------------------------------------------
  303.  */
  304. static pascal void
  305. CleanUpExitProc()
  306. {
  307.     ListEl * memRecord;
  308.     if(tclUseMemTracking) {
  309.     /* Only need to do this when tracking memory */
  310.     while (systemMemory != NULL) {
  311. memRecord = systemMemory;
  312. systemMemory = memRecord->next;
  313. DisposeHandle(memRecord->memoryHandle);
  314.     }
  315.     }
  316. }
  317. /*
  318.  *----------------------------------------------------------------------
  319.  *
  320.  * FreeAllMemory --
  321.  *
  322.  * This procedure frees all memory blocks allocated by the memory
  323.  * sub-system.  Make sure you don't have any code that references
  324.  * any malloced data!
  325.  *
  326.  * Results:
  327.  * None.
  328.  *
  329.  * Side effects:
  330.  * Frees all memory allocated by TclpAlloc.
  331.  *
  332.  *----------------------------------------------------------------------
  333.  */
  334. void
  335. FreeAllMemory()
  336. {
  337.     ListEl * memRecord;
  338. if(tclUseMemTracking) {
  339. /* Only need to do this when tracking memory */
  340.     while (systemMemory != NULL) {
  341. memRecord = systemMemory;
  342. systemMemory = memRecord->next;
  343. DisposeHandle(memRecord->memoryHandle);
  344.     }
  345.     while (appMemory != NULL) {
  346. memRecord = appMemory;
  347. appMemory = memRecord->next;
  348. DisposeHandle(memRecord->memoryHandle);
  349. }
  350.     }
  351. }
  352. /*
  353.  *----------------------------------------------------------------------
  354.  *
  355.  * ConfigureMemory --
  356.  *
  357.  * This procedure sets certain flags in this file that control
  358.  * how memory is allocated and managed.  This call must be made
  359.  * before any call to TclpAlloc is made.
  360.  *
  361.  * Results:
  362.  * None.
  363.  *
  364.  * Side effects:
  365.  * Certain state will be changed.
  366.  *
  367.  *----------------------------------------------------------------------
  368.  */
  369. void
  370. ConfigureMemory(
  371.     int flags) /* Flags that control memory alloc scheme. */
  372. {
  373.     memoryFlags = flags;
  374. }