summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
authordavygrvy <davygrvy>2003-12-21 23:50:13 (GMT)
committerdavygrvy <davygrvy>2003-12-21 23:50:13 (GMT)
commitbd23cfcf8912fb898bef69b10cd34e3673d0af83 (patch)
tree0dd59c8ef95660d1afe7967786a7a4fd4f6bdedd /generic
parent747881c8033dd9bcecd061f4c5d75f5bdc6097c5 (diff)
downloadtk-bd23cfcf8912fb898bef69b10cd34e3673d0af83.zip
tk-bd23cfcf8912fb898bef69b10cd34e3673d0af83.tar.gz
tk-bd23cfcf8912fb898bef69b10cd34e3673d0af83.tar.bz2
* generic/tkEvent.c: Added three new functions: TkCreateExitHandler,
* generic/tkInt.h: TkDeleteExitHandler, and TkFinalize. This adds * generic/tkMenu.c: an insertion point so Tk's exit handlers can be * generic/tkWindow.c: called on their own from tk85.dll's DllMain * mac/tkMacButton.c: for DLL_PROCESS_DETACH. These are private to * unix/tkUnixEvent.c: the binary and not exported. It is possible * win/tkWin32Dll.c: the Windows OS can unload Tk _prior_ to Tcl * win/tkWinEmbed.c: under some conditions such as ExitProcess(). * win/tkWinMenu.c: This avoids a dangling pointer problem when Tcl * win/tkWinX.c: does Tcl_Finalize after Tk has been unloaded. * win/winMain.c: DllMain's DLL_PROCESS_DETACH now protected with SEH as DeleteWindowsExitProc is causing an exception of its own under some teardown conditions. AT&T assembly syntax has not been added for MinGW yet. [Tcl Patch 858493]
Diffstat (limited to 'generic')
-rw-r--r--generic/tkEvent.c148
-rw-r--r--generic/tkInt.h7
-rw-r--r--generic/tkMenu.c4
-rw-r--r--generic/tkWindow.c9
4 files changed, 159 insertions, 9 deletions
diff --git a/generic/tkEvent.c b/generic/tkEvent.c
index f95bf9e..f6bf9d4 100644
--- a/generic/tkEvent.c
+++ b/generic/tkEvent.c
@@ -11,7 +11,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tkEvent.c,v 1.18 2003/07/19 01:01:36 hobbs Exp $
+ * RCS: @(#) $Id: tkEvent.c,v 1.19 2003/12/21 23:50:13 davygrvy Exp $
*/
#include "tkPort.h"
@@ -154,6 +154,29 @@ typedef struct ThreadSpecificData {
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.
*/
@@ -1458,6 +1481,129 @@ DelayedMotionProc(clientData)
}
/*
+ *---------------------------------------------------------------------------
+ *
+ * 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);
+}
+
+/*
*--------------------------------------------------------------
*
* Tk_MainLoop --
diff --git a/generic/tkInt.h b/generic/tkInt.h
index a90f2d6..635229a 100644
--- a/generic/tkInt.h
+++ b/generic/tkInt.h
@@ -11,7 +11,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: $Id: tkInt.h,v 1.60 2003/10/13 03:41:37 hobbs Exp $
+ * RCS: $Id: tkInt.h,v 1.61 2003/12/21 23:50:13 davygrvy Exp $
*/
#ifndef _TKINT
@@ -1167,6 +1167,11 @@ EXTERN char * TkTilePrintProc _ANSI_ARGS_((
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.
diff --git a/generic/tkMenu.c b/generic/tkMenu.c
index 9590b59..868268a 100644
--- a/generic/tkMenu.c
+++ b/generic/tkMenu.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: tkMenu.c,v 1.23 2003/12/03 16:38:23 dkf Exp $
+ * RCS: @(#) $Id: tkMenu.c,v 1.24 2003/12/21 23:50:13 davygrvy Exp $
*/
/*
@@ -3594,7 +3594,7 @@ TkMenuInit()
/*
* Make sure we cleanup on finalize.
*/
- Tcl_CreateExitHandler((Tcl_ExitProc *) TkMenuCleanup, NULL);
+ TkCreateExitHandler((Tcl_ExitProc *) TkMenuCleanup, NULL);
Tcl_MutexUnlock(&menuMutex);
}
if (!tsdPtr->menusInitialized) {
diff --git a/generic/tkWindow.c b/generic/tkWindow.c
index fde6736..d14f125 100644
--- a/generic/tkWindow.c
+++ b/generic/tkWindow.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: tkWindow.c,v 1.60 2003/07/18 13:24:19 vincentdarley Exp $
+ * RCS: @(#) $Id: tkWindow.c,v 1.61 2003/12/21 23:50:13 davygrvy Exp $
*/
#include "tkPort.h"
@@ -360,7 +360,7 @@ CreateTopLevelWindow(interp, parent, name, screenName, flags)
* exits.
*/
- Tcl_CreateExitHandler(DeleteWindowsExitProc, (ClientData) NULL);
+ TkCreateExitHandler(DeleteWindowsExitProc, (ClientData) tsdPtr);
}
if ((parent != NULL) && (screenName != NULL) && (screenName[0] == '\0')) {
@@ -2705,12 +2705,11 @@ Tk_GetNumMainWindows()
static void
DeleteWindowsExitProc(clientData)
- ClientData clientData; /* Not used. */
+ ClientData clientData; /* tsdPtr when handler was created. */
{
TkDisplay *dispPtr, *nextPtr;
Tcl_Interp *interp;
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
- Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
/*
* Finish destroying any windows that are in a