summaryrefslogtreecommitdiffstats
path: root/generic/tclInt.h
diff options
context:
space:
mode:
authorMiguel Sofer <miguel.sofer@gmail.com>2008-07-29 18:19:08 (GMT)
committerMiguel Sofer <miguel.sofer@gmail.com>2008-07-29 18:19:08 (GMT)
commite0dc5ad1dac50c004c16b1b5945aeda964c40ecd (patch)
tree5b6f051382e2f35069953bec645baefdad1b9e97 /generic/tclInt.h
parentd63487fc10c65ca57db9496dc4300e63faece5fa (diff)
downloadtcl-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.h103
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; \