summaryrefslogtreecommitdiffstats
path: root/generic/tclThreadAlloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclThreadAlloc.c')
-rwxr-xr-x[-rw-r--r--]generic/tclThreadAlloc.c791
1 files changed, 376 insertions, 415 deletions
diff --git a/generic/tclThreadAlloc.c b/generic/tclThreadAlloc.c
index e4261d6..ad9f0a0 100644..100755
--- a/generic/tclThreadAlloc.c
+++ b/generic/tclThreadAlloc.c
@@ -2,22 +2,31 @@
* 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.
- *
+ * 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.
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "tclInt.h"
-#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)
+
+#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC) && !defined(TCL_MEM_DEBUG)
+
+#ifdef WIN32
+#include "tclWinInt.h"
+#else
+extern 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.
+ * 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
@@ -29,23 +38,33 @@
#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.
+ * 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
-#define NOBJALLOC 800
+/*
+ * Alignment for allocated memory.
+ */
-/* Actual definition moved to tclInt.h */
-#define NOBJHIGH ALLOC_NOBJHIGH
+#if defined(__APPLE__)
+#define ALLOCALIGN 16
+#else
+#define ALLOCALIGN 8
+#endif
/*
- * 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.
+ * 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 union Block {
struct {
union {
@@ -59,117 +78,93 @@ typedef union Block {
} u;
size_t reqSize; /* Requested allocation size. */
} b;
- unsigned char padding[TCL_ALLOCALIGN];
+ unsigned char padding[ALLOCALIGN];
} Block;
-#define nextBlock b.u.next
-#define sourceBucket b.u.s.bucket
-#define magicNum1 b.u.s.magic1
-#define magicNum2 b.u.s.magic2
-#define MAGIC 0xEF
-#define blockReqSize b.reqSize
+#define b_next b.u.next
+#define b_bucket b.u.s.bucket
+#define b_magic1 b.u.s.magic1
+#define b_magic2 b.u.s.magic2
+#define MAGIC 0xef
+#define b_reqsize b.reqSize
/*
* The following defines the minimum and and maximum block sizes and the number
* of buckets in the bucket cache.
*/
-#define MINALLOC ((sizeof(Block) + 8 + (TCL_ALLOCALIGN-1)) & ~(TCL_ALLOCALIGN-1))
+#define MINALLOC ((sizeof(Block) + 8 + (ALLOCALIGN-1)) & ~(ALLOCALIGN-1))
#define NBUCKETS (11 - (MINALLOC >> 5))
#define MAXALLOC (MINALLOC << (NBUCKETS - 1))
/*
- * The following structure defines a bucket of blocks with various accounting
- * and statistics information.
+ * The following structure defines a bucket of blocks with
+ * various accounting and statistics information.
*/
typedef struct Bucket {
- Block *firstPtr; /* First block available */
- long numFree; /* Number of blocks available */
-
- /* All fields below for accounting only */
-
- long numRemoves; /* Number of removes from bucket */
- long numInserts; /* Number of inserts into bucket */
- long numWaits; /* Number of waits to acquire a lock */
- long numLocks; /* Number of locks acquired */
- long totalAssigned; /* Total space assigned to bucket */
+ Block *firstPtr;
+ long nfree;
+ long nget;
+ long nput;
+ long nwait;
+ long nlock;
+ long nrequest;
} 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().
+ * The following structure defines a cache of buckets and objs.
*/
typedef struct Cache {
- struct Cache *nextPtr; /* Linked list of cache entries */
- 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 */
- int totalAssigned; /* Total space assigned to thread */
- Bucket buckets[NBUCKETS]; /* The buckets for this thread */
+ 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.
+ * The following array specifies various per-bucket
+ * limits and locks. The values are statically initialized
+ * to avoid calculating them repeatedly.
*/
-static struct {
- size_t blockSize; /* Bucket blocksize. */
- int maxBlocks; /* Max blocks before move to share. */
- int numMove; /* Num blocks to move to share. */
- Tcl_Mutex *lockPtr; /* Share bucket lock. */
-} bucketInfo[NBUCKETS];
+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];
/*
* Static functions defined in this file.
*/
-static Cache * GetCache(void);
-static void LockBucket(Cache *cachePtr, int bucket);
-static void UnlockBucket(Cache *cachePtr, int bucket);
-static void PutBlocks(Cache *cachePtr, int bucket, int numMove);
-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 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.
+ * 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;
-
-#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
+static Cache sharedCache;
+static Cache *sharedPtr = &sharedCache;
+static Cache *firstCachePtr = &sharedCache;
+
/*
*----------------------------------------------------------------------
*
- * GetCache ---
+ * GetCache ---
*
* Gets per-thread memory cache, allocating it if necessary.
*
@@ -177,7 +172,7 @@ static __thread Cache *tcachePtr;
* Pointer to cache.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
@@ -201,11 +196,10 @@ GetCache(void)
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();
+ binfo[i].blocksize = MINALLOC << i;
+ binfo[i].maxblocks = 1 << (NBUCKETS - 1 - i);
+ binfo[i].nmove = i < NBUCKETS-1 ? 1 << (NBUCKETS - 2 - i) : 1;
+ binfo[i].lockPtr = TclpNewAllocMutex();
}
}
Tcl_MutexUnlock(initLockPtr);
@@ -217,24 +211,25 @@ GetCache(void)
cachePtr = TclpGetAllocCache();
if (cachePtr == NULL) {
- cachePtr = calloc(1, sizeof(Cache));
- if (cachePtr == NULL) {
- Tcl_Panic("alloc: could not allocate new cache");
- }
- Tcl_MutexLock(listLockPtr);
- cachePtr->nextPtr = firstCachePtr;
- firstCachePtr = cachePtr;
- Tcl_MutexUnlock(listLockPtr);
- cachePtr->owner = Tcl_GetCurrentThread();
+ 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 --
+ * TclFreeAllocCache --
*
* Flush and delete a cache, removing from list of caches.
*
@@ -248,8 +243,7 @@ GetCache(void)
*/
void
-TclFreeAllocCache(
- void *arg)
+TclFreeAllocCache(void *arg)
{
Cache *cachePtr = arg;
Cache **nextPtrPtr;
@@ -260,8 +254,8 @@ TclFreeAllocCache(
*/
for (bucket = 0; bucket < NBUCKETS; ++bucket) {
- if (cachePtr->buckets[bucket].numFree > 0) {
- PutBlocks(cachePtr, bucket, cachePtr->buckets[bucket].numFree);
+ if (cachePtr->buckets[bucket].nfree > 0) {
+ PutBlocks(cachePtr, bucket, cachePtr->buckets[bucket].nfree);
}
}
@@ -269,10 +263,10 @@ TclFreeAllocCache(
* Flush objs.
*/
- if (cachePtr->numObjects > 0) {
- Tcl_MutexLock(objLockPtr);
- MoveObjs(cachePtr, sharedPtr, cachePtr->numObjects);
- Tcl_MutexUnlock(objLockPtr);
+ if (cachePtr->nobjs > 0) {
+ Tcl_MutexLock(objLockPtr);
+ MoveObjs(cachePtr, sharedPtr, cachePtr->nobjs);
+ Tcl_MutexUnlock(objLockPtr);
}
/*
@@ -289,11 +283,12 @@ TclFreeAllocCache(
Tcl_MutexUnlock(listLockPtr);
free(cachePtr);
}
+
/*
*----------------------------------------------------------------------
*
- * TclpAlloc --
+ * TclpAlloc --
*
* Allocate memory.
*
@@ -307,70 +302,72 @@ TclFreeAllocCache(
*/
char *
-TclpAlloc(
- unsigned int reqSize)
+TclpAlloc(unsigned int reqsize)
{
- Cache *cachePtr;
- Block *blockPtr;
- register int bucket;
- size_t size;
+ Cache *cachePtr;
+ Block *blockPtr;
+ register int bucket;
+ size_t size;
-#ifndef __LP64__
if (sizeof(int) >= sizeof(size_t)) {
/* An unsigned int overflow can also be a size_t overflow */
const size_t zero = 0;
const size_t max = ~zero;
- if (((size_t) reqSize) > max - sizeof(Block) - RCHECK) {
+ if (((size_t) reqsize) > max - sizeof(Block) - RCHECK) {
/* Requested allocation exceeds memory */
return NULL;
}
}
-#endif
-
- GETCACHE(cachePtr);
+ cachePtr = TclpGetAllocCache();
+ 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,
+ * 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);
+ blockPtr = NULL;
+ size = reqsize + sizeof(Block);
#if RCHECK
- size++;
+ ++size;
#endif
if (size > MAXALLOC) {
bucket = NBUCKETS;
- blockPtr = malloc(size);
+ blockPtr = malloc(size);
if (blockPtr != NULL) {
- cachePtr->totalAssigned += reqSize;
+ cachePtr->nsysalloc += reqsize;
}
} else {
- bucket = 0;
- while (bucketInfo[bucket].blockSize < size) {
- bucket++;
- }
- if (cachePtr->buckets[bucket].numFree || GetBlocks(cachePtr, bucket)) {
+ 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->nextBlock;
- cachePtr->buckets[bucket].numFree--;
- cachePtr->buckets[bucket].numRemoves++;
- cachePtr->buckets[bucket].totalAssigned += reqSize;
+ 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 NULL;
}
- return Block2Ptr(blockPtr, bucket, reqSize);
+ return Block2Ptr(blockPtr, bucket, reqsize);
}
+
/*
*----------------------------------------------------------------------
*
- * TclpFree --
+ * TclpFree --
*
* Return blocks to the thread block cache.
*
@@ -384,49 +381,49 @@ TclpAlloc(
*/
void
-TclpFree(
- char *ptr)
+TclpFree(char *ptr)
{
- Cache *cachePtr;
- Block *blockPtr;
- int bucket;
+ if (ptr != NULL) {
+ Cache *cachePtr = TclpGetAllocCache();
+ Block *blockPtr;
+ int bucket;
- if (ptr == NULL) {
- return;
- }
-
- GETCACHE(cachePtr);
-
- /*
- * 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->sourceBucket;
- if (bucket == NBUCKETS) {
- cachePtr->totalAssigned -= blockPtr->blockReqSize;
- free(blockPtr);
- return;
- }
-
- cachePtr->buckets[bucket].totalAssigned -= blockPtr->blockReqSize;
- blockPtr->nextBlock = cachePtr->buckets[bucket].firstPtr;
- cachePtr->buckets[bucket].firstPtr = blockPtr;
- cachePtr->buckets[bucket].numFree++;
- cachePtr->buckets[bucket].numInserts++;
+ 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.
+ */
- if (cachePtr != sharedPtr &&
- cachePtr->buckets[bucket].numFree > bucketInfo[bucket].maxBlocks) {
- PutBlocks(cachePtr, bucket, bucketInfo[bucket].numMove);
+ 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 --
+ * TclpRealloc --
*
* Re-allocate memory to a larger or smaller size.
*
@@ -440,82 +437,83 @@ TclpFree(
*/
char *
-TclpRealloc(
- char *ptr,
- unsigned int reqSize)
+TclpRealloc(char *ptr, unsigned int reqsize)
{
Cache *cachePtr;
Block *blockPtr;
- void *newPtr;
+ void *new;
size_t size, min;
int bucket;
if (ptr == NULL) {
- return TclpAlloc(reqSize);
+ return TclpAlloc(reqsize);
}
-#ifndef __LP64__
if (sizeof(int) >= sizeof(size_t)) {
/* An unsigned int overflow can also be a size_t overflow */
const size_t zero = 0;
const size_t max = ~zero;
- if (((size_t) reqSize) > max - sizeof(Block) - RCHECK) {
+ if (((size_t) reqsize) > max - sizeof(Block) - RCHECK) {
/* Requested allocation exceeds memory */
return NULL;
}
}
-#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 realloc() directly.
+ * 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);
+ size = reqsize + sizeof(Block);
#if RCHECK
- size++;
+ ++size;
#endif
- bucket = blockPtr->sourceBucket;
+ bucket = blockPtr->b_bucket;
if (bucket != NBUCKETS) {
if (bucket > 0) {
- min = bucketInfo[bucket-1].blockSize;
+ min = binfo[bucket-1].blocksize;
} else {
min = 0;
}
- if (size > min && size <= bucketInfo[bucket].blockSize) {
- cachePtr->buckets[bucket].totalAssigned -= blockPtr->blockReqSize;
- cachePtr->buckets[bucket].totalAssigned += reqSize;
- return Block2Ptr(blockPtr, bucket, reqSize);
+ 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->totalAssigned -= blockPtr->blockReqSize;
- cachePtr->totalAssigned += reqSize;
+ cachePtr->nsysalloc -= blockPtr->b_reqsize;
+ cachePtr->nsysalloc += reqsize;
blockPtr = realloc(blockPtr, size);
if (blockPtr == NULL) {
return NULL;
}
- return Block2Ptr(blockPtr, NBUCKETS, reqSize);
+ return Block2Ptr(blockPtr, NBUCKETS, reqsize);
}
/*
* Finally, perform an expensive malloc/copy/free.
*/
- newPtr = TclpAlloc(reqSize);
- if (newPtr != NULL) {
- if (reqSize > blockPtr->blockReqSize) {
- reqSize = blockPtr->blockReqSize;
+ new = TclpAlloc(reqsize);
+ if (new != NULL) {
+ if (reqsize > blockPtr->b_reqsize) {
+ reqsize = blockPtr->b_reqsize;
}
- memcpy(newPtr, ptr, reqSize);
- TclpFree(ptr);
+ memcpy(new, ptr, reqsize);
+ TclpFree(ptr);
}
- return newPtr;
+ return new;
}
+
/*
*----------------------------------------------------------------------
@@ -528,12 +526,8 @@ TclpRealloc(
* Pointer to uninitialized Tcl_Obj.
*
* Side effects:
- * 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
+ * May move Tcl_Obj's from shared cached or allocate new Tcl_Obj's
+ * if list is empty.
*
*----------------------------------------------------------------------
*/
@@ -541,38 +535,38 @@ TclpRealloc(
Tcl_Obj *
TclThreadAllocObj(void)
{
- register Cache *cachePtr;
+ register Cache *cachePtr = TclpGetAllocCache();
+ register int nmove;
register Tcl_Obj *objPtr;
+ Tcl_Obj *newObjsPtr;
- GETCACHE(cachePtr);
+ if (cachePtr == NULL) {
+ cachePtr = GetCache();
+ }
/*
- * Get this thread's obj list structure and move or allocate new objs if
- * necessary.
+ * Get this thread's obj list structure and move
+ * or allocate new objs if necessary.
*/
-
- if (cachePtr->numObjects == 0) {
- register int numMove;
-
- Tcl_MutexLock(objLockPtr);
- numMove = sharedPtr->numObjects;
- if (numMove > 0) {
- if (numMove > NOBJALLOC) {
- numMove = NOBJALLOC;
+
+ if (cachePtr->nobjs == 0) {
+ Tcl_MutexLock(objLockPtr);
+ nmove = sharedPtr->nobjs;
+ if (nmove > 0) {
+ if (nmove > NOBJALLOC) {
+ nmove = NOBJALLOC;
}
- MoveObjs(sharedPtr, cachePtr, numMove);
+ MoveObjs(sharedPtr, cachePtr, nmove);
}
- Tcl_MutexUnlock(objLockPtr);
- if (cachePtr->numObjects == 0) {
- Tcl_Obj *newObjsPtr;
-
- cachePtr->numObjects = numMove = NOBJALLOC;
- newObjsPtr = malloc(sizeof(Tcl_Obj) * numMove);
+ Tcl_MutexUnlock(objLockPtr);
+ if (cachePtr->nobjs == 0) {
+ cachePtr->nobjs = nmove = NOBJALLOC;
+ newObjsPtr = malloc(sizeof(Tcl_Obj) * nmove);
if (newObjsPtr == NULL) {
- Tcl_Panic("alloc: could not allocate %d new objects", numMove);
+ panic("alloc: could not allocate %d new objects", nmove);
}
- while (--numMove >= 0) {
- objPtr = &newObjsPtr[numMove];
+ while (--nmove >= 0) {
+ objPtr = &newObjsPtr[nmove];
objPtr->internalRep.otherValuePtr = cachePtr->firstObjPtr;
cachePtr->firstObjPtr = objPtr;
}
@@ -585,9 +579,10 @@ TclThreadAllocObj(void)
objPtr = cachePtr->firstObjPtr;
cachePtr->firstObjPtr = objPtr->internalRep.otherValuePtr;
- cachePtr->numObjects--;
+ --cachePtr->nobjs;
return objPtr;
}
+
/*
*----------------------------------------------------------------------
@@ -600,42 +595,41 @@ TclThreadAllocObj(void)
* None.
*
* 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
+ * May move free Tcl_Obj's to shared list upon hitting high
+ * water mark.
*
*----------------------------------------------------------------------
*/
void
-TclThreadFreeObj(
- Tcl_Obj *objPtr)
+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.
*/
-
+
objPtr->internalRep.otherValuePtr = cachePtr->firstObjPtr;
cachePtr->firstObjPtr = objPtr;
- cachePtr->numObjects++;
-
+ ++cachePtr->nobjs;
+
/*
- * If the number of free objects has exceeded the high water mark, move
- * some blocks to the shared list.
+ * If the number of free objects has exceeded the high
+ * water mark, move some blocks to the shared list.
*/
-
- if (cachePtr->numObjects > NOBJHIGH) {
+
+ if (cachePtr->nobjs > NOBJHIGH) {
Tcl_MutexLock(objLockPtr);
MoveObjs(cachePtr, sharedPtr, NOBJALLOC);
Tcl_MutexUnlock(objLockPtr);
}
}
+
/*
*----------------------------------------------------------------------
@@ -648,14 +642,13 @@ TclThreadFreeObj(
* None.
*
* Side effects:
- * List appended to given dstring.
+ * List appended to given dstring.
*
*----------------------------------------------------------------------
*/
void
-Tcl_GetMemoryInfo(
- Tcl_DString *dsPtr)
+Tcl_GetMemoryInfo(Tcl_DString *dsPtr)
{
Cache *cachePtr;
char buf[200];
@@ -666,27 +659,28 @@ Tcl_GetMemoryInfo(
while (cachePtr != NULL) {
Tcl_DStringStartSublist(dsPtr);
if (cachePtr == sharedPtr) {
- Tcl_DStringAppendElement(dsPtr, "shared");
+ Tcl_DStringAppendElement(dsPtr, "shared");
} else {
- sprintf(buf, "thread%p", cachePtr->owner);
- Tcl_DStringAppendElement(dsPtr, buf);
+ sprintf(buf, "thread%d", (int) cachePtr->owner);
+ Tcl_DStringAppendElement(dsPtr, buf);
}
for (n = 0; n < NBUCKETS; ++n) {
- sprintf(buf, "%lu %ld %ld %ld %ld %ld %ld",
- (unsigned long) bucketInfo[n].blockSize,
- cachePtr->buckets[n].numFree,
- cachePtr->buckets[n].numRemoves,
- cachePtr->buckets[n].numInserts,
- cachePtr->buckets[n].totalAssigned,
- cachePtr->buckets[n].numLocks,
- cachePtr->buckets[n].numWaits);
+ sprintf(buf, "%lu %ld %ld %ld %ld %ld %ld",
+ (unsigned long) binfo[n].blocksize,
+ cachePtr->buckets[n].nfree,
+ cachePtr->buckets[n].nget,
+ cachePtr->buckets[n].nput,
+ cachePtr->buckets[n].nrequest,
+ cachePtr->buckets[n].nlock,
+ cachePtr->buckets[n].nwait);
Tcl_DStringAppendElement(dsPtr, buf);
}
Tcl_DStringEndSublist(dsPtr);
- cachePtr = cachePtr->nextPtr;
+ cachePtr = cachePtr->nextPtr;
}
Tcl_MutexUnlock(listLockPtr);
}
+
/*
*----------------------------------------------------------------------
@@ -699,46 +693,45 @@ Tcl_GetMemoryInfo(
* None.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
static void
-MoveObjs(
- Cache *fromPtr,
- Cache *toPtr,
- int numMove)
+MoveObjs(Cache *fromPtr, Cache *toPtr, int nmove)
{
register Tcl_Obj *objPtr = fromPtr->firstObjPtr;
Tcl_Obj *fromFirstObjPtr = objPtr;
- toPtr->numObjects += numMove;
- fromPtr->numObjects -= numMove;
+ toPtr->nobjs += nmove;
+ fromPtr->nobjs -= nmove;
/*
- * Find the last object to be moved; set the next one (the first one not
- * to be moved) as the first object in the 'from' cache.
+ * Find the last object to be moved; set the next one
+ * (the first one not to be moved) as the first object
+ * in the 'from' cache.
*/
- while (--numMove) {
+ while (--nmove) {
objPtr = objPtr->internalRep.otherValuePtr;
}
- fromPtr->firstObjPtr = objPtr->internalRep.otherValuePtr;
+ fromPtr->firstObjPtr = objPtr->internalRep.otherValuePtr;
/*
- * Move all objects as a block - they are already linked to each other, we
- * just have to update the first and last.
+ * Move all objects as a block - they are already linked to
+ * each other, we just have to update the first and last.
*/
objPtr->internalRep.otherValuePtr = toPtr->firstObjPtr;
toPtr->firstObjPtr = fromFirstObjPtr;
}
+
/*
*----------------------------------------------------------------------
*
- * Block2Ptr, Ptr2Block --
+ * Block2Ptr, Ptr2Block --
*
* Convert between internal blocks and user pointers.
*
@@ -752,83 +745,84 @@ MoveObjs(
*/
static char *
-Block2Ptr(
- Block *blockPtr,
- int bucket,
- unsigned int reqSize)
+Block2Ptr(Block *blockPtr, int bucket, unsigned int reqsize)
{
register void *ptr;
- blockPtr->magicNum1 = blockPtr->magicNum2 = MAGIC;
- blockPtr->sourceBucket = bucket;
- blockPtr->blockReqSize = reqSize;
+ blockPtr->b_magic1 = blockPtr->b_magic2 = MAGIC;
+ blockPtr->b_bucket = bucket;
+ blockPtr->b_reqsize = reqsize;
ptr = ((void *) (blockPtr + 1));
#if RCHECK
- ((unsigned char *)(ptr))[reqSize] = MAGIC;
+ ((unsigned char *)(ptr))[reqsize] = MAGIC;
#endif
return (char *) ptr;
}
static Block *
-Ptr2Block(
- char *ptr)
+Ptr2Block(char *ptr)
{
register Block *blockPtr;
blockPtr = (((Block *) ptr) - 1);
- if (blockPtr->magicNum1 != MAGIC || blockPtr->magicNum2 != MAGIC) {
- Tcl_Panic("alloc: invalid block: %p: %x %x",
- blockPtr, blockPtr->magicNum1, blockPtr->magicNum2);
- }
+ if (blockPtr->b_magic1 != MAGIC
#if RCHECK
- if (((unsigned char *) ptr)[blockPtr->blockReqSize] != MAGIC) {
- Tcl_Panic("alloc: invalid block: %p: %x %x %x",
- blockPtr, blockPtr->magicNum1, blockPtr->magicNum2,
- ((unsigned char *) ptr)[blockPtr->blockReqSize]);
- }
+ || ((unsigned char *) ptr)[blockPtr->b_reqsize] != MAGIC
#endif
+ || blockPtr->b_magic2 != MAGIC) {
+ panic("alloc: invalid block: %p: %x %x %x\n",
+ blockPtr, blockPtr->b_magic1, blockPtr->b_magic2,
+ ((unsigned char *) ptr)[blockPtr->b_reqsize]);
+ }
return blockPtr;
}
+
/*
*----------------------------------------------------------------------
*
- * LockBucket, UnlockBucket --
+ * LockBucket, UnlockBucket --
*
* Set/unset the lock to access a bucket in the shared cache.
*
* Results:
- * None.
+ * None.
*
* Side effects:
- * Lock activity and contention are monitored globally and on a per-cache
- * basis.
+ * Lock activity and contention are monitored globally and on
+ * a per-cache basis.
*
*----------------------------------------------------------------------
*/
static void
-LockBucket(
- Cache *cachePtr,
- int bucket)
+LockBucket(Cache *cachePtr, int bucket)
{
- Tcl_MutexLock(bucketInfo[bucket].lockPtr);
- cachePtr->buckets[bucket].numLocks++;
- sharedPtr->buckets[bucket].numLocks++;
+#if 0
+ if (Tcl_MutexTryLock(binfo[bucket].lockPtr) != TCL_OK) {
+ Tcl_MutexLock(binfo[bucket].lockPtr);
+ ++cachePtr->buckets[bucket].nwait;
+ ++sharedPtr->buckets[bucket].nwait;
+ }
+#else
+ Tcl_MutexLock(binfo[bucket].lockPtr);
+#endif
+ ++cachePtr->buckets[bucket].nlock;
+ ++sharedPtr->buckets[bucket].nlock;
}
+
static void
-UnlockBucket(
- Cache *cachePtr,
- int bucket)
+UnlockBucket(Cache *cachePtr, int bucket)
{
- Tcl_MutexUnlock(bucketInfo[bucket].lockPtr);
+ Tcl_MutexUnlock(binfo[bucket].lockPtr);
}
+
/*
*----------------------------------------------------------------------
*
- * PutBlocks --
+ * PutBlocks --
*
* Return unused blocks to the shared cache.
*
@@ -842,42 +836,40 @@ UnlockBucket(
*/
static void
-PutBlocks(
- Cache *cachePtr,
- int bucket,
- int numMove)
+PutBlocks(Cache *cachePtr, int bucket, int nmove)
{
register Block *lastPtr, *firstPtr;
- register int n = numMove;
+ register int n = nmove;
/*
- * Before acquiring the lock, walk the block list to find the last block
- * to be moved.
+ * Before acquiring the lock, walk the block list to find
+ * the last block to be moved.
*/
firstPtr = lastPtr = cachePtr->buckets[bucket].firstPtr;
while (--n > 0) {
- lastPtr = lastPtr->nextBlock;
+ lastPtr = lastPtr->b_next;
}
- cachePtr->buckets[bucket].firstPtr = lastPtr->nextBlock;
- cachePtr->buckets[bucket].numFree -= numMove;
+ cachePtr->buckets[bucket].firstPtr = lastPtr->b_next;
+ cachePtr->buckets[bucket].nfree -= nmove;
/*
- * Aquire the lock and place the list of blocks at the front of the shared
- * cache bucket.
+ * Aquire the lock and place the list of blocks at the front
+ * of the shared cache bucket.
*/
LockBucket(cachePtr, bucket);
- lastPtr->nextBlock = sharedPtr->buckets[bucket].firstPtr;
+ lastPtr->b_next = sharedPtr->buckets[bucket].firstPtr;
sharedPtr->buckets[bucket].firstPtr = firstPtr;
- sharedPtr->buckets[bucket].numFree += numMove;
+ sharedPtr->buckets[bucket].nfree += nmove;
UnlockBucket(cachePtr, bucket);
}
+
/*
*----------------------------------------------------------------------
*
- * GetBlocks --
+ * GetBlocks --
*
* Get more blocks for a bucket.
*
@@ -891,69 +883,67 @@ PutBlocks(
*/
static int
-GetBlocks(
- Cache *cachePtr,
- int bucket)
+GetBlocks(Cache *cachePtr, int bucket)
{
register Block *blockPtr;
register int n;
+ register size_t size;
/*
- * First, atttempt to move blocks from the shared cache. Note the
- * potentially dirty read of numFree before acquiring the lock which is a
- * slight performance enhancement. The value is verified after the lock is
- * actually acquired.
+ * First, atttempt to move blocks from the shared cache. Note
+ * the potentially dirty read of nfree before acquiring the lock
+ * which is a slight performance enhancement. The value is
+ * verified after the lock is actually acquired.
*/
-
- if (cachePtr != sharedPtr && sharedPtr->buckets[bucket].numFree > 0) {
+
+ if (cachePtr != sharedPtr && sharedPtr->buckets[bucket].nfree > 0) {
LockBucket(cachePtr, bucket);
- if (sharedPtr->buckets[bucket].numFree > 0) {
+ if (sharedPtr->buckets[bucket].nfree > 0) {
/*
- * Either move the entire list or walk the list to find the last
- * block to move.
+ * Either move the entire list or walk the list to find
+ * the last block to move.
*/
- n = bucketInfo[bucket].numMove;
- if (n >= sharedPtr->buckets[bucket].numFree) {
+ n = binfo[bucket].nmove;
+ if (n >= sharedPtr->buckets[bucket].nfree) {
cachePtr->buckets[bucket].firstPtr =
- sharedPtr->buckets[bucket].firstPtr;
- cachePtr->buckets[bucket].numFree =
- sharedPtr->buckets[bucket].numFree;
+ sharedPtr->buckets[bucket].firstPtr;
+ cachePtr->buckets[bucket].nfree =
+ sharedPtr->buckets[bucket].nfree;
sharedPtr->buckets[bucket].firstPtr = NULL;
- sharedPtr->buckets[bucket].numFree = 0;
+ sharedPtr->buckets[bucket].nfree = 0;
} else {
blockPtr = sharedPtr->buckets[bucket].firstPtr;
cachePtr->buckets[bucket].firstPtr = blockPtr;
- sharedPtr->buckets[bucket].numFree -= n;
- cachePtr->buckets[bucket].numFree = n;
+ sharedPtr->buckets[bucket].nfree -= n;
+ cachePtr->buckets[bucket].nfree = n;
while (--n > 0) {
- blockPtr = blockPtr->nextBlock;
+ blockPtr = blockPtr->b_next;
}
- sharedPtr->buckets[bucket].firstPtr = blockPtr->nextBlock;
- blockPtr->nextBlock = NULL;
+ sharedPtr->buckets[bucket].firstPtr = blockPtr->b_next;
+ blockPtr->b_next = NULL;
}
}
UnlockBucket(cachePtr, bucket);
}
-
- if (cachePtr->buckets[bucket].numFree == 0) {
- register size_t size;
+
+ if (cachePtr->buckets[bucket].nfree == 0) {
/*
- * If no blocks could be moved from shared, first look for a larger
- * block in this cache to split up.
+ * If no blocks could be moved from shared, first look for a
+ * larger block in this cache to split up.
*/
- blockPtr = NULL;
+ blockPtr = NULL;
n = NBUCKETS;
size = 0; /* lint */
while (--n > bucket) {
- if (cachePtr->buckets[n].numFree > 0) {
- size = bucketInfo[n].blockSize;
+ if (cachePtr->buckets[n].nfree > 0) {
+ size = binfo[n].blocksize;
blockPtr = cachePtr->buckets[n].firstPtr;
- cachePtr->buckets[n].firstPtr = blockPtr->nextBlock;
- cachePtr->buckets[n].numFree--;
+ cachePtr->buckets[n].firstPtr = blockPtr->b_next;
+ --cachePtr->buckets[n].nfree;
break;
}
}
@@ -974,26 +964,26 @@ GetBlocks(
* Split the larger block into smaller blocks for this bucket.
*/
- n = size / bucketInfo[bucket].blockSize;
- cachePtr->buckets[bucket].numFree = n;
+ n = size / binfo[bucket].blocksize;
+ cachePtr->buckets[bucket].nfree = n;
cachePtr->buckets[bucket].firstPtr = blockPtr;
while (--n > 0) {
- blockPtr->nextBlock = (Block *)
- ((char *) blockPtr + bucketInfo[bucket].blockSize);
- blockPtr = blockPtr->nextBlock;
+ blockPtr->b_next = (Block *)
+ ((char *) blockPtr + binfo[bucket].blocksize);
+ blockPtr = blockPtr->b_next;
}
- blockPtr->nextBlock = NULL;
+ blockPtr->b_next = NULL;
}
return 1;
}
-
+
/*
*----------------------------------------------------------------------
*
* TclFinalizeThreadAlloc --
*
- * This procedure is used to destroy all private resources used in this
- * file.
+ * This procedure is used to destroy all private resources used in
+ * this file.
*
* Results:
* None.
@@ -1005,13 +995,13 @@ GetBlocks(
*/
void
-TclFinalizeThreadAlloc(void)
+TclFinalizeThreadAlloc()
{
unsigned int i;
for (i = 0; i < NBUCKETS; ++i) {
- TclpFreeAllocMutex(bucketInfo[i].lockPtr);
- bucketInfo[i].lockPtr = NULL;
+ TclpFreeAllocMutex(binfo[i].lockPtr);
+ binfo[i].lockPtr = NULL;
}
TclpFreeAllocMutex(objLockPtr);
@@ -1023,37 +1013,15 @@ TclFinalizeThreadAlloc(void)
TclpFreeAllocCache(NULL);
}
-#else /* !(TCL_THREADS && USE_THREAD_ALLOC) */
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_GetMemoryInfo --
- *
- * Return a list-of-lists of memory stats.
- *
- * Results:
- * None.
- *
- * Side effects:
- * List appended to given dstring.
- *
- *----------------------------------------------------------------------
- */
+#else /* ! defined(TCL_THREADS) && ! defined(USE_THREAD_ALLOC) */
-void
-Tcl_GetMemoryInfo(
- Tcl_DString *dsPtr)
-{
- Tcl_Panic("Tcl_GetMemoryInfo called when threaded memory allocator not in use");
-}
-
/*
*----------------------------------------------------------------------
*
* TclFinalizeThreadAlloc --
*
- * This procedure is used to destroy all private resources used in this
- * file.
+ * This procedure is used to destroy all private resources used in
+ * this file.
*
* Results:
* None.
@@ -1065,16 +1033,9 @@ Tcl_GetMemoryInfo(
*/
void
-TclFinalizeThreadAlloc(void)
+TclFinalizeThreadAlloc()
{
- Tcl_Panic("TclFinalizeThreadAlloc called when threaded memory allocator not in use");
+ Tcl_Panic("TclFinalizeThreadAlloc called when threaded memory allocator not in use.");
}
-#endif /* TCL_THREADS && USE_THREAD_ALLOC */
-
-/*
- * Local Variables:
- * mode: c
- * c-basic-offset: 4
- * fill-column: 78
- * End:
- */
+
+#endif /* TCL_THREADS */