summaryrefslogtreecommitdiffstats
path: root/mac/tclMacAlloc.c
diff options
context:
space:
mode:
authorrjohnson <rjohnson>1998-03-26 14:45:59 (GMT)
committerrjohnson <rjohnson>1998-03-26 14:45:59 (GMT)
commit2b5738da524e944cda39e24c0a87b745a43bd8c3 (patch)
tree6e8c9473978f6dab66c601e911721a7bd9d70b1b /mac/tclMacAlloc.c
parentc6a259aeeca4814a97cf6694814c63e74e4e18fa (diff)
downloadtcl-2b5738da524e944cda39e24c0a87b745a43bd8c3.zip
tcl-2b5738da524e944cda39e24c0a87b745a43bd8c3.tar.gz
tcl-2b5738da524e944cda39e24c0a87b745a43bd8c3.tar.bz2
Initial revision
Diffstat (limited to 'mac/tclMacAlloc.c')
-rw-r--r--mac/tclMacAlloc.c340
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;
+}