Index: ChangeLog ================================================================== --- ChangeLog +++ ChangeLog @@ -1,5 +1,18 @@ +2011-11-20 Joe Mistachkin + + * generic/threadCmd.c: Correct check for current thread in the + ThreadReserve function [Bug 3411244]. Correct the order for releasing + the interpreter and freeing memory, see check-in [6067508840]. + +2011-11-17 Joe Mistachkin + + * generic/threadCmd.c: Refactor ThreadEventProc to make sure all paths + out of the function call Tcl_Release on the necessary Tcl interpreters. + Also, call ThreadErrorProc consistently whenever the return code is not + TCL_OK (i.e. do not check for it to be equal to TCL_ERROR). + 2011-11-17 Joe Mistachkin * generic/threadCmd.c: The [thread::wait] command should use the TCL_CANCEL_UNWIND flag when calling Tcl_Canceled because it manages its own event processing loop. Also, if the event processing loop is Index: generic/threadCmd.c ================================================================== --- generic/threadCmd.c +++ generic/threadCmd.c @@ -2963,11 +2963,11 @@ * We're last attached user, so tear down the *target* thread */ tsdPtr->flags |= THREAD_FLAGS_STOPPED; - if (thrId /* Not current! */) { + if (thrId && thrId != Tcl_GetCurrentThread() /* Not current! */) { ThreadEventResult *resultPtr = NULL; /* * Remove from the list of active threads, so nobody can post * work to this thread, since it is just about to terminate. @@ -3066,14 +3066,16 @@ */ interp = (sendPtr && sendPtr->interp) ? sendPtr->interp : tsdPtr->interp; if (interp != NULL) { + Tcl_Preserve((ClientData)interp); + if (clbkPtr && clbkPtr->threadId == thrId) { + Tcl_Release((ClientData)interp); /* Watch: this thread evaluates it's own callback. */ interp = clbkPtr->interp; - } else { Tcl_Preserve((ClientData)interp); } Tcl_ResetResult(interp); @@ -3105,32 +3107,61 @@ Tcl_MutexLock(&threadMutex); ThreadSetResult(interp, code, resultPtr); Tcl_ConditionNotify(&resultPtr->done); Tcl_MutexUnlock(&threadMutex); + /* + * We still need to release the reference to the Tcl + * interpreter added by ThreadSend whenever the callback + * data is not NULL. + */ + + if (clbkPtr) { + Tcl_Release((ClientData)clbkPtr->interp); + } } else if (clbkPtr && clbkPtr->threadId != thrId) { ThreadSendData *tmpPtr = (ThreadSendData*)clbkPtr; /* * Route the callback back to it's originator. * Do not wait for the result. */ - if (code == TCL_ERROR) { + if (code != TCL_OK) { ThreadErrorProc(interp); } ThreadSetResult(interp, code, &clbkPtr->result); ThreadSend(interp, clbkPtr->threadId, tmpPtr, NULL, 0); - } else if (code == TCL_ERROR) { + } else if (code != TCL_OK) { /* * Only pass errors onto the registered error handler * when we don't have a result target for this event. */ ThreadErrorProc(interp); + + /* + * We still need to release the reference to the Tcl + * interpreter added by ThreadSend whenever the callback + * data is not NULL. + */ + + if (clbkPtr) { + Tcl_Release((ClientData)clbkPtr->interp); + } + } else { + /* + * We still need to release the reference to the Tcl + * interpreter added by ThreadSend whenever the callback + * data is not NULL. + */ + + if (clbkPtr) { + Tcl_Release((ClientData)clbkPtr->interp); + } } if (interp != NULL) { Tcl_Release((ClientData)interp); } @@ -3399,12 +3430,12 @@ ret = (*sendPtr->execProc)(sendPtr->interp, (ClientData)sendPtr); if (ret != TCL_OK) { ThreadErrorProc(sendPtr->interp); } - ThreadFreeProc(clientData); Tcl_Release((ClientData)sendPtr->interp); + ThreadFreeProc(clientData); } /* *---------------------------------------------------------------------- *