⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tclalloc.c

📁 tcl是工具命令语言
💻 C
📖 第 1 页 / 共 2 页
字号:
/*  * tclAlloc.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 from the system. * * Copyright (c) 1983 Regents of the University of California. * Copyright (c) 1996-1997 Sun Microsystems, Inc. * Copyright (c) 1998-1999 by Scriptics Corporation. * * 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: tclAlloc.c,v 1.16 2002/04/23 17:03:34 hobbs Exp $ *//* * Windows and Unix use an alternative allocator when building with threads * that has significantly reduced lock contention. */#if !defined(TCL_THREADS) || !defined(USE_THREAD_ALLOC)#include "tclInt.h"#include "tclPort.h"#if USE_TCLALLOC#ifdef TCL_DEBUG#   define DEBUG/* #define MSTATS */#   define RCHECK#endif/* * We should really make use of AC_CHECK_TYPE(caddr_t) * here, but it can wait until Tcl uses config.h properly. */#if defined(MAC_TCL) || defined(_MSC_VER) || defined(__MINGW32__) || defined(__BORLANDC__)typedef unsigned long caddr_t;#endif/* * The overhead on a block is at least 8 bytes.  When free, this space * contains a pointer to the next free block, and the bottom two bits must * be zero.  When in use, the first byte is set to MAGIC, and the second * byte is the size index.  The remaining bytes are for alignment. * If range checking is enabled then a second word holds the size of the * requested block, less 1, rounded up to a multiple of sizeof(RMAGIC). * The order of elements is critical: ov_magic must overlay the low order * bits of ov_next, and ov_magic can not be a valid ov_next bit pattern. */union overhead {    union overhead *ov_next;	/* when free */    unsigned char ov_padding[8]; /* Ensure the structure is 8-byte aligned. */    struct {	unsigned char	ovu_magic0;	/* magic number */	unsigned char	ovu_index;	/* bucket # */	unsigned char	ovu_unused;	/* unused */	unsigned char	ovu_magic1;	/* other magic number */#ifdef RCHECK	unsigned short	ovu_rmagic;	/* range magic number */	unsigned long	ovu_size;	/* actual block size */	unsigned short  ovu_unused2;    /* padding to 8-byte align */#endif    } ovu;#define ov_magic0	ovu.ovu_magic0#define ov_magic1	ovu.ovu_magic1#define ov_index	ovu.ovu_index#define ov_rmagic	ovu.ovu_rmagic#define ov_size		ovu.ovu_size};#define MAGIC		0xef		/* magic # on accounting info */#define RMAGIC		0x5555		/* magic # on range info */#ifdef RCHECK#define	RSLOP		sizeof (unsigned short)#else#define	RSLOP		0#endif#define OVERHEAD (sizeof(union overhead) + RSLOP)/* * nextf[i] is the pointer to the next free block of size 2^(i+3).  The * smallest allocatable block is 8 bytes.  The overhead information * precedes the data area returned to the user. */#define NBUCKETS	13#define MAXMALLOC	(1<<(NBUCKETS+2))static	union overhead *nextf[NBUCKETS];/*  * The following structure is used to keep track of all system memory  * currently owned by Tcl.  When finalizing, all this memory will * be returned to the system. */struct block {    struct block *nextPtr;	/* Linked list. */    struct block *prevPtr;	/* Linked list for big blocks, ensures 8-byte 				 * alignment for suballocated blocks. */};static struct block *blockList;		/* Tracks the suballocated blocks. */static struct block bigBlocks = {	/* Big blocks aren't suballocated. */    &bigBlocks, &bigBlocks};/* * The allocator is protected by a special mutex that must be * explicitly initialized.  Futhermore, because Tcl_Alloc may be * used before anything else in Tcl, we make this module self-initializing * after all with the allocInit variable. */#ifdef TCL_THREADSstatic Tcl_Mutex *allocMutexPtr;#endifstatic int allocInit = 0;#ifdef MSTATS/* * nmalloc[i] is the difference between the number of mallocs and frees * for a given block size. */static	unsigned int nmalloc[NBUCKETS+1];#include <stdio.h>#endif#if defined(DEBUG) || defined(RCHECK)#define	ASSERT(p)   if (!(p)) panic(# p)#define RANGE_ASSERT(p) if (!(p)) panic(# p)#else#define	ASSERT(p)#define RANGE_ASSERT(p)#endif/* * Prototypes for functions used only in this file. */static void 		MoreCore _ANSI_ARGS_((int bucket));/* *------------------------------------------------------------------------- * * TclInitAlloc -- * *	Initialize the memory system. * * Results: *	None. * * Side effects: *	Initialize the mutex used to serialize allocations. * *------------------------------------------------------------------------- */voidTclInitAlloc(){    if (!allocInit) {	allocInit = 1;#ifdef TCL_THREADS	allocMutexPtr = Tcl_GetAllocMutex();#endif    }}/* *------------------------------------------------------------------------- * * TclFinalizeAllocSubsystem -- * *	Release all resources being used by this subsystem, including  *	aggressively freeing all memory allocated by TclpAlloc() that  *	has not yet been released with TclpFree(). *	 *	After this function is called, all memory allocated with  *	TclpAlloc() should be considered unusable. * * Results: *	None. * * Side effects: *	This subsystem is self-initializing, since memory can be  *	allocated before Tcl is formally initialized.  After this call, *	this subsystem has been reset to its initial state and is  *	usable again. * *------------------------------------------------------------------------- */voidTclFinalizeAllocSubsystem(){    int i;    struct block *blockPtr, *nextPtr;    Tcl_MutexLock(allocMutexPtr);    for (blockPtr = blockList; blockPtr != NULL; blockPtr = nextPtr) {	nextPtr = blockPtr->nextPtr;	TclpSysFree(blockPtr);    }    blockList = NULL;    for (blockPtr = bigBlocks.nextPtr; blockPtr != &bigBlocks; ) {	nextPtr = blockPtr->nextPtr;	TclpSysFree(blockPtr);	blockPtr = nextPtr;    }    bigBlocks.nextPtr = &bigBlocks;    bigBlocks.prevPtr = &bigBlocks;    for (i = 0; i < NBUCKETS; i++) {	nextf[i] = NULL;#ifdef MSTATS	nmalloc[i] = 0;#endif    }#ifdef MSTATS    nmalloc[i] = 0;#endif    Tcl_MutexUnlock(allocMutexPtr);}/* *---------------------------------------------------------------------- * * TclpAlloc -- * *	Allocate more memory. * * Results: *	None. * * Side effects: *	None. * *---------------------------------------------------------------------- */char *TclpAlloc(nbytes)    unsigned int nbytes;	/* Number of bytes to allocate. */{    register union overhead *op;    register long bucket;    register unsigned amt;    struct block *bigBlockPtr;    if (!allocInit) {	/*	 * We have to make the "self initializing" because Tcl_Alloc	 * may be used before any other part of Tcl.  E.g., see	 * main() for tclsh!	 */	TclInitAlloc();    }    Tcl_MutexLock(allocMutexPtr);    /*     * First the simple case: we simple allocate big blocks directly     */    if (nbytes + OVERHEAD >= MAXMALLOC) {	bigBlockPtr = (struct block *) TclpSysAlloc((unsigned) 		(sizeof(struct block) + OVERHEAD + nbytes), 0);	if (bigBlockPtr == NULL) {	    Tcl_MutexUnlock(allocMutexPtr);	    return NULL;	}	bigBlockPtr->nextPtr = bigBlocks.nextPtr;	bigBlocks.nextPtr = bigBlockPtr;	bigBlockPtr->prevPtr = &bigBlocks;	bigBlockPtr->nextPtr->prevPtr = bigBlockPtr;	op = (union overhead *) (bigBlockPtr + 1);	op->ov_magic0 = op->ov_magic1 = MAGIC;	op->ov_index = 0xff;#ifdef MSTATS	nmalloc[NBUCKETS]++;#endif#ifdef RCHECK	/*	 * Record allocated size of block and	 * bound space with magic numbers.	 */	op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);	op->ov_rmagic = RMAGIC;	*(unsigned short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;#endif	Tcl_MutexUnlock(allocMutexPtr);	return (void *)(op+1);    }    /*     * Convert amount of memory requested into closest block size     * stored in hash buckets which satisfies request.     * Account for space used per block for accounting.     */#ifndef RCHECK    amt = 8;	/* size of first bucket */    bucket = 0;#else    amt = 16;	/* size of first bucket */    bucket = 1;#endif    while (nbytes + OVERHEAD > amt) {	amt <<= 1;	if (amt == 0) {	    Tcl_MutexUnlock(allocMutexPtr);	    return (NULL);	}	bucket++;    }    ASSERT( bucket < NBUCKETS );    /*     * If nothing in hash bucket right now,     * request more memory from the system.     */    if ((op = nextf[bucket]) == NULL) {	MoreCore(bucket);	if ((op = nextf[bucket]) == NULL) {	    Tcl_MutexUnlock(allocMutexPtr);	    return (NULL);	}    }    /*     * Remove from linked list     */    nextf[bucket] = op->ov_next;    op->ov_magic0 = op->ov_magic1 = MAGIC;    op->ov_index = (unsigned char) bucket;#ifdef MSTATS    nmalloc[bucket]++;#endif#ifdef RCHECK    /*     * Record allocated size of block and     * bound space with magic numbers.     */    op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);    op->ov_rmagic = RMAGIC;    *(unsigned short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;#endif    Tcl_MutexUnlock(allocMutexPtr);    return ((char *)(op + 1));}/* *---------------------------------------------------------------------- * * MoreCore --

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -