diff options
author | ferrieux <ferrieux@users.sourceforge.net> | 2009-04-27 21:45:20 (GMT) |
---|---|---|
committer | ferrieux <ferrieux@users.sourceforge.net> | 2009-04-27 21:45:20 (GMT) |
commit | 08b861f017795ecc7d98f42a55b4d7f2a2c4b9ca (patch) | |
tree | a7d36c2c94c82691d7f22461bf81c46e2c66e2f6 /generic | |
parent | 18cc34b4b4357e640bce38edb0bb3442058cf563 (diff) | |
download | tcl-08b861f017795ecc7d98f42a55b4d7f2a2c4b9ca.zip tcl-08b861f017795ecc7d98f42a55b4d7f2a2c4b9ca.tar.gz tcl-08b861f017795ecc7d98f42a55b4d7f2a2c4b9ca.tar.bz2 |
Backport fix for [Bug 1028264]: WSACleanup() too early. The fix introduces "late exit handlers" for similar late process-wide cleanups.
Diffstat (limited to 'generic')
-rw-r--r-- | generic/tclEvent.c | 104 | ||||
-rw-r--r-- | generic/tclInt.h | 6 |
2 files changed, 107 insertions, 3 deletions
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); |