diff options
Diffstat (limited to 'generic/tclThreadAlloc.c')
| -rw-r--r-- | generic/tclThreadAlloc.c | 288 |
1 files changed, 87 insertions, 201 deletions
diff --git a/generic/tclThreadAlloc.c b/generic/tclThreadAlloc.c index 8077de4..106e908 100644 --- a/generic/tclThreadAlloc.c +++ b/generic/tclThreadAlloc.c @@ -35,9 +35,7 @@ */ #define NOBJALLOC 800 - -/* Actual definition moved to tclInt.h */ -#define NOBJHIGH ALLOC_NOBJHIGH +#define NOBJHIGH 1200 /* * The following union stores accounting information for each block including @@ -84,7 +82,6 @@ typedef union Block { typedef struct Bucket { Block *firstPtr; /* First block available */ - Block *lastPtr; /* End of block list */ long numFree; /* Number of blocks available */ /* All fields below for accounting only */ @@ -98,9 +95,7 @@ typedef struct Bucket { /* * The following structure defines a cache of buckets and objs, of which there - * will be (at most) one per thread. Any changes need to be reflected in the - * struct AllocCache defined in tclInt.h, possibly also in the initialisation - * code in Tcl_CreateInterp(). + * will be (at most) one per thread. */ typedef struct Cache { @@ -108,7 +103,6 @@ typedef struct Cache { Tcl_ThreadId owner; /* Which thread's cache is this? */ Tcl_Obj *firstObjPtr; /* List of free objects for thread */ int numObjects; /* Number of objects for thread */ - Tcl_Obj *lastPtr; /* Last object in this cache */ int totalAssigned; /* Total space assigned to thread */ Bucket buckets[NBUCKETS]; /* The buckets for this thread */ } Cache; @@ -137,7 +131,6 @@ 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 numMove); -static void PutObjs(Cache *fromPtr, int numMove); /* * Local variables defined in this file and initialized at startup. @@ -148,26 +141,6 @@ static Tcl_Mutex *objLockPtr; static Cache sharedCache; static Cache *sharedPtr = &sharedCache; static Cache *firstCachePtr = &sharedCache; - -#if defined(HAVE_FAST_TSD) -static __thread Cache *tcachePtr; - -# define GETCACHE(cachePtr) \ - do { \ - if (!tcachePtr) { \ - tcachePtr = GetCache(); \ - } \ - (cachePtr) = tcachePtr; \ - } while (0) -#else -# define GETCACHE(cachePtr) \ - do { \ - (cachePtr) = TclpGetAllocCache(); \ - if ((cachePtr) == NULL) { \ - (cachePtr) = GetCache(); \ - } \ - } while (0) -#endif /* *---------------------------------------------------------------------- @@ -196,11 +169,20 @@ GetCache(void) if (listLockPtr == NULL) { Tcl_Mutex *initLockPtr; + unsigned int i; initLockPtr = Tcl_GetAllocMutex(); Tcl_MutexLock(initLockPtr); if (listLockPtr == NULL) { - TclInitThreadAlloc(); + listLockPtr = TclpNewAllocMutex(); + objLockPtr = TclpNewAllocMutex(); + for (i = 0; i < NBUCKETS; ++i) { + bucketInfo[i].blockSize = MINALLOC << i; + bucketInfo[i].maxBlocks = 1 << (NBUCKETS - 1 - i); + bucketInfo[i].numMove = i < NBUCKETS - 1 ? + 1 << (NBUCKETS - 2 - i) : 1; + bucketInfo[i].lockPtr = TclpNewAllocMutex(); + } } Tcl_MutexUnlock(initLockPtr); } @@ -211,11 +193,10 @@ GetCache(void) cachePtr = TclpGetAllocCache(); if (cachePtr == NULL) { - cachePtr = TclpSysAlloc(sizeof(Cache), 0); + cachePtr = calloc(1, sizeof(Cache)); if (cachePtr == NULL) { Tcl_Panic("alloc: could not allocate new cache"); } - memset(cachePtr, 0, sizeof(Cache)); Tcl_MutexLock(listLockPtr); cachePtr->nextPtr = firstCachePtr; firstCachePtr = cachePtr; @@ -265,7 +246,9 @@ TclFreeAllocCache( */ if (cachePtr->numObjects > 0) { - PutObjs(cachePtr, cachePtr->numObjects); + Tcl_MutexLock(objLockPtr); + MoveObjs(cachePtr, sharedPtr, cachePtr->numObjects); + Tcl_MutexUnlock(objLockPtr); } /* @@ -280,7 +263,7 @@ TclFreeAllocCache( *nextPtrPtr = cachePtr->nextPtr; cachePtr->nextPtr = NULL; Tcl_MutexUnlock(listLockPtr); - TclpSysFree(cachePtr); + free(cachePtr); } /* @@ -321,11 +304,14 @@ TclpAlloc( } #endif - GETCACHE(cachePtr); + cachePtr = TclpGetAllocCache(); + if (cachePtr == NULL) { + cachePtr = GetCache(); + } /* * Increment the requested size to include room for the Block structure. - * Call TclpSysAlloc() directly if the required amount is greater than the + * 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. */ @@ -333,24 +319,24 @@ TclpAlloc( blockPtr = NULL; size = reqSize + sizeof(Block); #if RCHECK - size++; + ++size; #endif if (size > MAXALLOC) { bucket = NBUCKETS; - blockPtr = TclpSysAlloc(size, 0); + blockPtr = malloc(size); if (blockPtr != NULL) { cachePtr->totalAssigned += reqSize; } } else { bucket = 0; while (bucketInfo[bucket].blockSize < size) { - bucket++; + ++bucket; } if (cachePtr->buckets[bucket].numFree || GetBlocks(cachePtr, bucket)) { blockPtr = cachePtr->buckets[bucket].firstPtr; cachePtr->buckets[bucket].firstPtr = blockPtr->nextBlock; - cachePtr->buckets[bucket].numFree--; - cachePtr->buckets[bucket].numRemoves++; + --cachePtr->buckets[bucket].numFree; + ++cachePtr->buckets[bucket].numRemoves; cachePtr->buckets[bucket].totalAssigned += reqSize; } } @@ -388,7 +374,10 @@ TclpFree( return; } - GETCACHE(cachePtr); + cachePtr = TclpGetAllocCache(); + if (cachePtr == NULL) { + cachePtr = GetCache(); + } /* * Get the block back from the user pointer and call system free directly @@ -400,18 +389,15 @@ TclpFree( bucket = blockPtr->sourceBucket; if (bucket == NBUCKETS) { cachePtr->totalAssigned -= blockPtr->blockReqSize; - TclpSysFree(blockPtr); + free(blockPtr); return; } cachePtr->buckets[bucket].totalAssigned -= blockPtr->blockReqSize; blockPtr->nextBlock = cachePtr->buckets[bucket].firstPtr; cachePtr->buckets[bucket].firstPtr = blockPtr; - if (cachePtr->buckets[bucket].numFree == 0) { - cachePtr->buckets[bucket].lastPtr = blockPtr; - } - cachePtr->buckets[bucket].numFree++; - cachePtr->buckets[bucket].numInserts++; + ++cachePtr->buckets[bucket].numFree; + ++cachePtr->buckets[bucket].numInserts; if (cachePtr != sharedPtr && cachePtr->buckets[bucket].numFree > bucketInfo[bucket].maxBlocks) { @@ -463,18 +449,21 @@ TclpRealloc( } #endif - GETCACHE(cachePtr); + cachePtr = TclpGetAllocCache(); + 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 TclpSysRealloc() directly. + * size would also require a system block, call realloc() directly. */ blockPtr = Ptr2Block(ptr); size = reqSize + sizeof(Block); #if RCHECK - size++; + ++size; #endif bucket = blockPtr->sourceBucket; if (bucket != NBUCKETS) { @@ -491,7 +480,7 @@ TclpRealloc( } else if (size > MAXALLOC) { cachePtr->totalAssigned -= blockPtr->blockReqSize; cachePtr->totalAssigned += reqSize; - blockPtr = TclpSysRealloc(blockPtr, size); + blockPtr = realloc(blockPtr, size); if (blockPtr == NULL) { return NULL; } @@ -527,20 +516,18 @@ TclpRealloc( * May move Tcl_Obj's from shared cached or allocate new Tcl_Obj's if * list is empty. * - * Note: - * If this code is updated, the changes need to be reflected in the macro - * TclAllocObjStorageEx() defined in tclInt.h - * *---------------------------------------------------------------------- */ Tcl_Obj * TclThreadAllocObj(void) { - register Cache *cachePtr; + register Cache *cachePtr = TclpGetAllocCache(); register Tcl_Obj *objPtr; - GETCACHE(cachePtr); + if (cachePtr == NULL) { + cachePtr = GetCache(); + } /* * Get this thread's obj list structure and move or allocate new objs if @@ -563,17 +550,15 @@ TclThreadAllocObj(void) Tcl_Obj *newObjsPtr; cachePtr->numObjects = numMove = NOBJALLOC; - newObjsPtr = TclpSysAlloc(sizeof(Tcl_Obj) * numMove, 0); + newObjsPtr = malloc(sizeof(Tcl_Obj) * numMove); if (newObjsPtr == NULL) { Tcl_Panic("alloc: could not allocate %d new objects", numMove); } - cachePtr->lastPtr = newObjsPtr + numMove - 1; - objPtr = cachePtr->firstObjPtr; /* NULL */ while (--numMove >= 0) { - newObjsPtr[numMove].internalRep.twoPtrValue.ptr1 = objPtr; - objPtr = newObjsPtr + numMove; + objPtr = &newObjsPtr[numMove]; + objPtr->internalRep.twoPtrValue.ptr1 = cachePtr->firstObjPtr; + cachePtr->firstObjPtr = objPtr; } - cachePtr->firstObjPtr = newObjsPtr; } } @@ -583,7 +568,7 @@ TclThreadAllocObj(void) objPtr = cachePtr->firstObjPtr; cachePtr->firstObjPtr = objPtr->internalRep.twoPtrValue.ptr1; - cachePtr->numObjects--; + --cachePtr->numObjects; return objPtr; } @@ -600,10 +585,6 @@ TclThreadAllocObj(void) * Side effects: * May move free Tcl_Obj's to shared list upon hitting high water mark. * - * Note: - * If this code is updated, the changes need to be reflected in the macro - * TclAllocObjStorageEx() defined in tclInt.h - * *---------------------------------------------------------------------- */ @@ -611,9 +592,11 @@ void TclThreadFreeObj( Tcl_Obj *objPtr) { - Cache *cachePtr; + Cache *cachePtr = TclpGetAllocCache(); - GETCACHE(cachePtr); + if (cachePtr == NULL) { + cachePtr = GetCache(); + } /* * Get this thread's list and push on the free Tcl_Obj. @@ -621,10 +604,7 @@ TclThreadFreeObj( objPtr->internalRep.twoPtrValue.ptr1 = cachePtr->firstObjPtr; cachePtr->firstObjPtr = objPtr; - if (cachePtr->numObjects == 0) { - cachePtr->lastPtr = objPtr; - } - cachePtr->numObjects++; + ++cachePtr->numObjects; /* * If the number of free objects has exceeded the high water mark, move @@ -632,7 +612,9 @@ TclThreadFreeObj( */ if (cachePtr->numObjects > NOBJHIGH) { - PutObjs(cachePtr, NOBJALLOC); + Tcl_MutexLock(objLockPtr); + MoveObjs(cachePtr, sharedPtr, NOBJALLOC); + Tcl_MutexUnlock(objLockPtr); } } @@ -730,67 +712,13 @@ MoveObjs( * just have to update the first and last. */ - toPtr->lastPtr = objPtr; - objPtr->internalRep.twoPtrValue.ptr1 = toPtr->firstObjPtr; /* NULL */ + objPtr->internalRep.twoPtrValue.ptr1 = toPtr->firstObjPtr; toPtr->firstObjPtr = fromFirstObjPtr; } /* *---------------------------------------------------------------------- * - * PutObjs -- - * - * Move Tcl_Obj's from thread cache to shared cache. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static void -PutObjs( - Cache *fromPtr, - int numMove) -{ - int keep = fromPtr->numObjects - numMove; - Tcl_Obj *firstPtr, *lastPtr = NULL; - - fromPtr->numObjects = keep; - firstPtr = fromPtr->firstObjPtr; - if (keep == 0) { - fromPtr->firstObjPtr = NULL; - } else { - do { - lastPtr = firstPtr; - firstPtr = firstPtr->internalRep.twoPtrValue.ptr1; - } while (--keep > 0); - lastPtr->internalRep.twoPtrValue.ptr1 = NULL; - } - - /* - * Move all objects as a block - they are already linked to each other, we - * just have to update the first and last. - */ - - Tcl_MutexLock(objLockPtr); - fromPtr->lastPtr->internalRep.twoPtrValue.ptr1 = sharedPtr->firstObjPtr; - sharedPtr->firstObjPtr = firstPtr; - if (sharedPtr->numObjects == 0) { - sharedPtr->lastPtr = fromPtr->lastPtr; - } - sharedPtr->numObjects += numMove; - Tcl_MutexUnlock(objLockPtr); - - fromPtr->lastPtr = lastPtr; -} - -/* - *---------------------------------------------------------------------- - * * Block2Ptr, Ptr2Block -- * * Convert between internal blocks and user pointers. @@ -865,9 +793,17 @@ LockBucket( Cache *cachePtr, int bucket) { +#if 0 + if (Tcl_MutexTryLock(bucketInfo[bucket].lockPtr) != TCL_OK) { + Tcl_MutexLock(bucketInfo[bucket].lockPtr); + ++cachePtr->buckets[bucket].numWaits; + ++sharedPtr->buckets[bucket].numWaits; + } +#else Tcl_MutexLock(bucketInfo[bucket].lockPtr); - cachePtr->buckets[bucket].numLocks++; - sharedPtr->buckets[bucket].numLocks++; +#endif + ++cachePtr->buckets[bucket].numLocks; + ++sharedPtr->buckets[bucket].numLocks; } static void @@ -900,25 +836,20 @@ PutBlocks( int bucket, int numMove) { + register Block *lastPtr, *firstPtr; + register int n = numMove; + /* - * We have numFree. Want to shed numMove. So compute how many - * Blocks to keep. + * Before acquiring the lock, walk the block list to find the last block + * to be moved. */ - int keep = cachePtr->buckets[bucket].numFree - numMove; - Block *lastPtr = NULL, *firstPtr; - - cachePtr->buckets[bucket].numFree = keep; - firstPtr = cachePtr->buckets[bucket].firstPtr; - if (keep == 0) { - cachePtr->buckets[bucket].firstPtr = NULL; - } else { - do { - lastPtr = firstPtr; - firstPtr = firstPtr->nextBlock; - } while (--keep > 0); - lastPtr->nextBlock = NULL; + firstPtr = lastPtr = cachePtr->buckets[bucket].firstPtr; + while (--n > 0) { + lastPtr = lastPtr->nextBlock; } + cachePtr->buckets[bucket].firstPtr = lastPtr->nextBlock; + cachePtr->buckets[bucket].numFree -= numMove; /* * Aquire the lock and place the list of blocks at the front of the shared @@ -926,17 +857,10 @@ PutBlocks( */ LockBucket(cachePtr, bucket); - cachePtr->buckets[bucket].lastPtr->nextBlock - = sharedPtr->buckets[bucket].firstPtr; + lastPtr->nextBlock = sharedPtr->buckets[bucket].firstPtr; sharedPtr->buckets[bucket].firstPtr = firstPtr; - if (sharedPtr->buckets[bucket].numFree == 0) { - sharedPtr->buckets[bucket].lastPtr - = cachePtr->buckets[bucket].lastPtr; - } sharedPtr->buckets[bucket].numFree += numMove; UnlockBucket(cachePtr, bucket); - - cachePtr->buckets[bucket].lastPtr = lastPtr; } /* @@ -983,8 +907,6 @@ GetBlocks( if (n >= sharedPtr->buckets[bucket].numFree) { cachePtr->buckets[bucket].firstPtr = sharedPtr->buckets[bucket].firstPtr; - cachePtr->buckets[bucket].lastPtr = - sharedPtr->buckets[bucket].lastPtr; cachePtr->buckets[bucket].numFree = sharedPtr->buckets[bucket].numFree; sharedPtr->buckets[bucket].firstPtr = NULL; @@ -998,7 +920,6 @@ GetBlocks( blockPtr = blockPtr->nextBlock; } sharedPtr->buckets[bucket].firstPtr = blockPtr->nextBlock; - cachePtr->buckets[bucket].lastPtr = blockPtr; blockPtr->nextBlock = NULL; } } @@ -1021,7 +942,7 @@ GetBlocks( size = bucketInfo[n].blockSize; blockPtr = cachePtr->buckets[n].firstPtr; cachePtr->buckets[n].firstPtr = blockPtr->nextBlock; - cachePtr->buckets[n].numFree--; + --cachePtr->buckets[n].numFree; break; } } @@ -1032,7 +953,7 @@ GetBlocks( if (blockPtr == NULL) { size = MAXALLOC; - blockPtr = TclpSysAlloc(size, 0); + blockPtr = malloc(size); if (blockPtr == NULL) { return 0; } @@ -1050,45 +971,10 @@ GetBlocks( ((char *) blockPtr + bucketInfo[bucket].blockSize); blockPtr = blockPtr->nextBlock; } - cachePtr->buckets[bucket].lastPtr = blockPtr; blockPtr->nextBlock = NULL; } return 1; } - -/* - *---------------------------------------------------------------------- - * - * TclInitThreadAlloc -- - * - * Initializes the allocator cache-maintenance structures. - * It is done early and protected during the TclInitSubsystems(). - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -TclInitThreadAlloc(void) -{ - unsigned int i; - - listLockPtr = TclpNewAllocMutex(); - objLockPtr = TclpNewAllocMutex(); - for (i = 0; i < NBUCKETS; ++i) { - bucketInfo[i].blockSize = MINALLOC << i; - bucketInfo[i].maxBlocks = 1 << (NBUCKETS - 1 - i); - bucketInfo[i].numMove = i < NBUCKETS - 1 ? - 1 << (NBUCKETS - 2 - i) : 1; - bucketInfo[i].lockPtr = TclpNewAllocMutex(); - } - TclpInitAllocCache(); -} /* *---------------------------------------------------------------------- @@ -1113,8 +999,8 @@ TclFinalizeThreadAlloc(void) unsigned int i; for (i = 0; i < NBUCKETS; ++i) { - TclpFreeAllocMutex(bucketInfo[i].lockPtr); - bucketInfo[i].lockPtr = NULL; + TclpFreeAllocMutex(bucketInfo[i].lockPtr); + bucketInfo[i].lockPtr = NULL; } TclpFreeAllocMutex(objLockPtr); @@ -1131,9 +1017,9 @@ TclFinalizeThreadAlloc(void) * * TclFinalizeThreadAllocThread -- * - * This procedure is used to destroy single thread private resources - * defined in this file. Called either during Tcl_FinalizeThread() or - * Tcl_Finalize(). + * This procedure is used to destroy single thread private resources used + * in this file. + * Called in TclpFinalizeThreadData when a thread exits (Tcl_FinalizeThread). * * Results: * None. |
