Index: generic/xotcl.c =================================================================== diff -u -r368556e8af08a76c1408488c1b45f19f2b5b8f82 -r450d297dd8504fea9755773c81511dfda0582c11 --- generic/xotcl.c (.../xotcl.c) (revision 368556e8af08a76c1408488c1b45f19f2b5b8f82) +++ generic/xotcl.c (.../xotcl.c) (revision 450d297dd8504fea9755773c81511dfda0582c11) @@ -12672,28 +12672,53 @@ } static void -freeAllXOTclObjectsAndClasses(Tcl_Interp *interp, Tcl_HashTable *commandTable) { - Tcl_HashEntry *hPtr; - Tcl_HashSearch hSrch; - XOTclObject *obj; +freeAllXOTclObjectsAndClasses(Tcl_Interp *interp, Tcl_HashTable *commandNameTable) { + Tcl_HashEntry *hPtr, *hPtr2; + Tcl_HashSearch hSrch, hSrch2; + XOTclObject *object; XOTclClass *thecls, *theobj, *cl; + int deleted = 0; /* fprintf(stderr,"??? freeAllXOTclObjectsAndClasses in %p\n", in); */ thecls = RUNTIME_STATE(interp)->theClass; theobj = RUNTIME_STATE(interp)->theObject; /***** PHYSICAL DESTROY *****/ RUNTIME_STATE(interp)->exitHandlerDestroyRound = XOTCL_EXITHANDLER_ON_PHYSICAL_DESTROY; + + /* + * First delete all child commands of all objects, which are not + * objects themselves. This will for example delete namespace + * imprted commands and objects and will resolve potential loops in + * the dependency graph. The result is a plain object/class tree. + */ + for (hPtr = Tcl_FirstHashEntry(commandNameTable, &hSrch); hPtr; hPtr = Tcl_NextHashEntry(&hSrch)) { + char *key = Tcl_GetHashKey(commandNameTable, hPtr); + object = XOTclpGetObject(interp, key); + + if (object && object->nsPtr) { + for (hPtr2 = Tcl_FirstHashEntry(Tcl_Namespace_cmdTable(object->nsPtr), &hSrch2); hPtr2; + hPtr2 = Tcl_NextHashEntry(&hSrch2)) { + Tcl_Command cmd = Tcl_GetHashValue(hPtr2); + if (cmd && Tcl_Command_objProc(cmd) != XOTclObjDispatch) { + Tcl_DeleteCommandFromToken(interp, cmd); + deleted ++; + } + } + } + } + /*fprintf(stderr, "deleted %d cmds\n", deleted);*/ + while (1) { - int deleted = 0; - for (hPtr = Tcl_FirstHashEntry(commandTable, &hSrch); hPtr; hPtr = Tcl_NextHashEntry(&hSrch)) { - char *key = Tcl_GetHashKey(commandTable, hPtr); - obj = XOTclpGetObject(interp, key); - if (obj && !XOTclObjectIsClass(obj) && !ObjectHasChildren(interp, obj)) { - /* fprintf(stderr," ... delete object %s %p, class=%s\n", key, obj, - ObjStr(obj->cl->object.cmdName));*/ - freeUnsetTraceVariable(interp, obj); - Tcl_DeleteCommandFromToken(interp, obj->id); + deleted = 0; + for (hPtr = Tcl_FirstHashEntry(commandNameTable, &hSrch); hPtr; hPtr = Tcl_NextHashEntry(&hSrch)) { + char *key = Tcl_GetHashKey(commandNameTable, hPtr); + object = XOTclpGetObject(interp, key); + if (object && !XOTclObjectIsClass(object) && !ObjectHasChildren(interp, object)) { + /* fprintf(stderr," ... delete object %s %p, class=%s\n", key, object, + ObjStr(object->cl->object.cmdName));*/ + freeUnsetTraceVariable(interp, object); + Tcl_DeleteCommandFromToken(interp, object->id); Tcl_DeleteHashEntry(hPtr); deleted++; } @@ -12703,8 +12728,8 @@ continue; } - for (hPtr = Tcl_FirstHashEntry(commandTable, &hSrch); hPtr; hPtr = Tcl_NextHashEntry(&hSrch)) { - char *key = Tcl_GetHashKey(commandTable, hPtr); + for (hPtr = Tcl_FirstHashEntry(commandNameTable, &hSrch); hPtr; hPtr = Tcl_NextHashEntry(&hSrch)) { + char *key = Tcl_GetHashKey(commandNameTable, hPtr); cl = XOTclpGetClass(interp, key); /* fprintf(stderr,"cl key = %s %p\n", key, cl); */ if (cl @@ -12759,7 +12784,7 @@ int result; Tcl_HashSearch hSrch; Tcl_HashEntry *hPtr; - Tcl_HashTable objTable, *commandTable = &objTable; + Tcl_HashTable objTable, *commandNameTable = &objTable; /* fprintf(stderr,"+++ call EXIT handler\n"); */ @@ -12787,14 +12812,14 @@ * user-defined destroys are called. */ - Tcl_InitHashTable(commandTable, TCL_STRING_KEYS); - MEM_COUNT_ALLOC("Tcl_InitHashTable", commandTable); - getAllInstances(interp, commandTable, RUNTIME_STATE(interp)->theObject); + Tcl_InitHashTable(commandNameTable, TCL_STRING_KEYS); + MEM_COUNT_ALLOC("Tcl_InitHashTable", commandNameTable); + getAllInstances(interp, commandNameTable, RUNTIME_STATE(interp)->theObject); /***** SOFT DESTROY *****/ RUNTIME_STATE(interp)->exitHandlerDestroyRound = XOTCL_EXITHANDLER_ON_SOFT_DESTROY; - for (hPtr = Tcl_FirstHashEntry(commandTable, &hSrch); hPtr; hPtr = Tcl_NextHashEntry(&hSrch)) { - char *key = Tcl_GetHashKey(commandTable, hPtr); + for (hPtr = Tcl_FirstHashEntry(commandNameTable, &hSrch); hPtr; hPtr = Tcl_NextHashEntry(&hSrch)) { + char *key = Tcl_GetHashKey(commandNameTable, hPtr); obj = XOTclpGetObject(interp, key); /* fprintf(stderr,"key = %s %p %d\n", key, obj, obj && !XOTclObjectIsClass(obj)); */ @@ -12804,20 +12829,20 @@ } } - for (hPtr = Tcl_FirstHashEntry(commandTable, &hSrch); hPtr; hPtr = Tcl_NextHashEntry(&hSrch)) { - char *key = Tcl_GetHashKey(commandTable, hPtr); + for (hPtr = Tcl_FirstHashEntry(commandNameTable, &hSrch); hPtr; hPtr = Tcl_NextHashEntry(&hSrch)) { + char *key = Tcl_GetHashKey(commandNameTable, hPtr); cl = XOTclpGetClass(interp, key); if (cl && !(cl->object.flags & XOTCL_DESTROY_CALLED)) { callDestroyMethod((ClientData)cl, interp, (XOTclObject *)cl, 0); } } #ifdef DO_CLEANUP - freeAllXOTclObjectsAndClasses(interp, commandTable); + freeAllXOTclObjectsAndClasses(interp, commandNameTable); #endif - MEM_COUNT_FREE("Tcl_InitHashTable", commandTable); - Tcl_DeleteHashTable(commandTable); + MEM_COUNT_FREE("Tcl_InitHashTable", commandNameTable); + Tcl_DeleteHashTable(commandNameTable); return TCL_OK; }