diff options
author | davygrvy <davygrvy> | 2003-12-21 23:50:13 (GMT) |
---|---|---|
committer | davygrvy <davygrvy> | 2003-12-21 23:50:13 (GMT) |
commit | bd23cfcf8912fb898bef69b10cd34e3673d0af83 (patch) | |
tree | 0dd59c8ef95660d1afe7967786a7a4fd4f6bdedd /generic/tkEvent.c | |
parent | 747881c8033dd9bcecd061f4c5d75f5bdc6097c5 (diff) | |
download | tk-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/tkEvent.c')
-rw-r--r-- | generic/tkEvent.c | 148 |
1 files changed, 147 insertions, 1 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 -- |