Attachment "patch.txt" to
ticket [858493ffff]
added by
davygrvy
2003-12-22 06:11:04.
*** generic/tkEvent.c 19 Jul 2003 01:01:36 -0000 1.18
--- generic/tkEvent.c 21 Dec 2003 22:57:12 -0000
***************
*** 154,159 ****
--- 154,182 ----
static Tcl_ThreadDataKey dataKey;
/*
+ * For each exit handler created with a call to TkCreateExitHandler
+ * there is a structure of the following type:
+ */
+
+ typedef struct ExitHandler {
+ Tcl_ExitProc *proc; /* Procedure to call when process exits. */
+ ClientData clientData; /* One word of information to pass to proc. */
+ struct ExitHandler *nextPtr;/* Next in list of all exit handlers for
+ * this application, or NULL for end of list. */
+ } ExitHandler;
+
+ /*
+ * There is both per-process and per-thread exit handlers.
+ * The first list is controlled by a mutex. The other is in
+ * thread local storage.
+ */
+
+ static ExitHandler *firstExitPtr = NULL;
+ /* First in list of all exit handlers for
+ * application. */
+ TCL_DECLARE_MUTEX(exitMutex)
+
+ /*
* Prototypes for procedures that are only referenced locally within
* this file.
*/
***************
*** 1455,1460 ****
--- 1478,1606 ----
}
Tcl_QueueEvent(&dispPtr->delayedMotionPtr->header, TCL_QUEUE_TAIL);
dispPtr->delayedMotionPtr = NULL;
+ }
+
+ /*
+ *---------------------------------------------------------------------------
+ *
+ * TkCreateExitHandler --
+ *
+ * Same as Tcl_CreateExitHandler, but private to Tk.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects.
+ * Sets a handler with Tcl_CreateExitHandler if this is the first call.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+ void
+ TkCreateExitHandler (proc, clientData)
+ Tcl_ExitProc *proc; /* Procedure 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);
+ if (firstExitPtr == NULL) {
+ Tcl_CreateExitHandler(TkFinalize, NULL);
+ }
+ exitPtr->nextPtr = firstExitPtr;
+ firstExitPtr = exitPtr;
+ Tcl_MutexUnlock(&exitMutex);
+ }
+
+ /*
+ *---------------------------------------------------------------------------
+ *
+ * TkDeleteExitHandler --
+ *
+ * Same as Tcl_DeleteExitHandler, but private to Tk.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects.
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+ void
+ TkDeleteExitHandler (proc, clientData)
+ Tcl_ExitProc *proc; /* Procedure that was previously registered. */
+ ClientData clientData; /* Arbitrary value to pass to proc. */
+ {
+ ExitHandler *exitPtr, *prevPtr;
+
+ Tcl_MutexLock(&exitMutex);
+ for (prevPtr = NULL, exitPtr = firstExitPtr; exitPtr != NULL;
+ prevPtr = exitPtr, exitPtr = exitPtr->nextPtr) {
+ if ((exitPtr->proc == proc)
+ && (exitPtr->clientData == clientData)) {
+ if (prevPtr == NULL) {
+ firstExitPtr = exitPtr->nextPtr;
+ } else {
+ prevPtr->nextPtr = exitPtr->nextPtr;
+ }
+ ckfree((char *) exitPtr);
+ break;
+ }
+ }
+ Tcl_MutexUnlock(&exitMutex);
+ return;
+ }
+
+ /*
+ *---------------------------------------------------------------------------
+ *
+ * TkFinalize --
+ *
+ * Runs our private exit handlers and removes itself from Tcl. This is
+ * benificial should we want to protect from dangling pointers should
+ * the Tk shared library be unloaded prior to Tcl which can happen on
+ * windows should the process be forcefully exiting from an exception
+ * handler.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects.
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+ void
+ TkFinalize (clientData)
+ ClientData clientData; /* Arbitrary value to pass to proc. */
+ {
+ ExitHandler *exitPtr;
+
+ Tcl_DeleteExitHandler(TkFinalize, NULL);
+
+ Tcl_MutexLock(&exitMutex);
+ for (exitPtr = firstExitPtr; exitPtr != NULL; exitPtr = firstExitPtr) {
+ /*
+ * Be careful to remove the handler from the list before
+ * invoking its callback. This protects us against
+ * double-freeing if the callback should call
+ * TkDeleteExitHandler on itself.
+ */
+
+ firstExitPtr = exitPtr->nextPtr;
+ Tcl_MutexUnlock(&exitMutex);
+ (*exitPtr->proc)(exitPtr->clientData);
+ ckfree((char *) exitPtr);
+ Tcl_MutexLock(&exitMutex);
+ }
+ firstExitPtr = NULL;
+ Tcl_MutexUnlock(&exitMutex);
}
/*
*** generic/tkInt.h 13 Oct 2003 03:41:37 -0000 1.60
--- generic/tkInt.h 21 Dec 2003 22:57:15 -0000
***************
*** 1167,1172 ****
--- 1167,1177 ----
Tcl_FreeProc **freeProcPtr));
EXTERN XEvent * TkpGetBindingXEvent _ANSI_ARGS_((
Tcl_Interp *interp));
+ EXTERN void TkCreateExitHandler _ANSI_ARGS_((Tcl_ExitProc *proc,
+ ClientData clientData));
+ EXTERN void TkDeleteExitHandler _ANSI_ARGS_((Tcl_ExitProc *proc,
+ ClientData clientData));
+ EXTERN Tcl_ExitProc TkFinalize;
/*
* Unsupported commands.
*** generic/tkMenu.c 3 Dec 2003 16:38:23 -0000 1.23
--- generic/tkMenu.c 21 Dec 2003 22:57:19 -0000
***************
*** 3594,3600 ****
/*
* Make sure we cleanup on finalize.
*/
! Tcl_CreateExitHandler((Tcl_ExitProc *) TkMenuCleanup, NULL);
Tcl_MutexUnlock(&menuMutex);
}
if (!tsdPtr->menusInitialized) {
--- 3594,3600 ----
/*
* Make sure we cleanup on finalize.
*/
! TkCreateExitHandler((Tcl_ExitProc *) TkMenuCleanup, NULL);
Tcl_MutexUnlock(&menuMutex);
}
if (!tsdPtr->menusInitialized) {
*** generic/tkWindow.c 18 Jul 2003 13:24:19 -0000 1.60
--- generic/tkWindow.c 21 Dec 2003 22:57:22 -0000
***************
*** 360,366 ****
* exits.
*/
! Tcl_CreateExitHandler(DeleteWindowsExitProc, (ClientData) NULL);
}
if ((parent != NULL) && (screenName != NULL) && (screenName[0] == '\0')) {
--- 360,366 ----
* exits.
*/
! TkCreateExitHandler(DeleteWindowsExitProc, (ClientData) tsdPtr);
}
if ((parent != NULL) && (screenName != NULL) && (screenName[0] == '\0')) {
***************
*** 2705,2716 ****
static void
DeleteWindowsExitProc(clientData)
! ClientData clientData; /* Not used. */
{
TkDisplay *dispPtr, *nextPtr;
Tcl_Interp *interp;
! ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
! Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
/*
* Finish destroying any windows that are in a
--- 2705,2715 ----
static void
DeleteWindowsExitProc(clientData)
! ClientData clientData; /* tsdPtr when handler was created. */
{
TkDisplay *dispPtr, *nextPtr;
Tcl_Interp *interp;
! ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
/*
* Finish destroying any windows that are in a
*** mac/tkMacButton.c 10 Oct 2003 20:19:51 -0000 1.19
--- mac/tkMacButton.c 21 Dec 2003 22:57:25 -0000
***************
*** 1272,1278 ****
* code it includes will crash the Mac on exit from Tk.
oldPixPtr = ((CWindowPeek) windowRef)->port.portPixMap;
! Tcl_CreateExitHandler(ButtonExitProc, (ClientData) NULL);
*/
}
--- 1272,1278 ----
* code it includes will crash the Mac on exit from Tk.
oldPixPtr = ((CWindowPeek) windowRef)->port.portPixMap;
! TkCreateExitHandler(ButtonExitProc, (ClientData) NULL);
*/
}
*** unix/tkUnixEvent.c 2 Jul 2003 09:22:45 -0000 1.12
--- unix/tkUnixEvent.c 21 Dec 2003 22:57:28 -0000
***************
*** 81,87 ****
if (!tsdPtr->initialized) {
tsdPtr->initialized = 1;
Tcl_CreateEventSource(DisplaySetupProc, DisplayCheckProc, NULL);
! Tcl_CreateExitHandler(DisplayExitHandler, NULL);
}
}
--- 81,87 ----
if (!tsdPtr->initialized) {
tsdPtr->initialized = 1;
Tcl_CreateEventSource(DisplaySetupProc, DisplayCheckProc, NULL);
! TkCreateExitHandler(DisplayExitHandler, NULL);
}
}
*** win/tkWin32Dll.c 8 Dec 2002 00:46:51 -0000 1.6
--- win/tkWin32Dll.c 21 Dec 2003 22:57:29 -0000
***************
*** 12,17 ****
--- 12,18 ----
*/
#include "tkWinInt.h"
+ #ifndef STATIC_BUILD
/*
* The following declaration is for the VC++ DLL entry point.
***************
*** 61,67 ****
* Always TRUE.
*
* Side effects:
! * None.
*
*----------------------------------------------------------------------
*/
--- 62,70 ----
* Always TRUE.
*
* Side effects:
! * This might call some sycronization functions, but MSDN
! * documentation states: "Waiting on synchronization objects in
! * DllMain can cause a deadlock."
*
*----------------------------------------------------------------------
*/
***************
*** 77,84 ****
* the hInstance to use.
*/
! if (reason == DLL_PROCESS_ATTACH) {
TkWinSetHINSTANCE(hInstance);
}
! return (TRUE);
}
--- 80,113 ----
* the hInstance to use.
*/
! switch (reason) {
! case DLL_PROCESS_ATTACH:
! DisableThreadLibraryCalls(hInstance);
TkWinSetHINSTANCE(hInstance);
+ break;
+
+ case DLL_PROCESS_DETACH:
+ /*
+ * Protect the call to TkFinalize in an SEH block. We can't
+ * be guarenteed Tk is always being unloaded from a stable
+ * condition.
+ */
+
+ __try {
+ /*
+ * Run and remove our exit handlers, if they haven't already
+ * been run. Just in case we are being unloaded prior to
+ * Tcl (it can happen), we won't leave any dangling pointers
+ * hanging around for when Tcl gets unloaded later.
+ */
+
+ TkFinalize(NULL);
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ /* empty handler body */
+ }
+ break;
}
! return TRUE;
}
+ #endif /* !STATIC_BUILD */
+
*** win/tkWinEmbed.c 13 Dec 2003 01:07:35 -0000 1.8
--- win/tkWinEmbed.c 21 Dec 2003 22:57:31 -0000
***************
*** 208,214 ****
*/
if (tsdPtr->firstContainerPtr == (Container *) NULL) {
! Tcl_CreateExitHandler(CleanupContainerList, (ClientData) NULL);
}
/*
--- 208,214 ----
*/
if (tsdPtr->firstContainerPtr == (Container *) NULL) {
! TkCreateExitHandler(CleanupContainerList, (ClientData) NULL);
}
/*
***************
*** 284,290 ****
*/
if (tsdPtr->firstContainerPtr == (Container *) NULL) {
! Tcl_CreateExitHandler(CleanupContainerList, (ClientData) NULL);
}
/*
--- 284,290 ----
*/
if (tsdPtr->firstContainerPtr == (Container *) NULL) {
! TkCreateExitHandler(CleanupContainerList, (ClientData) NULL);
}
/*
*** win/tkWinMenu.c 16 Dec 2003 03:12:51 -0000 1.25
--- win/tkWinMenu.c 21 Dec 2003 22:57:35 -0000
***************
*** 2990,2996 ****
tsdPtr->menuHWND = CreateWindow(MENU_CLASS_NAME, "MenuWindow", WS_POPUP,
0, 0, 10, 10, NULL, NULL, Tk_GetHINSTANCE(), NULL);
! Tcl_CreateExitHandler(MenuExitHandler, (ClientData) NULL);
SetDefaults(1);
}
--- 2990,2996 ----
tsdPtr->menuHWND = CreateWindow(MENU_CLASS_NAME, "MenuWindow", WS_POPUP,
0, 0, 10, 10, NULL, NULL, Tk_GetHINSTANCE(), NULL);
! TkCreateExitHandler(MenuExitHandler, (ClientData) NULL);
SetDefaults(1);
}
*** win/tkWinX.c 13 Dec 2003 01:50:29 -0000 1.26
--- win/tkWinX.c 21 Dec 2003 22:57:37 -0000
***************
*** 277,283 ****
/*
* Make sure we cleanup on finalize.
*/
! Tcl_CreateExitHandler((Tcl_ExitProc *) TkWinXCleanup,
(ClientData) hInstance);
}
--- 277,283 ----
/*
* Make sure we cleanup on finalize.
*/
! TkCreateExitHandler((Tcl_ExitProc *) TkWinXCleanup,
(ClientData) hInstance);
}
*** win/winMain.c 12 Dec 2003 00:45:33 -0000 1.18
--- win/winMain.c 21 Dec 2003 22:57:39 -0000
***************
*** 174,180 ****
* This exit handler will be used to free the
* resources allocated in this file.
*/
! Tcl_CreateExitHandler(AppInitExitHandler, NULL);
/*
* Initialize the console only if we are running as an interactive
--- 174,180 ----
* This exit handler will be used to free the
* resources allocated in this file.
*/
! TkCreateExitHandler(AppInitExitHandler, NULL);
/*
* Initialize the console only if we are running as an interactive