From 95660b09be94d6eb4b0482d33c78d8880e0c14cb Mon Sep 17 00:00:00 2001 From: dkf Date: Mon, 1 Sep 2008 00:35:40 +0000 Subject: Improve the semantics of C-implemented destructors slightly. --- ChangeLog | 8 ++++++++ generic/tclOO.c | 49 +++++++++++++++++++++++++++++++------------------ generic/tclOOMethod.c | 12 +++++++++++- 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/ChangeLog b/ChangeLog index c9225ea..8f5fab5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2008-09-01 Donal K. Fellows + + * generic/tclOOMethod.c (InvokeProcedureMethod): + * generic/tclOO.c (ObjectRenamedTrace): Arrange for only methods that + involve callbacks into the Tcl interpreter to be skipped when the + interpreter is being torn down. Allows the semantics of destructors in + a dying interpreter to be more useful when they're implemented in C. + 2008-08-29 Donal K. Fellows * unix/Makefile.in: Ensure that all TclOO headers get installed. diff --git a/generic/tclOO.c b/generic/tclOO.c index 95926f2..b25f070 100644 --- a/generic/tclOO.c +++ b/generic/tclOO.c @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclOO.c,v 1.15 2008/08/20 15:41:26 dkf Exp $ + * RCS: @(#) $Id: tclOO.c,v 1.16 2008/09/01 00:35:42 dkf Exp $ */ #ifdef HAVE_CONFIG_H @@ -548,6 +548,7 @@ ObjectRenamedTrace( { Object *oPtr = clientData; Class *clsPtr; + CallContext *contextPtr; /* * If this is a rename and not a delete of the object, we just flush the @@ -570,24 +571,22 @@ ObjectRenamedTrace( AddRef(oPtr); oPtr->flags |= OBJECT_DELETED; - if (!Tcl_InterpDeleted(interp)) { - CallContext *contextPtr = TclOOGetCallContext(oPtr, NULL, DESTRUCTOR); - if (contextPtr != NULL) { - int result; - Tcl_InterpState state; + contextPtr = TclOOGetCallContext(oPtr, NULL, DESTRUCTOR); + if (contextPtr != NULL) { + int result; + Tcl_InterpState state; - contextPtr->callPtr->flags |= DESTRUCTOR; - contextPtr->skip = 0; - state = Tcl_SaveInterpState(interp, TCL_OK); - result = Tcl_NRCallObjProc(interp, TclOOInvokeContext, contextPtr, - 0, NULL); - if (result != TCL_OK) { - Tcl_BackgroundError(interp); - } - Tcl_RestoreInterpState(interp, state); - TclOODeleteContext(contextPtr); + contextPtr->callPtr->flags |= DESTRUCTOR; + contextPtr->skip = 0; + state = Tcl_SaveInterpState(interp, TCL_OK); + result = Tcl_NRCallObjProc(interp, TclOOInvokeContext, contextPtr, 0, + NULL); + if (result != TCL_OK) { + Tcl_BackgroundError(interp); } + Tcl_RestoreInterpState(interp, state); + TclOODeleteContext(contextPtr); } /* @@ -2134,11 +2133,18 @@ Tcl_ObjectContextInvokeNext( if (contextPtr->index+1 >= contextPtr->callPtr->numChain) { /* - * We're at the end of the chain; generate an error message. + * We're at the end of the chain; generate an error message unless the + * interpreter is being torn down, in which case we might be getting + * here because of methods/destructors doing a [next] (or equivalent) + * unexpectedly. */ const char *methodType; + if (Tcl_InterpDeleted(interp)) { + return TCL_OK; + } + if (contextPtr->callPtr->flags & CONSTRUCTOR) { methodType = "constructor"; } else if (contextPtr->callPtr->flags & DESTRUCTOR) { @@ -2195,11 +2201,18 @@ TclNRObjectContextInvokeNext( if (contextPtr->index+1 >= contextPtr->callPtr->numChain) { /* - * We're at the end of the chain; generate an error message. + * We're at the end of the chain; generate an error message unless the + * interpreter is being torn down, in which case we might be getting + * here because of methods/destructors doing a [next] (or equivalent) + * unexpectedly. */ const char *methodType; + if (Tcl_InterpDeleted(interp)) { + return TCL_OK; + } + if (contextPtr->callPtr->flags & CONSTRUCTOR) { methodType = "constructor"; } else if (contextPtr->callPtr->flags & DESTRUCTOR) { diff --git a/generic/tclOOMethod.c b/generic/tclOOMethod.c index 75aef73..5371719 100644 --- a/generic/tclOOMethod.c +++ b/generic/tclOOMethod.c @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclOOMethod.c,v 1.17 2008/08/23 18:53:12 msofer Exp $ + * RCS: @(#) $Id: tclOOMethod.c,v 1.18 2008/09/01 00:35:42 dkf Exp $ */ #ifdef HAVE_CONFIG_H @@ -643,6 +643,16 @@ InvokeProcedureMethod( * call frame's lifetime). */ /* + * If the interpreter was deleted, we just skip to the next thing in the + * chain. + */ + + if (Tcl_InterpDeleted(interp)) { + return TclNRObjectContextInvokeNext(interp, context, objc, objv, + Tcl_ObjectContextSkippedArgs(context)); + } + + /* * Allocate the special frame data. */ -- cgit v0.12