Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch nonmonotonic-obj-alloc Excluding Merge-Ins
This is equivalent to a diff from 208b2e859d to d61626209b
2014-09-08
| ||
21:36 | Zap outdated comment. Leaf check-in: d61626209b user: ferrieux tags: nonmonotonic-obj-alloc | |
2014-09-06
| ||
19:56 | Don't leak our temp sorted chunk table. check-in: a3fa5b8266 user: ferrieux tags: nonmonotonic-obj-alloc | |
2014-09-05
| ||
20:42 | merge trunk check-in: dee6e07687 user: ferrieux tags: nonmonotonic-obj-alloc | |
2014-09-04
| ||
22:05 | Remove ChannelHandlerEvent struct, which has never been used in all of recorded Tcl history. Still n... check-in: e2338e8828 user: dgp tags: trunk | |
2014-09-03
| ||
21:24 | Merging changes from trunk check-in: 6f6342b8fe user: hypnotoad tags: core_zip_vfs | |
19:44 | Distinguish hanging from crashing in exit tests. check-in: 208b2e859d user: ferrieux tags: trunk | |
15:48 | [132fad6fde]. Fixed GetCache to use TclpSysAlloc+memset instead of calloc. Now consistent with tclWi... check-in: da203cbda6 user: ashok tags: trunk | |
Changes to generic/tclBasic.c.
︙ | ︙ | |||
839 840 841 842 843 844 845 846 847 848 849 850 851 852 | * Create unsupported commands for debugging bytecode and objects. */ Tcl_CreateObjCommand(interp, "::tcl::unsupported::disassemble", Tcl_DisassembleObjCmd, NULL, NULL); Tcl_CreateObjCommand(interp, "::tcl::unsupported::representation", Tcl_RepresentationCmd, NULL, NULL); /* Adding the bytecode assembler command */ cmdPtr = (Command *) Tcl_NRCreateCommand(interp, "::tcl::unsupported::assemble", Tcl_AssembleObjCmd, TclNRAssembleObjCmd, NULL, NULL); cmdPtr->compileProc = &TclCompileAssembleCmd; | > > | 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 | * Create unsupported commands for debugging bytecode and objects. */ Tcl_CreateObjCommand(interp, "::tcl::unsupported::disassemble", Tcl_DisassembleObjCmd, NULL, NULL); Tcl_CreateObjCommand(interp, "::tcl::unsupported::representation", Tcl_RepresentationCmd, NULL, NULL); Tcl_CreateObjCommand(interp, "::tcl::unsupported::gc", Tcl_GcCmd, NULL, NULL); /* Adding the bytecode assembler command */ cmdPtr = (Command *) Tcl_NRCreateCommand(interp, "::tcl::unsupported::assemble", Tcl_AssembleObjCmd, TclNRAssembleObjCmd, NULL, NULL); cmdPtr->compileProc = &TclCompileAssembleCmd; |
︙ | ︙ |
Changes to generic/tclInt.h.
︙ | ︙ | |||
1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 | * TIP #268. * Values for the selection mode, i.e the package require preferences. */ enum PkgPreferOptions { PKG_PREFER_LATEST, PKG_PREFER_STABLE }; /* *---------------------------------------------------------------- * 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 | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 | * TIP #268. * Values for the selection mode, i.e the package require preferences. */ enum PkgPreferOptions { PKG_PREFER_LATEST, PKG_PREFER_STABLE }; /* *---------------------------------------------------------------- * These structures support gc *---------------------------------------------------------------- */ /* * Header starting each chunk of Tcl_Obj, to chain them for use by gc */ typedef struct ObjChunkHeader { struct ObjChunkHeader *next; /* chaining */ Tcl_Obj *end; /* address of last+1 */ } ObjChunkHeader; MODULE_SCOPE ObjChunkHeader *tclObjChunkList; /* initialised in tclObj.c */ /* * Cell of temporary sorted array of chunk ranges and counters, for * dichotomic search in gc */ typedef struct ObjChunkInfo { Tcl_Obj *beg,*end; /* [beg,end[ is the chunk's range */ long free; /* temporary counter for gc ; long for word-aligt */ } ObjChunkInfo; MODULE_SCOPE void TclpLockAlloc(void); MODULE_SCOPE void TclpUnlockAlloc(void); MODULE_SCOPE Tcl_Obj **TclpGetGlobalFreeObj(void); MODULE_SCOPE Tcl_Obj **TclpGetLocalFreeObj(void); MODULE_SCOPE void TclpRecomputeGlobalNumObj(void); MODULE_SCOPE void TclpRecomputeLocalNumObj(void); /* *---------------------------------------------------------------- * 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 |
︙ | ︙ | |||
3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 | Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int Tcl_ForeachObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int Tcl_FormatObjCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int Tcl_GetsObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int Tcl_GlobalObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); | > > > | 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 | Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int Tcl_ForeachObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int Tcl_FormatObjCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int Tcl_GcCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int Tcl_GetsObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int Tcl_GlobalObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); |
︙ | ︙ |
Changes to generic/tclObj.c.
︙ | ︙ | |||
46 47 48 49 50 51 52 53 54 55 56 57 58 59 | * Pointer to a heap-allocated string of length zero that the Tcl core uses as * the value of an empty string representation for an object. This value is * shared by all new objects allocated by Tcl_NewObj. */ char tclEmptyString = '\0'; char *tclEmptyStringRep = &tclEmptyString; #if defined(TCL_MEM_DEBUG) && defined(TCL_THREADS) /* * Structure for tracking the source file and line number where a given * Tcl_Obj was allocated. We also track the pointer to the Tcl_Obj itself, * for sanity checking purposes. */ | > > | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | * Pointer to a heap-allocated string of length zero that the Tcl core uses as * the value of an empty string representation for an object. This value is * shared by all new objects allocated by Tcl_NewObj. */ char tclEmptyString = '\0'; char *tclEmptyStringRep = &tclEmptyString; ObjChunkHeader *tclObjChunkList = NULL; #if defined(TCL_MEM_DEBUG) && defined(TCL_THREADS) /* * Structure for tracking the source file and line number where a given * Tcl_Obj was allocated. We also track the pointer to the Tcl_Obj itself, * for sanity checking purposes. */ |
︙ | ︙ | |||
1233 1234 1235 1236 1237 1238 1239 | */ #define OBJS_TO_ALLOC_EACH_TIME 100 void TclAllocateFreeObjects(void) { | | > | > > > > > | 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 | */ #define OBJS_TO_ALLOC_EACH_TIME 100 void TclAllocateFreeObjects(void) { size_t bytesToAlloc = (sizeof(ObjChunkHeader) + OBJS_TO_ALLOC_EACH_TIME * sizeof(Tcl_Obj)); char *basePtr; ObjChunkHeader *header; register Tcl_Obj *prevPtr, *objPtr; register int i; /* * This has been noted by Purify to be a potential leak. The problem is * that Tcl, when not TCL_MEM_DEBUG compiled, keeps around all allocated * Tcl_Obj's, pointed to by tclFreeObjList, when freed instead of actually * freeing the memory. TclFinalizeObjects() does not ckfree() this memory, * but leaves it to Tcl's memory subsystem finalization to release it. * Purify apparently can't figure that out, and fires a false alarm. */ header = (ObjChunkHeader *) ckalloc(bytesToAlloc); header->next = tclObjChunkList; header->end = (Tcl_Obj *)(((char *)header) + bytesToAlloc); tclObjChunkList = header; basePtr = (char *) (header + 1); prevPtr = NULL; objPtr = (Tcl_Obj *) basePtr; for (i = 0; i < OBJS_TO_ALLOC_EACH_TIME; i++) { objPtr->internalRep.twoPtrValue.ptr1 = prevPtr; prevPtr = objPtr; objPtr++; |
︙ | ︙ | |||
4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 | 16, "..."); Tcl_AppendToObj(descObj, "\"", -1); } else { Tcl_AppendToObj(descObj, ", no string representation", -1); } Tcl_SetObjResult(interp, descObj); return TCL_OK; } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * tab-width: 8 * indent-tabs-mode: nil * End: */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 | 16, "..."); Tcl_AppendToObj(descObj, "\"", -1); } else { Tcl_AppendToObj(descObj, ", no string representation", -1); } Tcl_SetObjResult(interp, descObj); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_GcCmd -- * * Implementation of the "tcl::unsupported::gc" command. * * Results: * {purged $nbobj chunks {$start $total $used $start $total $used ...}} * * Side effects: * None. * *---------------------------------------------------------------------- */ static void BailOut(void) { exit(127); } static void GcLog( const char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); } static int ComparePointers( const void *a, const void *b) { char *aa = *(char **)a; char *bb = *(char **)b; /* * BEWARE: ptr difference (aa-bb) is *not* a proper order * (an extra bit is needed for that) * Hence we resort to explicit pointer comparison * Which stores this bit in the Carry flag. */ return (aa<bb)?-1:((aa>bb)?1:0); } #define GC_BISECT_MIN_RECURS 4 static ObjChunkInfo * GC_FindChunkInfo( Tcl_Obj *obj, ObjChunkInfo *itab, int len) { while (1) { int mid; if (len <= GC_BISECT_MIN_RECURS) { int i; for(i = 0; i < len; i++, itab++) { if ((obj>=itab->beg)&&(obj<itab->end)) { return itab; } } /* no Panic : avoid dumping core with a huge heap */ GcLog("### GC internal error: no chunk enclosing obj %p\n",obj); BailOut(); } mid = len / 2; if (obj >= itab[mid].beg) { itab += mid; len -= mid; } else { len = mid; } } } #ifndef USE_THREAD_ALLOC void TclpLockAlloc(void) { Tcl_MutexLock(&tclObjMutex); } void TclpUnlockAlloc(void) { Tcl_MutexUnlock(&tclObjMutex); } Tcl_Obj ** TclpGetGlobalFreeObj(void) { return &tclFreeObjList; } Tcl_Obj ** TclpGetLocalFreeObj(void) { return NULL; } void TclpRecomputeGlobalNumObj(void) { } void TclpRecomputeLocalNumObj(void) { } # define FREE_INTERNAL ckfree #else # define FREE_INTERNAL free #endif static Tcl_Obj * DerefIf( Tcl_Obj **src) { return (src ? (*src) : NULL); } #define NEXT_OBJ(objPtr) \ ((objPtr)->internalRep.twoPtrValue.ptr1) int Tcl_GcCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { int nch, i, npurge; ObjChunkHeader *chunk, **tmp; ObjChunkInfo *info, *infotab; Tcl_Obj *obj; if (objc != 1) { Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; } TclpLockAlloc(); GcLog("GC Phase 1: prepare sorted list of chunk info\n"); nch = 0; for (chunk = tclObjChunkList; chunk; chunk = chunk->next) { nch++; } infotab = (ObjChunkInfo *) malloc(nch * sizeof(ObjChunkInfo)); tmp = (ObjChunkHeader **) infotab; /* pointers are smaller, so they fit */ for (chunk = tclObjChunkList; chunk; chunk = chunk->next) { *(tmp++) = chunk; } qsort(infotab, nch, sizeof(ObjChunkHeader *), ComparePointers); /* in-place cacheing of chunk headers into chunk infos */ for(i = nch - 1; i >= 0; i--) { chunk = ((ObjChunkHeader **) infotab)[i]; info = infotab + i; info->beg = (Tcl_Obj *)(chunk + 1); info->end = chunk->end; info->free = 0; } GcLog("GC Phase 2: scan free lists, locating each obj's chunk and " "updating its free count\n"); for (obj = DerefIf(TclpGetLocalFreeObj()); obj != NULL; obj = (Tcl_Obj *) NEXT_OBJ(obj)) { info = GC_FindChunkInfo(obj, infotab, nch); if (info) { info->free++; } } for (obj = DerefIf(TclpGetGlobalFreeObj()); obj != NULL; obj = (Tcl_Obj *) NEXT_OBJ(obj)) { info = GC_FindChunkInfo(obj, infotab, nch); if (info) { info->free++; } } GcLog("GC Phase 3: locate chunks entirely made of free objs and mark them " "with chunk->end=NULL and info->free=-1\n"); npurge = 0; for (i = 0, info = infotab; i < nch; i++, info++) { int room, delta; room = info->end - info->beg; delta = info->free - room; chunk = ((ObjChunkHeader *)info->beg) - 1; if (delta > 0) { GcLog("# GC internal error: chunk at %p counts %ld frees but has " "room for %d only !\n", chunk, info->free, room); BailOut(); } if (delta < 0) { #if 0 GcLog(" . chunk %p : %d / %d\n", chunk, -delta, room); #endif continue; } /* here we have a purgeable chunk */ npurge += room; chunk->end = NULL ; /* mark it for final sweep of chunks */ info->free = -1 ; /* mark it for final sweep of objs*/ #if 0 GcLog(" PURGE chunk %p : 0 / %d\n", chunk, room); #endif } if (!npurge) { GcLog(" Sorry - nothing to purge :(\n"); } else { GcLog("GC Phase 4: remove the soon-to-be-purged objs from free " "lists\n"); { Tcl_Obj **pobj; int n, p; n = p = 0; for (pobj = TclpGetLocalFreeObj(); *pobj != NULL ;) { n++; info = GC_FindChunkInfo(*pobj, infotab, nch); if (info->free != -1) { pobj = (Tcl_Obj **) & NEXT_OBJ(*pobj); } else { *pobj = (Tcl_Obj *) NEXT_OBJ(*pobj); p++; } } TclpRecomputeLocalNumObj(); GcLog(" (local: purge %d / %d\n", p, n); n = p = 0; for (pobj = TclpGetGlobalFreeObj(); *pobj != NULL ;) { n++; info = GC_FindChunkInfo(*pobj, infotab, nch); if (info->free != -1) { pobj = (Tcl_Obj **) & NEXT_OBJ(*pobj); } else { *pobj = (Tcl_Obj *) NEXT_OBJ(*pobj); p++; } } TclpRecomputeGlobalNumObj(); GcLog(" (global: purge %d / %d\n", p, n); } GcLog("GC Phase 5: free the located chunks, totalling %d objs\n", npurge); { ObjChunkHeader **pchunk; for (pchunk = &tclObjChunkList; (chunk = *pchunk) != NULL; ) { if (chunk->end) { pchunk = &chunk->next; } else { *pchunk = chunk->next; FREE_INTERNAL(chunk); } } } free(infotab); } TclpUnlockAlloc(); return TCL_OK; } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * tab-width: 8 * indent-tabs-mode: nil * End: */ |
Changes to generic/tclThreadAlloc.c.
︙ | ︙ | |||
564 565 566 567 568 569 570 | MoveObjs(sharedPtr, cachePtr, numMove); } Tcl_MutexUnlock(objLockPtr); if (cachePtr->numObjects == 0) { Tcl_Obj *newObjsPtr; cachePtr->numObjects = numMove = NOBJALLOC; | | > > > > > > > > > > | 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 | MoveObjs(sharedPtr, cachePtr, numMove); } Tcl_MutexUnlock(objLockPtr); if (cachePtr->numObjects == 0) { Tcl_Obj *newObjsPtr; cachePtr->numObjects = numMove = NOBJALLOC; newObjsPtr = (Tcl_Obj *)(((ObjChunkHeader *)TclpSysAlloc(sizeof(ObjChunkHeader) + sizeof(Tcl_Obj) * numMove, 0)) + 1); if (newObjsPtr == NULL) { Tcl_Panic("alloc: could not allocate %d new objects", numMove); } while (--numMove >= 0) { objPtr = &newObjsPtr[numMove]; objPtr->internalRep.twoPtrValue.ptr1 = cachePtr->firstObjPtr; cachePtr->firstObjPtr = objPtr; } { ObjChunkHeader *chunk = ((ObjChunkHeader *)newObjsPtr) - 1; chunk->end = newObjsPtr + NOBJALLOC; Tcl_MutexLock(objLockPtr); chunk->next = tclObjChunkList; tclObjChunkList = chunk; Tcl_MutexUnlock(objLockPtr); } } } /* * Pop the first object. */ |
︙ | ︙ | |||
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 | TclFinalizeThreadAllocThread(void) { Cache *cachePtr = TclpGetAllocCache(); if (cachePtr != NULL) { TclpFreeAllocCache(cachePtr); } } #else /* !(TCL_THREADS && USE_THREAD_ALLOC) */ /* *---------------------------------------------------------------------- * * Tcl_GetMemoryInfo -- * | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 | TclFinalizeThreadAllocThread(void) { Cache *cachePtr = TclpGetAllocCache(); if (cachePtr != NULL) { TclpFreeAllocCache(cachePtr); } } /* *---------------------------------------------------------------------- * * TclpLockAlloc, TclpUnlockAlloc, TclpGetGlobalFreeObj, TclpGetLocalFreeObj -- * These functions allow outside callers to reach safely into our internal * state for inspection or gc. *---------------------------------------------------------------------- */ void TclpLockAlloc(void) { Tcl_MutexLock(objLockPtr); } void TclpUnlockAlloc(void) { Tcl_MutexUnlock(objLockPtr); } Tcl_Obj ** TclpGetGlobalFreeObj(void) { return &sharedPtr->firstObjPtr; } Tcl_Obj ** TclpGetLocalFreeObj(void) { Cache *cachePtr; GETCACHE(cachePtr); return &cachePtr->firstObjPtr; } void TclpRecomputeGlobalNumObj(void) { int n; Tcl_Obj *obj; for(n=0,obj=sharedPtr->firstObjPtr;obj;obj=(Tcl_Obj *)obj->internalRep.twoPtrValue.ptr1,n++); sharedPtr->numObjects = n; } void TclpRecomputeLocalNumObj(void) { int n; Tcl_Obj *obj; Cache *cachePtr; GETCACHE(cachePtr); for(n=0,obj=cachePtr->firstObjPtr;obj;obj=(Tcl_Obj *)obj->internalRep.twoPtrValue.ptr1,n++); cachePtr->numObjects = n; } #else /* !(TCL_THREADS && USE_THREAD_ALLOC) */ /* *---------------------------------------------------------------------- * * Tcl_GetMemoryInfo -- * |
︙ | ︙ |