diff options
author | davygrvy <davygrvy> | 2004-10-27 00:37:37 (GMT) |
---|---|---|
committer | davygrvy <davygrvy> | 2004-10-27 00:37:37 (GMT) |
commit | e0d7c1fd68c5e02578fe3468dacf258c21095864 (patch) | |
tree | b983c1273c1a6326de84746006f8e4f502466cdb /generic | |
parent | 236a6a97da006e7f8190249e8fb9b25cfad30b0d (diff) | |
download | tk-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:
Diffstat (limited to 'generic')
-rw-r--r-- | generic/tkInt.h | 7 | ||||
-rw-r--r-- | generic/tkMenu.c | 6 | ||||
-rw-r--r-- | generic/tkUtil.c | 148 | ||||
-rw-r--r-- | generic/tkWindow.c | 9 |
4 files changed, 160 insertions, 10 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 |