diff options
author | cvs2fossil <cvs2fossil> | 2011-01-25 19:02:56 (GMT) |
---|---|---|
committer | cvs2fossil <cvs2fossil> | 2011-01-25 19:02:56 (GMT) |
commit | 352fce86be9d102b2284de839b7f7ff94ed971f2 (patch) | |
tree | e454e0d4460f15029e4ed5ae3f3131a992445426 /mac/tclMacAlloc.c | |
parent | 75f084f6970d2344bb5a82fdff6a73825bc6e64e (diff) | |
download | tcl-dgp_refactor_merge.zip tcl-dgp_refactor_merge.tar.gz tcl-dgp_refactor_merge.tar.bz2 |
Created branch dgp-refactor-merge-syntheticdgp_refactor_mergedgp_refactor_merge_synthetic
Diffstat (limited to 'mac/tclMacAlloc.c')
-rw-r--r-- | mac/tclMacAlloc.c | 412 |
1 files changed, 412 insertions, 0 deletions
diff --git a/mac/tclMacAlloc.c b/mac/tclMacAlloc.c new file mode 100644 index 0000000..3e6a948 --- /dev/null +++ b/mac/tclMacAlloc.c @@ -0,0 +1,412 @@ +/* + * tclMacAlloc.c -- + * + * This is a very fast storage allocator. It allocates blocks of a + * small number of different sizes, and keeps free lists of each size. + * Blocks that don't exactly fit are passed up to the next larger size. + * Blocks over a certain size are directly allocated by calling NewPtr. + * + * Copyright (c) 1983 Regents of the University of California. + * Copyright (c) 1996-1997 Sun Microsystems, Inc. + * + * Portions contributed by Chris Kingsley, Jack Jansen and Ray Johnson + *. + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tclMacAlloc.c,v 1.5 2001/11/23 01:27:09 das Exp $ + */ + +#include "tclInt.h" +#include "tclMacInt.h" +#include <Memory.h> +#include <Gestalt.h> +#include <stdlib.h> +#include <string.h> + + +/* + * Flags that are used by ConfigureMemory to define how the allocator + * should work. They can be or'd together. + */ +#define MEMORY_ALL_SYS 1 /* All memory should come from the system +heap. */ +#define MEMORY_DONT_USE_TEMPMEM 2 /* Don't use temporary memory but system memory. */ + +/* + * Amount of space to leave in the application heap for the Toolbox to work. + */ + +#define TOOLBOX_SPACE (512 * 1024) + +static int memoryFlags = 0; +static Handle toolGuardHandle = NULL; + /* This handle must be around so that we don't + * have NewGWorld failures. This handle is + * purgeable. Before we allocate any blocks, + * we see if this handle is still around. + * If it is not, then we try to get it again. + * If we can get it, we lock it and try + * to do the normal allocation, unlocking on + * the way out. If we can't, we go to the + * system heap directly. */ + +static int tclUseMemTracking = 0; /* Are we tracking memory allocations? + * On recent versions of the MacOS this + * is no longer necessary, as we can use + * temporary memory which is freed by the + * OS after a quit or crash. */ + +static size_t tclExtraHdlSize = 0; /* Size of extra memory allocated at the start + * of each block when using memory tracking + * ( == 0 otherwise) */ + +/* + * The following typedef and variable are used to keep track of memory + * blocks that are allocated directly from the System Heap. These chunks + * of memory must always be freed - even if we crash. + */ + +typedef struct listEl { + Handle memoryHandle; + struct listEl * next; + struct listEl * prec; +} ListEl; + +static ListEl * systemMemory = NULL; +static ListEl * appMemory = NULL; + +/* + * Prototypes for functions used only in this file. + */ + +static pascal void CleanUpExitProc _ANSI_ARGS_((void)); +void ConfigureMemory _ANSI_ARGS_((int flags)); +void FreeAllMemory _ANSI_ARGS_((void)); + +/* + *---------------------------------------------------------------------- + * + * TclpSysRealloc -- + * + * This function reallocates a chunk of system memory. If the + * chunk is already big enough to hold the new block, then no + * allocation happens. + * + * Results: + * Returns a pointer to the newly allocated block. + * + * Side effects: + * May copy the contents of the original block to the new block + * and deallocate the original block. + * + *---------------------------------------------------------------------- + */ + +VOID * +TclpSysRealloc( + VOID *oldPtr, /* Original block */ + unsigned int size) /* New size of block. */ +{ + Handle hand; + void *newPtr; + int maxsize; + OSErr err; + + if (tclUseMemTracking) { + hand = ((ListEl *) ((Ptr) oldPtr - tclExtraHdlSize))->memoryHandle; + } else { + hand = RecoverHandle((Ptr) oldPtr); + } + maxsize = GetHandleSize(hand) - sizeof(Handle); + if (maxsize < size) { + HUnlock(hand); + SetHandleSize(hand,size + tclExtraHdlSize); + err = MemError(); + HLock(hand); + if(err==noErr){ + newPtr=(*hand + tclExtraHdlSize); + } else { + newPtr = TclpSysAlloc(size, 1); + if(newPtr!=NULL) { + memmove(newPtr, oldPtr, maxsize); + TclpSysFree(oldPtr); + } + } + } else { + newPtr = oldPtr; + } + return newPtr; +} + +/* + *---------------------------------------------------------------------- + * + * TclpSysAlloc -- + * + * Allocate a new block of memory free from the System. + * + * Results: + * Returns a pointer to a new block of memory. + * + * Side effects: + * May obtain memory from app or sys space. Info is added to + * overhead lists etc. + * + *---------------------------------------------------------------------- + */ + +VOID * +TclpSysAlloc( + long size, /* Size of block to allocate. */ + int isBin) /* Is this a bin allocation? */ +{ + Handle hand = NULL; + ListEl * newMemoryRecord; + int isSysMem = 0; + static int initialized=0; + + if (!initialized) { + long response = 0; + OSErr err = noErr; + int useTempMem = 0; + + /* Check if we can use temporary memory */ + initialized=1; + err = Gestalt(gestaltOSAttr, &response); + if (err == noErr) { + useTempMem = response & (1 << gestaltRealTempMemory); + } + tclUseMemTracking = !useTempMem || (memoryFlags & MEMORY_DONT_USE_TEMPMEM); + if(tclUseMemTracking) { + tclExtraHdlSize = sizeof(ListEl); + /* + * We are allocating memory directly from the system + * heap. We need to install an exit handle + * to ensure the memory is cleaned up. + */ + TclMacInstallExitToShellPatch(CleanUpExitProc); + } + } + + if (!(memoryFlags & MEMORY_ALL_SYS)) { + + /* + * If the guard handle has been purged, throw it away and try + * to allocate it again. + */ + + if ((toolGuardHandle != NULL) && (*toolGuardHandle == NULL)) { + DisposeHandle(toolGuardHandle); + toolGuardHandle = NULL; + } + + /* + * If we have never allocated the guard handle, or it was purged + * and thrown away, then try to allocate it again. + */ + + if (toolGuardHandle == NULL) { + toolGuardHandle = NewHandle(TOOLBOX_SPACE); + if (toolGuardHandle != NULL) { + HLock(toolGuardHandle); + HPurge(toolGuardHandle); + } + } + + /* + * If we got the handle, lock it and do our allocation. + */ + + if (toolGuardHandle != NULL) { + HLock(toolGuardHandle); + hand = NewHandle(size + tclExtraHdlSize); + HUnlock(toolGuardHandle); + } + } + if (hand == NULL) { + /* + * Ran out of memory in application space. Lets try to get + * more memory from system. Otherwise, we return NULL to + * denote failure. + */ + if(!tclUseMemTracking) { + /* Use Temporary Memory instead of System Heap when available */ + OSErr err; + isBin = 1; /* always HLockHi TempMemHandles */ + hand = TempNewHandle(size + tclExtraHdlSize,&err); + if(err!=noErr) { hand=NULL; } + } else { + /* Use system heap when tracking memory */ + isSysMem=1; + isBin = 0; + hand = NewHandleSys(size + tclExtraHdlSize); + } + } + if (hand == NULL) { + return NULL; + } + if (isBin) { + HLockHi(hand); + } else { + HLock(hand); + } + if(tclUseMemTracking) { + /* Only need to do this when tracking memory */ + newMemoryRecord = (ListEl *) *hand; + newMemoryRecord->memoryHandle = hand; + newMemoryRecord->prec = NULL; + if(isSysMem) { + newMemoryRecord->next = systemMemory; + systemMemory = newMemoryRecord; + } else { + newMemoryRecord->next = appMemory; + appMemory = newMemoryRecord; + } + if(newMemoryRecord->next!=NULL) { + newMemoryRecord->next->prec=newMemoryRecord; + } + } + + return (*hand + tclExtraHdlSize); +} + +/* + *---------------------------------------------------------------------- + * + * TclpSysFree -- + * + * Free memory that we allocated back to the system. + * + * Results: + * None. + * + * Side effects: + * Memory is freed. + * + *---------------------------------------------------------------------- + */ + +void +TclpSysFree( + void * ptr) /* Free this system memory. */ +{ + if(tclUseMemTracking) { + /* Only need to do this when tracking memory */ + ListEl *memRecord; + + memRecord = (ListEl *) ((Ptr) ptr - tclExtraHdlSize); + /* Remove current record from linked list */ + if(memRecord->next!=NULL) { + memRecord->next->prec=memRecord->prec; + } + if(memRecord->prec!=NULL) { + memRecord->prec->next=memRecord->next; + } + if(memRecord==appMemory) { + appMemory=memRecord->next; + } else if(memRecord==systemMemory) { + systemMemory=memRecord->next; + } + DisposeHandle(memRecord->memoryHandle); + } else { + DisposeHandle(RecoverHandle((Ptr) ptr)); + } +} + +/* + *---------------------------------------------------------------------- + * + * CleanUpExitProc -- + * + * This procedure is invoked as an exit handler when ExitToShell + * is called. It removes any memory that was allocated directly + * from the system heap. This must be called when the application + * quits or the memory will never be freed. + * + * Results: + * None. + * + * Side effects: + * May free memory in the system heap. + * + *---------------------------------------------------------------------- + */ + +static pascal void +CleanUpExitProc() +{ + ListEl * memRecord; + + if(tclUseMemTracking) { + /* Only need to do this when tracking memory */ + while (systemMemory != NULL) { + memRecord = systemMemory; + systemMemory = memRecord->next; + DisposeHandle(memRecord->memoryHandle); + } + } +} + +/* + *---------------------------------------------------------------------- + * + * FreeAllMemory -- + * + * This procedure frees all memory blocks allocated by the memory + * sub-system. Make sure you don't have any code that references + * any malloced data! + * + * Results: + * None. + * + * Side effects: + * Frees all memory allocated by TclpAlloc. + * + *---------------------------------------------------------------------- + */ + +void +FreeAllMemory() +{ + ListEl * memRecord; + + if(tclUseMemTracking) { + /* Only need to do this when tracking memory */ + while (systemMemory != NULL) { + memRecord = systemMemory; + systemMemory = memRecord->next; + DisposeHandle(memRecord->memoryHandle); + } + while (appMemory != NULL) { + memRecord = appMemory; + appMemory = memRecord->next; + DisposeHandle(memRecord->memoryHandle); + } + } +} + +/* + *---------------------------------------------------------------------- + * + * ConfigureMemory -- + * + * This procedure sets certain flags in this file that control + * how memory is allocated and managed. This call must be made + * before any call to TclpAlloc is made. + * + * Results: + * None. + * + * Side effects: + * Certain state will be changed. + * + *---------------------------------------------------------------------- + */ + +void +ConfigureMemory( + int flags) /* Flags that control memory alloc scheme. */ +{ + memoryFlags = flags; +} |