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

📄 tclthreadalloc.c

📁 tcl是工具命令语言
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * tclThreadAlloc.c -- * *	This is a very fast storage allocator for used with threads (designed *	avoid lock contention).  The basic strategy is to allocate memory in *  	fixed size blocks from block caches. *  * The Initial Developer of the Original Code is America Online, Inc. * Portions created by AOL are Copyright (C) 1999 America Online, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * RCS: @(#) $Id: tclThreadAlloc.c,v 1.4 2002/08/26 13:05:56 msofer Exp $ */#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)#include "tclInt.h"#ifdef WIN32#include "tclWinInt.h"#elseextern Tcl_Mutex *TclpNewAllocMutex(void);extern void *TclpGetAllocCache(void);extern void TclpSetAllocCache(void *);#endif/* * If range checking is enabled, an additional byte will be allocated * to store the magic number at the end of the requested memory. */#ifndef RCHECK#ifdef  NDEBUG#define RCHECK		0#else#define RCHECK		1#endif#endif/* * The following define the number of Tcl_Obj's to allocate/move * at a time and the high water mark to prune a per-thread cache. * On a 32 bit system, sizeof(Tcl_Obj) = 24 so 800 * 24 = ~16k. * */ #define NOBJALLOC	 800#define NOBJHIGH	1200/* * The following defines the number of buckets in the bucket * cache and those block sizes from (1<<4) to (1<<(3+NBUCKETS)) */#define NBUCKETS	  11#define MAXALLOC	  16284/* * The following union stores accounting information for * each block including two small magic numbers and * a bucket number when in use or a next pointer when * free.  The original requested size (not including * the Block overhead) is also maintained. */ typedef struct Block {    union {    	struct Block *next;	  /* Next in free list. */    	struct {	    unsigned char magic1; /* First magic number. */	    unsigned char bucket; /* Bucket block allocated from. */	    unsigned char unused; /* Padding. */	    unsigned char magic2; /* Second magic number. */        } b_s;    } b_u;    size_t b_reqsize;		  /* Requested allocation size. */} Block;#define b_next		b_u.next#define b_bucket	b_u.b_s.bucket#define b_magic1	b_u.b_s.magic1#define b_magic2	b_u.b_s.magic2#define MAGIC		0xef/* * The following structure defines a bucket of blocks with * various accounting and statistics information. */typedef struct Bucket {    Block *firstPtr;    int nfree;    int nget;    int nput;    int nwait;    int nlock;    int nrequest;} Bucket;/* * The following structure defines a cache of buckets and objs. */typedef struct Cache {    struct Cache  *nextPtr;    Tcl_ThreadId   owner;    Tcl_Obj       *firstObjPtr;    int            nobjs;    int	           nsysalloc;    Bucket         buckets[NBUCKETS];} Cache;/* * The following array specifies various per-bucket  * limits and locks.  The values are statically initialized * to avoid calculating them repeatedly. */struct binfo {    size_t blocksize;	/* Bucket blocksize. */    int maxblocks;	/* Max blocks before move to share. */    int nmove;		/* Num blocks to move to share. */    Tcl_Mutex *lockPtr; /* Share bucket lock. */} binfo[NBUCKETS] = {    {   16, 1024, 512, NULL},    {   32,  512, 256, NULL},    {   64,  256, 128, NULL},    {  128,  128,  64, NULL},    {  256,   64,  32, NULL},    {  512,   32,  16, NULL},    { 1024,   16,   8, NULL},    { 2048,    8,   4, NULL},    { 4096,    4,   2, NULL},    { 8192,    2,   1, NULL},    {16284,    1,   1, NULL},};/* * Static functions defined in this file. */static void LockBucket(Cache *cachePtr, int bucket);static void UnlockBucket(Cache *cachePtr, int bucket);static void PutBlocks(Cache *cachePtr, int bucket, int nmove);static int  GetBlocks(Cache *cachePtr, int bucket);static Block *Ptr2Block(char *ptr);static char *Block2Ptr(Block *blockPtr, int bucket, unsigned int reqsize);static void MoveObjs(Cache *fromPtr, Cache *toPtr, int nmove);/* * Local variables defined in this file and initialized at * startup. */static Tcl_Mutex *listLockPtr;static Tcl_Mutex *objLockPtr;static Cache     sharedCache;static Cache    *sharedPtr = &sharedCache;static Cache    *firstCachePtr = &sharedCache;/* *---------------------------------------------------------------------- * *  GetCache --- * *	Gets per-thread memory cache, allocating it if necessary. * * Results: *	Pointer to cache. * * Side effects: *  	None. * *---------------------------------------------------------------------- */static Cache *GetCache(void){    Cache *cachePtr;    /*     * Check for first-time initialization.     */    if (listLockPtr == NULL) {	Tcl_Mutex *initLockPtr;    	int i;	initLockPtr = Tcl_GetAllocMutex();	Tcl_MutexLock(initLockPtr);	if (listLockPtr == NULL) {	    listLockPtr = TclpNewAllocMutex();	    objLockPtr = TclpNewAllocMutex();	    for (i = 0; i < NBUCKETS; ++i) {	        binfo[i].lockPtr = TclpNewAllocMutex();	    }	}	Tcl_MutexUnlock(initLockPtr);    }    /*     * Get this thread's cache, allocating if necessary.     */    cachePtr = TclpGetAllocCache();    if (cachePtr == NULL) {    	cachePtr = calloc(1, sizeof(Cache));    	if (cachePtr == NULL) {	    panic("alloc: could not allocate new cache");    	}    	Tcl_MutexLock(listLockPtr);    	cachePtr->nextPtr = firstCachePtr;    	firstCachePtr = cachePtr;    	Tcl_MutexUnlock(listLockPtr);    	cachePtr->owner = Tcl_GetCurrentThread();	TclpSetAllocCache(cachePtr);    }    return cachePtr;}/* *---------------------------------------------------------------------- * *  TclFreeAllocCache -- * *	Flush and delete a cache, removing from list of caches. * * Results: *	None. * * Side effects: *	None. * *---------------------------------------------------------------------- */voidTclFreeAllocCache(void *arg){    Cache *cachePtr = arg;    Cache **nextPtrPtr;    register int   bucket;    /*     * Flush blocks.     */    for (bucket = 0; bucket < NBUCKETS; ++bucket) {	if (cachePtr->buckets[bucket].nfree > 0) {	    PutBlocks(cachePtr, bucket, cachePtr->buckets[bucket].nfree);	}    }    /*     * Flush objs.     */    if (cachePtr->nobjs > 0) {    	Tcl_MutexLock(objLockPtr);    	MoveObjs(cachePtr, sharedPtr, cachePtr->nobjs);    	Tcl_MutexUnlock(objLockPtr);    }    /*     * Remove from pool list.     */    Tcl_MutexLock(listLockPtr);    nextPtrPtr = &firstCachePtr;    while (*nextPtrPtr != cachePtr) {	nextPtrPtr = &(*nextPtrPtr)->nextPtr;    }    *nextPtrPtr = cachePtr->nextPtr;    cachePtr->nextPtr = NULL;    Tcl_MutexUnlock(listLockPtr);#ifdef WIN32    TlsFree((DWORD) cachePtr);#else    free(cachePtr);#endif}/* *---------------------------------------------------------------------- * *  TclpAlloc -- * *	Allocate memory. * * Results: *	Pointer to memory just beyond Block pointer. * * Side effects: *	May allocate more blocks for a bucket. * *---------------------------------------------------------------------- */char *TclpAlloc(unsigned int reqsize){    Cache         *cachePtr = TclpGetAllocCache();    Block         *blockPtr;    register int   bucket;    size_t  	   size;    if (cachePtr == NULL) {	cachePtr = GetCache();    }        /*     * Increment the requested size to include room for      * the Block structure.  Call malloc() directly if the     * required amount is greater than the largest block,     * otherwise pop the smallest block large enough,     * allocating more blocks if necessary.     */    blockPtr = NULL;         size = reqsize + sizeof(Block);#if RCHECK    ++size;#endif    if (size > MAXALLOC) {	bucket = NBUCKETS;    	blockPtr = malloc(size);	if (blockPtr != NULL) {	    cachePtr->nsysalloc += reqsize;	}    } else {    	bucket = 0;    	while (binfo[bucket].blocksize < size) {    	    ++bucket;    	}    	if (cachePtr->buckets[bucket].nfree || GetBlocks(cachePtr, bucket)) {	    blockPtr = cachePtr->buckets[bucket].firstPtr;	    cachePtr->buckets[bucket].firstPtr = blockPtr->b_next;	    --cachePtr->buckets[bucket].nfree;    	    ++cachePtr->buckets[bucket].nget;	    cachePtr->buckets[bucket].nrequest += reqsize;	}    }    if (blockPtr == NULL) {    	return NULL;    }    return Block2Ptr(blockPtr, bucket, reqsize);}/* *---------------------------------------------------------------------- * *  TclpFree -- * *	Return blocks to the thread block cache. * * Results: *	None. * * Side effects: *	May move blocks to shared cache. * *---------------------------------------------------------------------- */voidTclpFree(char *ptr){    if (ptr != NULL) {	Cache  *cachePtr = TclpGetAllocCache();	Block *blockPtr;	int bucket;	if (cachePtr == NULL) {	    cachePtr = GetCache();	} 	/*	 * Get the block back from the user pointer and	 * call system free directly for large blocks.	 * Otherwise, push the block back on the bucket and	 * move blocks to the shared cache if there are now	 * too many free.	 */	blockPtr = Ptr2Block(ptr);	bucket = blockPtr->b_bucket;	if (bucket == NBUCKETS) {	    cachePtr->nsysalloc -= blockPtr->b_reqsize;	    free(blockPtr);	} else {	    cachePtr->buckets[bucket].nrequest -= blockPtr->b_reqsize;	    blockPtr->b_next = cachePtr->buckets[bucket].firstPtr;	    cachePtr->buckets[bucket].firstPtr = blockPtr;	    ++cachePtr->buckets[bucket].nfree;	    ++cachePtr->buckets[bucket].nput;	    if (cachePtr != sharedPtr &&		    cachePtr->buckets[bucket].nfree > binfo[bucket].maxblocks) {		PutBlocks(cachePtr, bucket, binfo[bucket].nmove);	    }	}    }}/* *---------------------------------------------------------------------- * *  TclpRealloc -- * *	Re-allocate memory to a larger or smaller size. * * Results: *	Pointer to memory just beyond Block pointer. * * Side effects: *	Previous memory, if any, may be freed. * *---------------------------------------------------------------------- */char *TclpRealloc(char *ptr, unsigned int reqsize){    Cache *cachePtr = TclpGetAllocCache();    Block *blockPtr;    void *new;    size_t size, min;    int bucket;    if (ptr == NULL) {	return TclpAlloc(reqsize);    }    if (cachePtr == NULL) {	cachePtr = GetCache();    }    /*     * If the block is not a system block and fits in place,     * simply return the existing pointer.  Otherwise, if the block     * is a system block and the new size would also require a system     * block, call realloc() directly.     */    blockPtr = Ptr2Block(ptr);    size = reqsize + sizeof(Block);#if RCHECK    ++size;#endif    bucket = blockPtr->b_bucket;    if (bucket != NBUCKETS) {	if (bucket > 0) {	    min = binfo[bucket-1].blocksize;	} else {	    min = 0;	}	if (size > min && size <= binfo[bucket].blocksize) {	    cachePtr->buckets[bucket].nrequest -= blockPtr->b_reqsize;	    cachePtr->buckets[bucket].nrequest += reqsize;	    return Block2Ptr(blockPtr, bucket, reqsize);	}    } else if (size > MAXALLOC) {	cachePtr->nsysalloc -= blockPtr->b_reqsize;	cachePtr->nsysalloc += reqsize;	blockPtr = realloc(blockPtr, size);	if (blockPtr == NULL) {	    return NULL;	}	return Block2Ptr(blockPtr, NBUCKETS, reqsize);    }    /*     * Finally, perform an expensive malloc/copy/free.

⌨️ 快捷键说明

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