summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordavygrvy <davygrvy>2004-10-27 00:37:37 (GMT)
committerdavygrvy <davygrvy>2004-10-27 00:37:37 (GMT)
commite0d7c1fd68c5e02578fe3468dacf258c21095864 (patch)
treeb983c1273c1a6326de84746006f8e4f502466cdb
parent236a6a97da006e7f8190249e8fb9b25cfad30b0d (diff)
downloadtk-e0d7c1fd68c5e02578fe3468dacf258c21095864.zip
tk-e0d7c1fd68c5e02578fe3468dacf258c21095864.tar.gz
tk-e0d7c1fd68c5e02578fe3468dacf258c21095864.tar.bz2
* generic/tkInt.h: Backport of shutdown safety mods from the HEAD
* generic/tkMenu.c: dating from 2003-12-21 * generic/tkUtil.c: * generic/tkWindow.c: * mac/tkMacButton.c: * unix/tkUnixEvent.c: * win/tkWin32Dll.c: * win/tkWinEmbed.c: * win/tkWinMenu.c: * win/tkWinX.c:
-rw-r--r--generic/tkInt.h7
-rw-r--r--generic/tkMenu.c6
-rw-r--r--generic/tkUtil.c148
-rw-r--r--generic/tkWindow.c9
-rw-r--r--mac/tkMacButton.c4
-rw-r--r--unix/tkUnixEvent.c4
-rw-r--r--win/tkWin32Dll.c42
-rw-r--r--win/tkWinEmbed.c16
-rw-r--r--win/tkWinMenu.c4
-rw-r--r--win/tkWinX.c10
10 files changed, 215 insertions, 35 deletions
diff --git a/generic/tkInt.h b/generic/tkInt.h
index 72782ed..9fdf1fa 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.56.2.2 2004/10/05 22:27:26 hobbs Exp $
+ * RCS: $Id: tkInt.h,v 1.56.2.3 2004/10/27 00:37:37 davygrvy Exp $
*/
#ifndef _TKINT
@@ -1166,6 +1166,11 @@ EXTERN char * TkTilePrintProc _ANSI_ARGS_((
ClientData clientData, Tk_Window tkwin,
char *widgRec, int offset,
Tcl_FreeProc **freeProcPtr));
+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 a2f791a..ac6ae3e 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.20.2.3 2004/09/16 20:05:44 hobbs Exp $
+ * RCS: @(#) $Id: tkMenu.c,v 1.20.2.4 2004/10/27 00:37:38 davygrvy Exp $
*/
/*
@@ -370,7 +370,7 @@ static void MenuWorldChanged _ANSI_ARGS_((
static int PostProcessEntry _ANSI_ARGS_((TkMenuEntry *mePtr));
static void RecursivelyDeleteMenu _ANSI_ARGS_((TkMenu *menuPtr));
static void UnhookCascadeEntry _ANSI_ARGS_((TkMenuEntry *mePtr));
-static void TkMenuCleanup _ANSI_ARGS_((ClientData unused));
+static Tcl_ExitProc TkMenuCleanup;
/*
* The structure below is a list of procs that respond to certain window
@@ -3594,7 +3594,7 @@ TkMenuInit()
/*
* Make sure we cleanup on finalize.
*/
- Tcl_CreateExitHandler((Tcl_ExitProc *) TkMenuCleanup, NULL);
+ TkCreateExitHandler(TkMenuCleanup, NULL);
Tcl_MutexUnlock(&menuMutex);
}
if (!tsdPtr->menusInitialized) {
diff --git a/generic/tkUtil.c b/generic/tkUtil.c
index 415b0f6..f91d4e5 100644
--- a/generic/tkUtil.c
+++ b/generic/tkUtil.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: tkUtil.c,v 1.12 2002/08/05 04:30:40 dgp Exp $
+ * RCS: @(#) $Id: tkUtil.c,v 1.12.2.1 2004/10/27 00:37:38 davygrvy Exp $
*/
#include "tkInt.h"
@@ -951,3 +951,149 @@ TkFindStateNumObj(interp, optionPtr, mapPtr, keyPtr)
}
return mPtr->numKey;
}
+
+/*
+ * 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)
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * 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
+ * Tcl_DeleteExitHandler on itself.
+ */
+
+ firstExitPtr = exitPtr->nextPtr;
+ Tcl_MutexUnlock(&exitMutex);
+ (*exitPtr->proc)(exitPtr->clientData);
+ ckfree((char *) exitPtr);
+ Tcl_MutexLock(&exitMutex);
+ }
+ firstExitPtr = NULL;
+ Tcl_MutexUnlock(&exitMutex);
+}
diff --git a/generic/tkWindow.c b/generic/tkWindow.c
index 7a23210..53d4a8c 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.56.2.3 2004/03/26 22:01:26 dkf Exp $
+ * RCS: @(#) $Id: tkWindow.c,v 1.56.2.4 2004/10/27 00:37:38 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
diff --git a/mac/tkMacButton.c b/mac/tkMacButton.c
index 365fc26..e0f0d38 100644
--- a/mac/tkMacButton.c
+++ b/mac/tkMacButton.c
@@ -9,7 +9,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tkMacButton.c,v 1.17.2.2 2003/10/10 20:20:47 hobbs Exp $
+ * RCS: @(#) $Id: tkMacButton.c,v 1.17.2.3 2004/10/27 00:37:38 davygrvy Exp $
*/
#include "tkButton.h"
@@ -1272,7 +1272,7 @@ InitSampleControls()
* code it includes will crash the Mac on exit from Tk.
oldPixPtr = ((CWindowPeek) windowRef)->port.portPixMap;
- Tcl_CreateExitHandler(ButtonExitProc, (ClientData) NULL);
+ TkCreateExitHandler(ButtonExitProc, (ClientData) NULL);
*/
}
diff --git a/unix/tkUnixEvent.c b/unix/tkUnixEvent.c
index b1bf18b..34d9a69 100644
--- a/unix/tkUnixEvent.c
+++ b/unix/tkUnixEvent.c
@@ -9,7 +9,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tkUnixEvent.c,v 1.11.2.2 2004/05/03 22:23:09 hobbs Exp $
+ * RCS: @(#) $Id: tkUnixEvent.c,v 1.11.2.3 2004/10/27 00:37:38 davygrvy Exp $
*/
#include "tkInt.h"
@@ -81,7 +81,7 @@ TkCreateXEventSource()
if (!tsdPtr->initialized) {
tsdPtr->initialized = 1;
Tcl_CreateEventSource(DisplaySetupProc, DisplayCheckProc, NULL);
- Tcl_CreateExitHandler(DisplayExitHandler, NULL);
+ TkCreateExitHandler(DisplayExitHandler, NULL);
}
}
diff --git a/win/tkWin32Dll.c b/win/tkWin32Dll.c
index 4570a5a..fde647b 100644
--- a/win/tkWin32Dll.c
+++ b/win/tkWin32Dll.c
@@ -8,16 +8,17 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tkWin32Dll.c,v 1.6 2002/12/08 00:46:51 hobbs Exp $
+ * RCS: @(#) $Id: tkWin32Dll.c,v 1.6.2.1 2004/10/27 00:37:38 davygrvy Exp $
*/
#include "tkWinInt.h"
+#ifndef STATIC_BUILD
/*
* The following declaration is for the VC++ DLL entry point.
*/
-BOOL APIENTRY DllMain _ANSI_ARGS_((HINSTANCE hInst,
+BOOL WINAPI DllMain _ANSI_ARGS_((HINSTANCE hInst,
DWORD reason, LPVOID reserved));
/*
@@ -38,7 +39,7 @@ BOOL APIENTRY DllMain _ANSI_ARGS_((HINSTANCE hInst,
*----------------------------------------------------------------------
*/
-BOOL APIENTRY
+BOOL WINAPI
DllEntryPoint(hInst, reason, reserved)
HINSTANCE hInst; /* Library instance handle. */
DWORD reason; /* Reason this function is being called. */
@@ -61,12 +62,14 @@ DllEntryPoint(hInst, reason, reserved)
* Always TRUE.
*
* Side effects:
- * None.
+ * This might call some sycronization functions, but MSDN
+ * documentation states: "Waiting on synchronization objects in
+ * DllMain can cause a deadlock."
*
*----------------------------------------------------------------------
*/
-BOOL APIENTRY
+BOOL WINAPI
DllMain(hInstance, reason, reserved)
HINSTANCE hInstance;
DWORD reason;
@@ -77,8 +80,33 @@ DllMain(hInstance, reason, reserved)
* the hInstance to use.
*/
- if (reason == DLL_PROCESS_ATTACH) {
+ 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);
+ return TRUE;
}
+#endif /* !STATIC_BUILD */
diff --git a/win/tkWinEmbed.c b/win/tkWinEmbed.c
index 990ff29..a916050 100644
--- a/win/tkWinEmbed.c
+++ b/win/tkWinEmbed.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: tkWinEmbed.c,v 1.7 2002/08/05 04:30:41 dgp Exp $
+ * RCS: @(#) $Id: tkWinEmbed.c,v 1.7.2.1 2004/10/27 00:37:38 davygrvy Exp $
*/
#include "tkWinInt.h"
@@ -208,7 +208,7 @@ TkpUseWindow(interp, tkwin, string)
*/
if (tsdPtr->firstContainerPtr == (Container *) NULL) {
- Tcl_CreateExitHandler(CleanupContainerList, (ClientData) NULL);
+ TkCreateExitHandler(CleanupContainerList, (ClientData) NULL);
}
/*
@@ -284,7 +284,7 @@ TkpMakeContainer(tkwin)
*/
if (tsdPtr->firstContainerPtr == (Container *) NULL) {
- Tcl_CreateExitHandler(CleanupContainerList, (ClientData) NULL);
+ TkCreateExitHandler(CleanupContainerList, (ClientData) NULL);
}
/*
@@ -385,11 +385,13 @@ TkWinEmbeddedEventProc(hwnd, message, wParam, lParam)
*/
for (containerPtr = tsdPtr->firstContainerPtr;
- containerPtr->parentHWnd != hwnd;
+ containerPtr && containerPtr->parentHWnd != hwnd;
containerPtr = containerPtr->nextPtr) {
- if (containerPtr == NULL) {
- panic("TkWinContainerProc couldn't find Container record");
- }
+ /* empty loop body */
+ }
+
+ if (containerPtr == NULL) {
+ Tcl_Panic("TkWinContainerProc couldn't find Container record");
}
switch (message) {
diff --git a/win/tkWinMenu.c b/win/tkWinMenu.c
index 8dec5d8..b101ab6 100644
--- a/win/tkWinMenu.c
+++ b/win/tkWinMenu.c
@@ -9,7 +9,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tkWinMenu.c,v 1.21.2.3 2004/09/23 00:56:15 mdejong Exp $
+ * RCS: @(#) $Id: tkWinMenu.c,v 1.21.2.4 2004/10/27 00:37:38 davygrvy Exp $
*/
#define OEMRESOURCE
@@ -3014,7 +3014,7 @@ TkpMenuInit()
tsdPtr->menuHWND = CreateWindow(MENU_CLASS_NAME, "MenuWindow", WS_POPUP,
0, 0, 10, 10, NULL, NULL, Tk_GetHINSTANCE(), NULL);
- Tcl_CreateExitHandler(MenuExitHandler, (ClientData) NULL);
+ TkCreateExitHandler(MenuExitHandler, (ClientData) NULL);
SetDefaults(1);
}
diff --git a/win/tkWinX.c b/win/tkWinX.c
index da65e26..7ca4ad5 100644
--- a/win/tkWinX.c
+++ b/win/tkWinX.c
@@ -10,7 +10,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tkWinX.c,v 1.25.2.4 2004/09/23 01:49:08 hobbs Exp $
+ * RCS: @(#) $Id: tkWinX.c,v 1.25.2.5 2004/10/27 00:37:38 davygrvy Exp $
*/
#include "tkWinInt.h"
@@ -283,8 +283,7 @@ TkWinXInit(hInstance)
/*
* Make sure we cleanup on finalize.
*/
- Tcl_CreateExitHandler((Tcl_ExitProc *) TkWinXCleanup,
- (ClientData) hInstance);
+ TkCreateExitHandler(TkWinXCleanup, (ClientData) hInstance);
}
/*
@@ -304,9 +303,10 @@ TkWinXInit(hInstance)
*/
void
-TkWinXCleanup(hInstance)
- HINSTANCE hInstance;
+TkWinXCleanup(clientData)
+ ClientData clientData;
{
+ HINSTANCE hInstance = (HINSTANCE) clientData;
/*
* Clean up our own class.
*/