/* ** Copyright 1994, Silicon Graphics, Inc. ** All Rights Reserved. ** ** This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.; ** the contents of this file may not be disclosed to third parties, copied or ** duplicated in any form, in whole or in part, without the prior written ** permission of Silicon Graphics, Inc. ** ** RESTRICTED RIGHTS LEGEND: ** Use, duplication or disclosure by the Government is subject to restrictions ** as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data ** and Computer Software clause at DFARS 252.227-7013, and/or in similar or ** successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished - ** rights reserved under the Copyright Laws of the United States. ** ** Author: Eric Veach, July 1994. */ #ifdef NT #include #endif #include "memalloc.h" #include #ifdef NO_MALLOPT #define memalign(a,n) malloc(n) #define mallopt(t,v) #endif #define Pool mPool typedef struct Pool { char *prevAlloc; char *lastAlloc; int usedCount; int chunkSize; } Pool; typedef struct Chunk { Pool *pool; } Chunk; static Pool **Pools; static size_t MaxFast; #define POOL_SIZE 200 #define CHUNK_PAD sizeof(Chunk) #define ALIGN_SHIFT 3 #define ALIGN (1 << ALIGN_SHIFT) #define CHUNK_SIZE(n) (((n) + CHUNK_PAD + ALIGN - 1) & (-ALIGN)) #define ALIGNED_CHUNK_PAD ((CHUNK_PAD + ALIGN - 1) & (-ALIGN)) static int NewPool( size_t n, int poolSize ) { Pool *p; char *base; /* We want the *returned* chunks to be aligned on ALIGN boundaries. * The Chunk structures will be located just before these boundaries. */ p = (Pool *)malloc( CHUNK_SIZE(sizeof(Pool)) + poolSize * n ); if (p == NULL) { return 0; } base = (char *)p + CHUNK_SIZE(sizeof(Pool)) - CHUNK_PAD; p->prevAlloc = base - n; p->lastAlloc = base + (poolSize-1) * n; p->usedCount = poolSize; p->chunkSize = n; Pools[n>>ALIGN_SHIFT] = p; return 1; } int __gl_memInit( size_t maxFast ) { int i, numPools; if( Pools == NULL ) { #ifdef MEMORY_DEBUG mallopt( M_DEBUG, 1 ); #endif MaxFast = CHUNK_SIZE(maxFast) - CHUNK_PAD; numPools = ((MaxFast + CHUNK_PAD) >> ALIGN_SHIFT) + 1; Pools = (struct Pool **)malloc( numPools * sizeof(Pools[0]) ); if (Pools == NULL) return 0; /* Create a tiny pool for every size, to avoid a check for NULL * in memAlloc(). */ for( i = 1; i < numPools; ++i ) { if (NewPool( i << ALIGN_SHIFT, 1 ) == 0) { return 0; } } } return 1; } void *__gl_memAlloc( size_t n ) { Pool *p; Chunk *c; if( n <= MaxFast ) { n = CHUNK_SIZE( n ); p = Pools[n >> ALIGN_SHIFT]; assert ( p->chunkSize == n ); c = (Chunk *)(p->prevAlloc + n); p->prevAlloc = (char *) c; c->pool = p; if( c >= (Chunk *) p->lastAlloc ) { if (NewPool( n, POOL_SIZE ) == 0) { return 0; } } assert( ((size_t)(c + 1) & (ALIGN - 1)) == 0 ); } else { char* v; /* v = (char*) malloc( n + ALIGNED_CHUNK_PAD ) + ALIGNED_CHUNK_PAD;*/ v = (char*) malloc( n + ALIGNED_CHUNK_PAD ); if (v == NULL) { return 0; } v = v + ALIGNED_CHUNK_PAD; c = ((Chunk*) v) - 1; c->pool = NULL; assert( ((size_t)(c + 1) & (ALIGN - 1)) == 0 ); } return (c + 1); } extern void *__gl_memRealloc( void *v1, size_t n ) { Chunk *c = ((Chunk *) v1) - 1; Pool *p = c->pool; void *v2; #ifdef NT size_t len; #else int len; #endif if( p == NULL ) { char* v; /* v = (char*) realloc( (char*)v1 - ALIGNED_CHUNK_PAD, n + ALIGNED_CHUNK_PAD ) + ALIGNED_CHUNK_PAD; */ v = (char*) realloc( (char*)v1 - ALIGNED_CHUNK_PAD, n + ALIGNED_CHUNK_PAD); if (v == NULL) { return 0; } v = v + ALIGNED_CHUNK_PAD; c = ((Chunk*) v) - 1; assert( ((size_t)(c + 1) & (ALIGN - 1)) == 0 ); return (c+1); } len = p->chunkSize - CHUNK_PAD; if( n <= len ) { return v1; } v2 = memAlloc( n ); if (v2 == NULL) { return 0; } (void) memcpy( v2, v1, len ); memFree( v1 ); return v2; } extern void __gl_memFree( void *v ) { Chunk *c = ((Chunk *) v) - 1; Pool *p = c->pool; if( p == NULL ) { free( ((char*) v) - ALIGNED_CHUNK_PAD ); } else { if( --p->usedCount <= 0 ) { free( p ); } } }