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