From 08b861f017795ecc7d98f42a55b4d7f2a2c4b9ca Mon Sep 17 00:00:00 2001 From: ferrieux Date: Mon, 27 Apr 2009 21:45:20 +0000 Subject: Backport fix for [Bug 1028264]: WSACleanup() too early. The fix introduces "late exit handlers" for similar late process-wide cleanups. --- ChangeLog | 6 ++++ generic/tclEvent.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++-- generic/tclInt.h | 6 +++- win/tclWinSock.c | 4 +-- 4 files changed, 115 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index e4ec9ee..71fd071 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2009-04-27 Alexandre Ferrieux + * generic/tclInt.h: Backport fix for [Bug 1028264]: WSACleanup() too early. + * generic/tclEvent.c: The fix introduces "late exit handlers" + * win/tclWinSock.c: for similar late process-wide cleanups. + +2009-04-27 Alexandre Ferrieux + * win/tclWinSock.c: Backport fix for [Bug 2446662]: resync Win behavior on RST with that of unix (EOF). diff --git a/generic/tclEvent.c b/generic/tclEvent.c index dc9705d..299922f 100644 --- a/generic/tclEvent.c +++ b/generic/tclEvent.c @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclEvent.c,v 1.80 2008/03/10 17:54:47 dgp Exp $ + * RCS: @(#) $Id: tclEvent.c,v 1.80.2.1 2009/04/27 21:45:20 ferrieux Exp $ */ #include "tclInt.h" @@ -51,7 +51,7 @@ typedef struct ErrAssocData { } ErrAssocData; /* - * For each exit handler created with a call to Tcl_CreateExitHandler there is + * For each exit handler created with a call to Tcl_Create(Late)ExitHandler there is * a structure of the following type: */ @@ -70,6 +70,9 @@ typedef struct ExitHandler { static ExitHandler *firstExitPtr = NULL; /* First in list of all exit handlers for * application. */ +static ExitHandler *firstLateExitPtr = NULL; + /* First in list of all late exit handlers for + * application. */ TCL_DECLARE_MUTEX(exitMutex) /* @@ -633,6 +636,39 @@ Tcl_CreateExitHandler( /* *---------------------------------------------------------------------- * + * TclCreateLateExitHandler -- + * + * Arrange for a given function to be invoked after all pre-thread cleanups + * + * Results: + * None. + * + * Side effects: + * Proc will be invoked with clientData as argument when the application + * exits. + * + *---------------------------------------------------------------------- + */ + +void +TclCreateLateExitHandler( + Tcl_ExitProc *proc, /* Function to invoke. */ + ClientData clientData) /* Arbitrary value to pass to proc. */ +{ + ExitHandler *exitPtr; + + exitPtr = (ExitHandler *) ckalloc(sizeof(ExitHandler)); + exitPtr->proc = proc; + exitPtr->clientData = clientData; + Tcl_MutexLock(&exitMutex); + exitPtr->nextPtr = firstLateExitPtr; + firstLateExitPtr = exitPtr; + Tcl_MutexUnlock(&exitMutex); +} + +/* + *---------------------------------------------------------------------- + * * Tcl_DeleteExitHandler -- * * This function cancels an existing exit handler matching proc and @@ -676,6 +712,49 @@ Tcl_DeleteExitHandler( /* *---------------------------------------------------------------------- * + * TclDeleteLateExitHandler -- + * + * This function cancels an existing late exit handler matching proc and + * clientData, if such a handler exits. + * + * Results: + * None. + * + * Side effects: + * If there is a late exit handler corresponding to proc and clientData then + * it is canceled; if no such handler exists then nothing happens. + * + *---------------------------------------------------------------------- + */ + +void +TclDeleteLateExitHandler( + Tcl_ExitProc *proc, /* Function that was previously registered. */ + ClientData clientData) /* Arbitrary value to pass to proc. */ +{ + ExitHandler *exitPtr, *prevPtr; + + Tcl_MutexLock(&exitMutex); + for (prevPtr = NULL, exitPtr = firstLateExitPtr; exitPtr != NULL; + prevPtr = exitPtr, exitPtr = exitPtr->nextPtr) { + if ((exitPtr->proc == proc) + && (exitPtr->clientData == clientData)) { + if (prevPtr == NULL) { + firstLateExitPtr = exitPtr->nextPtr; + } else { + prevPtr->nextPtr = exitPtr->nextPtr; + } + ckfree((char *) exitPtr); + break; + } + } + Tcl_MutexUnlock(&exitMutex); + return; +} + +/* + *---------------------------------------------------------------------- + * * Tcl_CreateThreadExitHandler -- * * Arrange for a given function to be invoked just before the current @@ -976,6 +1055,27 @@ Tcl_Finalize(void) Tcl_FinalizeThread(); /* + * Now invoke late (process-wide) exit handlers. + */ + + Tcl_MutexLock(&exitMutex); + for (exitPtr = firstLateExitPtr; exitPtr != NULL; exitPtr = firstLateExitPtr) { + /* + * Be careful to remove the handler from the list before invoking its + * callback. This protects us against double-freeing if the callback + * should call Tcl_DeleteLateExitHandler on itself. + */ + + firstLateExitPtr = exitPtr->nextPtr; + Tcl_MutexUnlock(&exitMutex); + exitPtr->proc(exitPtr->clientData); + ckfree((char *) exitPtr); + Tcl_MutexLock(&exitMutex); + } + firstLateExitPtr = NULL; + Tcl_MutexUnlock(&exitMutex); + + /* * Now finalize the Tcl execution environment. Note that this must be done * after the exit handlers, because there are order dependencies. */ diff --git a/generic/tclInt.h b/generic/tclInt.h index aef7a3f..5d7e6ab 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -13,7 +13,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclInt.h,v 1.362.2.5 2008/11/14 00:22:39 nijtmans Exp $ + * RCS: @(#) $Id: tclInt.h,v 1.362.2.6 2009/04/27 21:45:20 ferrieux Exp $ */ #ifndef _TCLINT @@ -2502,6 +2502,10 @@ MODULE_SCOPE int TclFileMakeDirsCmd(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int TclFileRenameCmd(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); +MODULE_SCOPE void TclCreateLateExitHandler (Tcl_ExitProc * proc, + ClientData clientData); +MODULE_SCOPE void TclDeleteLateExitHandler (Tcl_ExitProc * proc, + ClientData clientData); MODULE_SCOPE void TclFinalizeAllocSubsystem(void); MODULE_SCOPE void TclFinalizeAsync(void); MODULE_SCOPE void TclFinalizeDoubleConversion(void); diff --git a/win/tclWinSock.c b/win/tclWinSock.c index 8e2612e..b26d697 100644 --- a/win/tclWinSock.c +++ b/win/tclWinSock.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: tclWinSock.c,v 1.62.2.1 2009/04/27 21:36:34 ferrieux Exp $ + * RCS: @(#) $Id: tclWinSock.c,v 1.62.2.2 2009/04/27 21:45:20 ferrieux Exp $ */ #include "tclWinInt.h" @@ -231,7 +231,7 @@ InitSockets(void) if (!initialized) { initialized = 1; - Tcl_CreateExitHandler(SocketExitHandler, (ClientData) NULL); + TclCreateLateExitHandler(SocketExitHandler, (ClientData) NULL); /* * Create the async notification window with a new class. We must -- cgit v0.12