diff options
author | Miguel Sofer <miguel.sofer@gmail.com> | 2008-07-29 18:19:08 (GMT) |
---|---|---|
committer | Miguel Sofer <miguel.sofer@gmail.com> | 2008-07-29 18:19:08 (GMT) |
commit | e0dc5ad1dac50c004c16b1b5945aeda964c40ecd (patch) | |
tree | 5b6f051382e2f35069953bec645baefdad1b9e97 /generic/tclInt.h | |
parent | d63487fc10c65ca57db9496dc4300e63faece5fa (diff) | |
download | tcl-e0dc5ad1dac50c004c16b1b5945aeda964c40ecd.zip tcl-e0dc5ad1dac50c004c16b1b5945aeda964c40ecd.tar.gz tcl-e0dc5ad1dac50c004c16b1b5945aeda964c40ecd.tar.bz2 |
* generic/tclBasic.c: Made use of the thread's alloc cache
* generic/tclInt.h: stored in the ekeko at interp creation
* generic/tclNRE.h: to avoid hitting the TSD each time an
* generic/tclThreadAlloc.c: NRE callback is pushed or pulled; the
approach is suitably general to extend to evry other obj
allocation where an interp is know; this is left for some other
time, requires a lot of grunt work.
Diffstat (limited to 'generic/tclInt.h')
-rw-r--r-- | generic/tclInt.h | 103 |
1 files changed, 80 insertions, 23 deletions
diff --git a/generic/tclInt.h b/generic/tclInt.h index 1b10fc6..fb77ec5 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -14,7 +14,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclInt.h,v 1.380 2008/07/29 05:30:32 msofer Exp $ + * RCS: @(#) $Id: tclInt.h,v 1.381 2008/07/29 18:19:12 msofer Exp $ */ #ifndef _TCLINT @@ -1602,6 +1602,24 @@ enum PkgPreferOptions { /* *---------------------------------------------------------------- + * This structure shadows the first few fields of the memory cache for the + * allocator defined in tclThreadAlloc.c; it has to be kept in sync with the + * definition there. + * Some macros require knowledge of some fields in the struct in order to + * avoid hitting the TSD unnecessarily. In order to facilitate this, a pointer + * to the relevant fields is kept in the objCache field in struct Interp. + *---------------------------------------------------------------- + */ + +typedef struct AllocCache { + 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 */ +} AllocCache; + +/* + *---------------------------------------------------------------- * This structure defines an interpreter, which is a collection of commands * plus other state information related to interpreting commands, such as * variable storage. Primary responsibility for this data structure is in @@ -1928,17 +1946,12 @@ typedef struct Interp { * They are used by the macros defined below. */ - void *allocCache; + AllocCache *allocCache; void *pendingObjDataPtr; /* Pointer to the Cache and PendingObjData * structs for this interp's thread; see * tclObj.c and tclThreadAlloc.c */ int *asyncReadyPtr; /* Pointer to the asyncReady indicator for * this interp's thread; see tclAsync.c */ - int *stackBound; /* Pointer to the limit stack address - * allowable for invoking a new command - * without "risking" a C-stack overflow; see - * TclpCheckStackSpace in the platform's - * directory. */ /* * The pointer to the object system root ekeko. c.f. TIP #257. @@ -3411,6 +3424,12 @@ MODULE_SCOPE unsigned TclHashObjKey(Tcl_HashTable *tablePtr, void *keyPtr); # define TclIncrObjsFreed() #endif /* TCL_COMPILE_STATS */ +# define TclAllocObjStorage(objPtr) \ + TclAllocObjStorageEx(NULL, (objPtr)) + +# define TclFreeObjStorage(objPtr) \ + TclFreeObjStorageEx(NULL, (objPtr)) + #ifndef TCL_MEM_DEBUG # define TclNewObj(objPtr) \ TclIncrObjsAllocated(); \ @@ -3453,10 +3472,10 @@ MODULE_SCOPE unsigned TclHashObjKey(Tcl_HashTable *tablePtr, void *keyPtr); * track memory leaks */ -# define TclAllocObjStorage(objPtr) \ +# define TclAllocObjStorageEx(interp, objPtr) \ (objPtr) = (Tcl_Obj *) Tcl_Alloc(sizeof(Tcl_Obj)) -# define TclFreeObjStorage(objPtr) \ +# define TclFreeObjStorageEx(interp, objPtr) \ ckfree((char *) (objPtr)) #undef USE_THREAD_ALLOC @@ -3476,11 +3495,43 @@ MODULE_SCOPE void TclpSetAllocCache(void *); MODULE_SCOPE void TclpFreeAllocMutex(Tcl_Mutex *mutex); MODULE_SCOPE void TclpFreeAllocCache(void *); -# define TclAllocObjStorage(objPtr) \ - (objPtr) = TclThreadAllocObj() - -# define TclFreeObjStorage(objPtr) \ - TclThreadFreeObj((objPtr)) +/* + * These macros need to be kept in sync with the code of TclThreadAllocObj() + * and TclThreadFreeObj(). + * + * Note that the optimiser should resolve the case (interp==NULL) at compile + * time. + */ + +# define ALLOC_NOBJHIGH 1200 + +# define TclAllocObjStorageEx(interp, objPtr) \ + do { \ + AllocCache *cachePtr; \ + if (((interp) == NULL) || \ + ((cachePtr = ((Interp *)(interp))->allocCache), \ + (cachePtr->numObjects == 0))) { \ + (objPtr) = TclThreadAllocObj(); \ + } else { \ + (objPtr) = cachePtr->firstObjPtr; \ + cachePtr->firstObjPtr = (objPtr)->internalRep.otherValuePtr; \ + --cachePtr->numObjects; \ + } \ + } while (0) + +# define TclFreeObjStorageEx(interp, objPtr) \ + do { \ + AllocCache *cachePtr; \ + if (((interp) == NULL) || \ + ((cachePtr = ((Interp *)(interp))->allocCache), \ + (cachePtr->numObjects >= ALLOC_NOBJHIGH))) { \ + TclThreadFreeObj(objPtr); \ + } else { \ + (objPtr)->internalRep.otherValuePtr = cachePtr->firstObjPtr; \ + cachePtr->firstObjPtr = objPtr; \ + ++cachePtr->numObjects; \ + } \ + } while (0) #else /* not PURIFY or USE_THREAD_ALLOC */ @@ -3489,7 +3540,7 @@ MODULE_SCOPE void TclpFreeAllocCache(void *); MODULE_SCOPE Tcl_Mutex tclObjMutex; #endif -# define TclAllocObjStorage(objPtr) \ +# define TclAllocObjStorageEx(interp, objPtr) \ Tcl_MutexLock(&tclObjMutex); \ if (tclFreeObjList == NULL) { \ TclAllocateFreeObjects(); \ @@ -3499,7 +3550,7 @@ MODULE_SCOPE Tcl_Mutex tclObjMutex; tclFreeObjList->internalRep.otherValuePtr; \ Tcl_MutexUnlock(&tclObjMutex) -# define TclFreeObjStorage(objPtr) \ +# define TclFreeObjStorageEx(interp, objPtr) \ Tcl_MutexLock(&tclObjMutex); \ (objPtr)->internalRep.otherValuePtr = (void *) tclFreeObjList; \ tclFreeObjList = (objPtr); \ @@ -3957,8 +4008,14 @@ MODULE_SCOPE void TclBNInitBignumFromWideUInt(mp_int *bignum, * DO NOT LET THEM CROSS THREAD BOUNDARIES */ +#define TclSmallAlloc(nbytes, memPtr) \ + TclSmallAllocEx(NULL, (nbytes), (memPtr)) + +#define TclSmallFree(memPtr) \ + TclSmallFreeEx(NULL, (memPtr)) + #ifndef TCL_MEM_DEBUG -#define TclSmallAlloc(nbytes, memPtr) \ +#define TclSmallAllocEx(interp, nbytes, memPtr) \ { \ Tcl_Obj *objPtr; \ switch ((nbytes)>sizeof(Tcl_Obj)) { \ @@ -3969,16 +4026,16 @@ MODULE_SCOPE void TclBNInitBignumFromWideUInt(mp_int *bignum, case 0: (void)0; \ } \ TclIncrObjsAllocated(); \ - TclAllocObjStorage(objPtr); \ - memPtr = (ClientData) objPtr; \ + TclAllocObjStorageEx((interp), (objPtr)); \ + memPtr = (ClientData) (objPtr); \ } -#define TclSmallFree(memPtr) \ - TclFreeObjStorage((Tcl_Obj *) memPtr); \ +#define TclSmallFreeEx(interp, memPtr) \ + TclFreeObjStorageEx((interp), (Tcl_Obj *) (memPtr)); \ TclIncrObjsFreed() #else /* TCL_MEM_DEBUG */ -#define TclSmallAlloc(nbytes, memPtr) \ +#define TclSmallAllocEx(interp, nbytes, memPtr) \ { \ Tcl_Obj *objPtr; \ switch ((nbytes)>sizeof(Tcl_Obj)) { \ @@ -3992,7 +4049,7 @@ MODULE_SCOPE void TclBNInitBignumFromWideUInt(mp_int *bignum, memPtr = (ClientData) objPtr; \ } -#define TclSmallFree(memPtr) \ +#define TclSmallFreeEx(interp, memPtr) \ { \ Tcl_Obj *objPtr = (Tcl_Obj *) memPtr; \ objPtr->bytes = NULL; \ |