From 038ad9c8c8c8a7c63a58858d7693942420d5babd Mon Sep 17 00:00:00 2001 From: ferrieux Date: Tue, 27 Jan 2009 00:01:42 +0000 Subject: Fix [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 77bcb0a..2c4ede0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2009-01-26 Alexandre Ferrieux + * generic/tclInt.h: Fix [Bug 1028264]: WSACleanup() too early. + * generic/tclEvent.c: The fix introduces "late exit handlers" + * win/tclWinSock.c: for similar late process-wide cleanups. + +2009-01-26 Alexandre Ferrieux + * win/tclWinSocl.c: Fix [Bug 2446662]: resync Win behavior on RST with that of unix (EOF). diff --git a/generic/tclEvent.c b/generic/tclEvent.c index cbb0aad..40e1fe6 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.86 2008/12/09 20:16:29 dgp Exp $ + * RCS: @(#) $Id: tclEvent.c,v 1.87 2009/01/27 00:01:45 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 @@ -977,6 +1056,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 b633e12..ae1d45a 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -15,7 +15,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.414 2009/01/22 06:42:33 nijtmans Exp $ + * RCS: @(#) $Id: tclInt.h,v 1.415 2009/01/27 00:01:49 ferrieux Exp $ */ #ifndef _TCLINT @@ -2640,6 +2640,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 d99ee2d..b03bf48 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.65 2009/01/26 22:57:57 ferrieux Exp $ + * RCS: @(#) $Id: tclWinSock.c,v 1.66 2009/01/27 00:02:08 ferrieux Exp $ */ #include "tclWinInt.h" @@ -232,7 +232,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