diff options
author | rjohnson <rjohnson> | 1998-03-26 14:45:59 (GMT) |
---|---|---|
committer | rjohnson <rjohnson> | 1998-03-26 14:45:59 (GMT) |
commit | 2b5738da524e944cda39e24c0a87b745a43bd8c3 (patch) | |
tree | 6e8c9473978f6dab66c601e911721a7bd9d70b1b /mac/tclMacAlloc.c | |
parent | c6a259aeeca4814a97cf6694814c63e74e4e18fa (diff) | |
download | tcl-2b5738da524e944cda39e24c0a87b745a43bd8c3.zip tcl-2b5738da524e944cda39e24c0a87b745a43bd8c3.tar.gz tcl-2b5738da524e944cda39e24c0a87b745a43bd8c3.tar.bz2 |
Initial revision
Diffstat (limited to 'mac/tclMacAlloc.c')
-rw-r--r-- | mac/tclMacAlloc.c | 340 |
1 files changed, 340 insertions, 0 deletions
diff --git a/mac/tclMacAlloc.c b/mac/tclMacAlloc.c new file mode 100644 index 0000000..59d1417 --- /dev/null +++ b/mac/tclMacAlloc.c @@ -0,0 +1,340 @@ +/* + * 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. + * + * SCCS: @(#) tclMacAlloc.c 1.13 97/07/24 14:42:19 + */ + +#include "tclMacInt.h" +#include "tclInt.h" +#include <Memory.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. */ + +/* + * Amount of space to leave in the application heap for the Toolbox to work. + */ + +#define TOOLBOX_SPACE (32 * 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. */ + + +/* + * 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; +} ListEl; + +ListEl * systemMemory = NULL; +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; + + hand = * (Handle *) ((Ptr) oldPtr - sizeof(Handle)); + maxsize = GetHandleSize(hand) - sizeof(Handle); + if (maxsize < size) { + newPtr = TclpSysAlloc(size, 1); + memcpy(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; + + 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) { + HPurge(toolGuardHandle); + } + } + + /* + * If we got the handle, lock it and do our allocation. + */ + + if (toolGuardHandle != NULL) { + HLock(toolGuardHandle); + hand = NewHandle(size + sizeof(Handle)); + HUnlock(toolGuardHandle); + } + } + if (hand != NULL) { + newMemoryRecord = (ListEl *) NewPtr(sizeof(ListEl)); + if (newMemoryRecord == NULL) { + DisposeHandle(hand); + return NULL; + } + newMemoryRecord->memoryHandle = hand; + newMemoryRecord->next = appMemory; + appMemory = newMemoryRecord; + } else { + /* + * Ran out of memory in application space. Lets try to get + * more memory from system. Otherwise, we return NULL to + * denote failure. + */ + isBin = 0; + hand = NewHandleSys(size + sizeof(Handle)); + if (hand == NULL) { + return NULL; + } + if (systemMemory == NULL) { + /* + * This is the first time we've attempted to allocate memory + * directly from the system heap. We need to now install the + * exit handle to ensure the memory is cleaned up. + */ + TclMacInstallExitToShellPatch(CleanUpExitProc); + } + newMemoryRecord = (ListEl *) NewPtrSys(sizeof(ListEl)); + if (newMemoryRecord == NULL) { + DisposeHandle(hand); + return NULL; + } + newMemoryRecord->memoryHandle = hand; + newMemoryRecord->next = systemMemory; + systemMemory = newMemoryRecord; + } + if (isBin) { + HLockHi(hand); + } else { + HLock(hand); + } + (** (Handle **) hand) = hand; + + return (*hand + sizeof(Handle)); +} + +/* + *---------------------------------------------------------------------- + * + * 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. */ +{ + Handle hand; + OSErr err; + + hand = * (Handle *) ((Ptr) ptr - sizeof(Handle)); + DisposeHandle(hand); + err = MemError(); +} + +/* + *---------------------------------------------------------------------- + * + * 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; + + while (systemMemory != NULL) { + memRecord = systemMemory; + systemMemory = memRecord->next; + DisposeHandle(memRecord->memoryHandle); + DisposePtr((void *) memRecord); + } +} + +/* + *---------------------------------------------------------------------- + * + * 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; + + while (systemMemory != NULL) { + memRecord = systemMemory; + systemMemory = memRecord->next; + DisposeHandle(memRecord->memoryHandle); + DisposePtr((void *) memRecord); + } + while (appMemory != NULL) { + memRecord = appMemory; + appMemory = memRecord->next; + DisposeHandle(memRecord->memoryHandle); + DisposePtr((void *) memRecord); + } +} + +/* + *---------------------------------------------------------------------- + * + * 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; +} |