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