Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | [SF Bug 271] Use refcounts to manage ItclObject lifecycle. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
e98b14aa2805934d5bf636846fb3c790 |
User & Date: | dgp 2017-10-29 21:14:02 |
Context
2017-11-28
| ||
17:12 | [SF Bug 279] Drop surplus quote. check-in: 7d61f6d79a user: dgp tags: trunk | |
2017-10-29
| ||
21:14 | [SF Bug 271] Use refcounts to manage ItclObject lifecycle. check-in: e98b14aa28 user: dgp tags: trunk | |
2017-10-24
| ||
16:23 | [SF Itcl Bug 278] itcl::is object -class filtered away namespace context before search. check-in: 94bb83e707 user: dgp tags: trunk | |
Changes
Changes to generic/itclClass.c.
︙ | ︙ | |||
966 967 968 969 970 971 972 | */ hPtr = Tcl_FirstHashEntry(&iclsPtr->infoPtr->objects, &place); while (hPtr) { ioPtr = (ItclObject*)Tcl_GetHashValue(hPtr); if (ioPtr->iclsPtr == iclsPtr) { if ((ioPtr->accessCmd != NULL) && (!(ioPtr->flags & (ITCL_OBJECT_IS_DESTRUCTED)))) { | | | | 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 | */ hPtr = Tcl_FirstHashEntry(&iclsPtr->infoPtr->objects, &place); while (hPtr) { ioPtr = (ItclObject*)Tcl_GetHashValue(hPtr); if (ioPtr->iclsPtr == iclsPtr) { if ((ioPtr->accessCmd != NULL) && (!(ioPtr->flags & (ITCL_OBJECT_IS_DESTRUCTED)))) { ItclPreserveObject(ioPtr); Tcl_DeleteCommandFromToken(iclsPtr->interp, ioPtr->accessCmd); ioPtr->accessCmd = NULL; ItclReleaseObject(ioPtr); /* * Fix 227804: Whenever an object to delete was found we * have to reset the search to the beginning as the * current entry in the search was deleted and accessing it * is therefore not allowed anymore. */ |
︙ | ︙ |
Changes to generic/itclInt.h.
︙ | ︙ | |||
381 382 383 384 385 386 387 388 389 390 391 392 393 394 | Tcl_Obj *hullWindowNamePtr; /* the window path name for the hull * (before renaming in installhull) */ int destructorHasBeenCalled; /* is set when the destructor is called * to avoid callin destructor twice */ int noComponentTrace; /* don't call component traces if * setting components in DelegationInstall */ int hadConstructorError; /* needed for multiple calls of CallItclObjectCmd */ } ItclObject; #define ITCL_IGNORE_ERRS 0x002 /* useful for construction/destruction */ typedef struct ItclResolveInfo { int flags; ItclClass *iclsPtr; | > | 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 | Tcl_Obj *hullWindowNamePtr; /* the window path name for the hull * (before renaming in installhull) */ int destructorHasBeenCalled; /* is set when the destructor is called * to avoid callin destructor twice */ int noComponentTrace; /* don't call component traces if * setting components in DelegationInstall */ int hadConstructorError; /* needed for multiple calls of CallItclObjectCmd */ int refCount; } ItclObject; #define ITCL_IGNORE_ERRS 0x002 /* useful for construction/destruction */ typedef struct ItclResolveInfo { int flags; ItclClass *iclsPtr; |
︙ | ︙ | |||
682 683 684 685 686 687 688 689 690 691 692 693 694 695 | Tcl_ObjectContext contextPtr, Tcl_CallFrame *framePtr, int *isFinished); MODULE_SCOPE void ItclPreserveIMF(ItclMemberFunc *imPtr); MODULE_SCOPE void ItclReleaseIMF(ClientData imPtr); MODULE_SCOPE void ItclPreserveClass(ItclClass *iclsPtr); MODULE_SCOPE void ItclReleaseClass(ClientData iclsPtr); MODULE_SCOPE ItclFoundation *ItclGetFoundation(Tcl_Interp *interp); MODULE_SCOPE Tcl_ObjCmdProc ItclClassCommandDispatcher; MODULE_SCOPE Tcl_Command Itcl_CmdAliasProc(Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *cmdName, ClientData clientData); MODULE_SCOPE Tcl_Var Itcl_VarAliasProc(Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *VarName, ClientData clientData); | > > > | 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 | Tcl_ObjectContext contextPtr, Tcl_CallFrame *framePtr, int *isFinished); MODULE_SCOPE void ItclPreserveIMF(ItclMemberFunc *imPtr); MODULE_SCOPE void ItclReleaseIMF(ClientData imPtr); MODULE_SCOPE void ItclPreserveClass(ItclClass *iclsPtr); MODULE_SCOPE void ItclReleaseClass(ClientData iclsPtr); MODULE_SCOPE void ItclPreserveObject(ItclObject *ioPtr); MODULE_SCOPE void ItclReleaseObject(ClientData ioPtr); MODULE_SCOPE ItclFoundation *ItclGetFoundation(Tcl_Interp *interp); MODULE_SCOPE Tcl_ObjCmdProc ItclClassCommandDispatcher; MODULE_SCOPE Tcl_Command Itcl_CmdAliasProc(Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *cmdName, ClientData clientData); MODULE_SCOPE Tcl_Var Itcl_VarAliasProc(Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *VarName, ClientData clientData); |
︙ | ︙ |
Changes to generic/itclMethod.c.
︙ | ︙ | |||
2461 2462 2463 2464 2465 2466 2467 | stackPtr = (Itcl_Stack *)Tcl_GetHashValue(hPtr); } Itcl_PushStack(framePtr, stackPtr); if (ioPtr != NULL) { ioPtr->callRefCount++; | | | 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 | stackPtr = (Itcl_Stack *)Tcl_GetHashValue(hPtr); } Itcl_PushStack(framePtr, stackPtr); if (ioPtr != NULL) { ioPtr->callRefCount++; ItclPreserveObject(ioPtr); } imPtr->iclsPtr->callRefCount++; if (!imPtr->iclsPtr->infoPtr->useOldResolvers) { Itcl_SetCallFrameResolver(interp, ioPtr->resolvePtr); } result = TCL_OK; |
︙ | ︙ | |||
2576 2577 2578 2579 2580 2581 2582 | if (callContextPtr->refCount == 0) { if (callContextPtr->ioPtr != NULL) { hPtr = Tcl_FindHashEntry(&callContextPtr->ioPtr->contextCache, (char *)callContextPtr->imPtr); if (hPtr == NULL) { ckfree((char *)callContextPtr); } | | | 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 | if (callContextPtr->refCount == 0) { if (callContextPtr->ioPtr != NULL) { hPtr = Tcl_FindHashEntry(&callContextPtr->ioPtr->contextCache, (char *)callContextPtr->imPtr); if (hPtr == NULL) { ckfree((char *)callContextPtr); } ItclReleaseObject(ioPtr); } else { ckfree((char *)callContextPtr); } } result = call_result; finishReturn: ItclReleaseIMF(imPtr); |
︙ | ︙ |
Changes to generic/itclObject.c.
︙ | ︙ | |||
66 67 68 69 70 71 72 73 74 75 76 77 78 79 | static int ItclInitObjectOptions(Tcl_Interp *interp, ItclObject *ioPtr, ItclClass *iclsPtr); static const char * GetConstructorVar(Tcl_Interp *interp, ItclClass *iclsPtr, const char *varName); static ItclClass * GetClassFromClassName(Tcl_Interp *interp, const char *className, ItclClass *iclsPtr); /* * ------------------------------------------------------------------------ * ItclDeleteObjectMetadata() * * Delete the metadata data if any *------------------------------------------------------------------------- | > > > > > > > > > > > > > > > > > > | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | static int ItclInitObjectOptions(Tcl_Interp *interp, ItclObject *ioPtr, ItclClass *iclsPtr); static const char * GetConstructorVar(Tcl_Interp *interp, ItclClass *iclsPtr, const char *varName); static ItclClass * GetClassFromClassName(Tcl_Interp *interp, const char *className, ItclClass *iclsPtr); void ItclPreserveObject( ItclObject *ioPtr) { ioPtr->refCount++; } void ItclReleaseObject( ClientData clientData) { ItclObject *ioPtr = (ItclObject *)clientData; if (--ioPtr->refCount == 0) { ItclFreeObject((char *) clientData); } } /* * ------------------------------------------------------------------------ * ItclDeleteObjectMetadata() * * Delete the metadata data if any *------------------------------------------------------------------------- |
︙ | ︙ | |||
265 266 267 268 269 270 271 | } /* * Add a command to the current namespace with the object name. * This is done before invoking the constructors so that the * command can be used during construction to query info. */ | | | 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | } /* * Add a command to the current namespace with the object name. * This is done before invoking the constructors so that the * command can be used during construction to query info. */ ItclPreserveObject(ioPtr); ioPtr->namePtr = Tcl_NewStringObj(name, -1); Tcl_IncrRefCount(ioPtr->namePtr); nsName = Tcl_GetCurrentNamespace(interp)->fullName; ioPtr->origNamePtr = Tcl_NewStringObj("", -1); if ((name[0] != ':') && (name[1] != ':')) { Tcl_AppendToObj(ioPtr->origNamePtr, nsName, -1); |
︙ | ︙ | |||
295 296 297 298 299 300 301 | Tcl_InitObjHashTable(&ioPtr->objectOptions); Tcl_InitObjHashTable(&ioPtr->objectComponents); Tcl_InitObjHashTable(&ioPtr->objectDelegatedOptions); Tcl_InitObjHashTable(&ioPtr->objectDelegatedFunctions); Tcl_InitObjHashTable(&ioPtr->objectMethodVariables); Tcl_InitHashTable(&ioPtr->contextCache, TCL_ONE_WORD_KEYS); | | < | 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | Tcl_InitObjHashTable(&ioPtr->objectOptions); Tcl_InitObjHashTable(&ioPtr->objectComponents); Tcl_InitObjHashTable(&ioPtr->objectDelegatedOptions); Tcl_InitObjHashTable(&ioPtr->objectDelegatedFunctions); Tcl_InitObjHashTable(&ioPtr->objectMethodVariables); Tcl_InitHashTable(&ioPtr->contextCache, TCL_ONE_WORD_KEYS); ItclPreserveObject(ioPtr); /* * Install the class namespace and object context so that * the object's data members can be initialized via simple * "set" commands. */ |
︙ | ︙ | |||
491 492 493 494 495 496 497 | if (ioPtr->accessCmd != (Tcl_Command) NULL) { Tcl_DeleteCommandFromToken(interp, ioPtr->accessCmd); ioPtr->accessCmd = NULL; } result = Itcl_RestoreInterpState(interp, istate); infoPtr->currIoPtr = saveCurrIoPtr; /* need this for 2 ReleaseData at errorReturn!! */ | | | 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 | if (ioPtr->accessCmd != (Tcl_Command) NULL) { Tcl_DeleteCommandFromToken(interp, ioPtr->accessCmd); ioPtr->accessCmd = NULL; } result = Itcl_RestoreInterpState(interp, istate); infoPtr->currIoPtr = saveCurrIoPtr; /* need this for 2 ReleaseData at errorReturn!! */ ItclPreserveObject(ioPtr); goto errorReturn; } else { /* a constructor cannot return a result as the object name * is returned as result */ Tcl_ResetResult(interp); } |
︙ | ︙ | |||
540 541 542 543 544 545 546 | */ if (ioPtr->accessCmd != (Tcl_Command) NULL) { Tcl_DeleteCommandFromToken(interp, ioPtr->accessCmd); ioPtr->accessCmd = NULL; } result = Itcl_RestoreInterpState(interp, istate); /* need this for 2 ReleaseData at errorReturn!! */ | | | 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 | */ if (ioPtr->accessCmd != (Tcl_Command) NULL) { Tcl_DeleteCommandFromToken(interp, ioPtr->accessCmd); ioPtr->accessCmd = NULL; } result = Itcl_RestoreInterpState(interp, istate); /* need this for 2 ReleaseData at errorReturn!! */ ItclPreserveObject(ioPtr); goto errorReturn; } if (iclsPtr->flags & ITCL_WIDGETADAPTOR) { if (saveNsNamePtr) { Tcl_SetVar2Ex(interp, "::itcl::internal::varNsName", name, |
︙ | ︙ | |||
592 593 594 595 596 597 598 | istate = Itcl_SaveInterpState(interp, result); if (ioPtr->accessCmd != (Tcl_Command) NULL) { Tcl_DeleteCommandFromToken(interp, ioPtr->accessCmd); ioPtr->accessCmd = NULL; } result = Itcl_RestoreInterpState(interp, istate); /* need this for 2 ReleaseData at errorReturn!! */ | | | 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 | istate = Itcl_SaveInterpState(interp, result); if (ioPtr->accessCmd != (Tcl_Command) NULL) { Tcl_DeleteCommandFromToken(interp, ioPtr->accessCmd); ioPtr->accessCmd = NULL; } result = Itcl_RestoreInterpState(interp, istate); /* need this for 2 ReleaseData at errorReturn!! */ ItclPreserveObject(ioPtr); goto errorReturn; } } /* * Add it to the list of all known objects. The only * tricky thing to watch out for is the case where the |
︙ | ︙ | |||
684 685 686 687 688 689 690 | infoPtr->currIoPtr = saveCurrIoPtr; } infoPtr->lastIoPtr = ioPtr; Tcl_DeleteHashTable(ioPtr->constructed); ckfree((char*)ioPtr->constructed); ioPtr->constructed = NULL; ItclAddObjectsDictInfo(interp, ioPtr); | | | 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 | infoPtr->currIoPtr = saveCurrIoPtr; } infoPtr->lastIoPtr = ioPtr; Tcl_DeleteHashTable(ioPtr->constructed); ckfree((char*)ioPtr->constructed); ioPtr->constructed = NULL; ItclAddObjectsDictInfo(interp, ioPtr); ItclReleaseObject(ioPtr); return result; errorReturn: /* * At this point, the object is not constructed as there was an error. * Destroy the "constructed" table in the object data, since * it is no longer needed. |
︙ | ︙ | |||
709 710 711 712 713 714 715 | } if (ioPtr->constructed != NULL) { Tcl_DeleteHashTable(ioPtr->constructed); ckfree((char*)ioPtr->constructed); ioPtr->constructed = NULL; } ItclDeleteObjectVariablesNamespace(interp, ioPtr); | | | | 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 | } if (ioPtr->constructed != NULL) { Tcl_DeleteHashTable(ioPtr->constructed); ckfree((char*)ioPtr->constructed); ioPtr->constructed = NULL; } ItclDeleteObjectVariablesNamespace(interp, ioPtr); ItclReleaseObject(ioPtr); ItclReleaseObject(ioPtr); return result; } /* * ------------------------------------------------------------------------ * ItclInitObjectCommands() * |
︙ | ︙ | |||
1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 | int Itcl_DeleteObject( Tcl_Interp *interp, /* interpreter mananging object */ ItclObject *contextIoPtr) /* object to be deleted */ { Tcl_CmdInfo cmdInfo; Tcl_HashEntry *hPtr; Tcl_GetCommandInfoFromToken(contextIoPtr->accessCmd, &cmdInfo); contextIoPtr->flags |= ITCL_OBJECT_IS_DELETED; | > | | | 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 | int Itcl_DeleteObject( Tcl_Interp *interp, /* interpreter mananging object */ ItclObject *contextIoPtr) /* object to be deleted */ { Tcl_CmdInfo cmdInfo; Tcl_HashEntry *hPtr; Tcl_GetCommandInfoFromToken(contextIoPtr->accessCmd, &cmdInfo); contextIoPtr->flags |= ITCL_OBJECT_IS_DELETED; ItclPreserveObject(contextIoPtr); /* * Invoke the object's destructors. */ if (Itcl_DestructObject(interp, contextIoPtr, 0) != TCL_OK) { ItclReleaseObject(contextIoPtr); contextIoPtr->flags |= ITCL_TCLOO_OBJECT_IS_DELETED|ITCL_OBJECT_DESTRUCT_ERROR; return TCL_ERROR; } /* * Remove the object from the global list. */ |
︙ | ︙ | |||
1328 1329 1330 1331 1332 1333 1334 | * safely deleted without attempting to destruct the object * again. Then delete the access command. If this is * the last use of the object data, the object will die here. */ if ((contextIoPtr->accessCmd != NULL) && (!(contextIoPtr->flags & (ITCL_OBJECT_IS_RENAMED)))) { if (Tcl_GetCommandInfoFromToken(contextIoPtr->accessCmd, &cmdInfo) == 1) { | | | | 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 | * safely deleted without attempting to destruct the object * again. Then delete the access command. If this is * the last use of the object data, the object will die here. */ if ((contextIoPtr->accessCmd != NULL) && (!(contextIoPtr->flags & (ITCL_OBJECT_IS_RENAMED)))) { if (Tcl_GetCommandInfoFromToken(contextIoPtr->accessCmd, &cmdInfo) == 1) { cmdInfo.deleteProc = ItclReleaseObject; Tcl_SetCommandInfoFromToken(contextIoPtr->accessCmd, &cmdInfo); Tcl_DeleteCommandFromToken(interp, contextIoPtr->accessCmd); } } contextIoPtr->oPtr = NULL; contextIoPtr->accessCmd = NULL; ItclReleaseObject(contextIoPtr); return TCL_OK; } /* * ------------------------------------------------------------------------ * ItclDeleteObjectVariablesNamespace() |
︙ | ︙ | |||
2710 2711 2712 2713 2714 2715 2716 | (char*)contextIoPtr); if (hPtr) { Tcl_DeleteHashEntry(hPtr); } contextIoPtr->accessCmd = NULL; } | | | | 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 | (char*)contextIoPtr); if (hPtr) { Tcl_DeleteHashEntry(hPtr); } contextIoPtr->accessCmd = NULL; } ItclReleaseObject(contextIoPtr); } /* * ------------------------------------------------------------------------ * ItclFreeObject() * * Deletes all instance variables and frees all memory associated with * the given object instance. This is usually invoked automatically * by ItclReleaseObject(), when an object's data is no longer being used. * ------------------------------------------------------------------------ */ static void ItclFreeObject( char * cdata) /* object instance data */ { FOREACH_HASH_DECLS; |
︙ | ︙ |