317 lines
8.4 KiB
C
317 lines
8.4 KiB
C
|
/*
|
|||
|
* tclMacExit.c --
|
|||
|
*
|
|||
|
* This file contains routines that deal with cleaning up various state
|
|||
|
* when Tcl/Tk applications quit. Unfortunantly, not all state is cleaned
|
|||
|
* up by the process when an application quites or crashes. Also you
|
|||
|
* need to do different things depending on wether you are running as
|
|||
|
* 68k code, PowerPC, or a code resource. The Exit handler code was
|
|||
|
* adapted from code posted on alt.sources.mac by Dave Nebinger.
|
|||
|
*
|
|||
|
* Copyright (c) 1995 Dave Nebinger.
|
|||
|
* Copyright (c) 1995-1996 Sun Microsystems, Inc.
|
|||
|
*
|
|||
|
* See the file "license.terms" for information on usage and redistribution
|
|||
|
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
|||
|
*
|
|||
|
* SCCS: @(#) tclMacExit.c 1.3 96/09/05 10:51:02
|
|||
|
*/
|
|||
|
|
|||
|
#include "tclInt.h"
|
|||
|
#include "tclMacInt.h"
|
|||
|
#include <SegLoad.h>
|
|||
|
#include <Traps.h>
|
|||
|
|
|||
|
/*
|
|||
|
* Various typedefs and defines needed to patch ExitToShell.
|
|||
|
*/
|
|||
|
|
|||
|
enum {
|
|||
|
uppExitToShellProcInfo = kPascalStackBased
|
|||
|
};
|
|||
|
|
|||
|
#if USESROUTINEDESCRIPTORS
|
|||
|
typedef UniversalProcPtr ExitToShellUPP;
|
|||
|
|
|||
|
#define CallExitToShellProc(userRoutine) \
|
|||
|
CallUniversalProc((UniversalProcPtr)(userRoutine),uppExitToShellProcInfo)
|
|||
|
#define NewExitToShellProc(userRoutine) \
|
|||
|
(ExitToShellUPP)NewRoutineDescriptor((ProcPtr)(userRoutine), \
|
|||
|
uppExitToShellProcInfo, GetCurrentArchitecture())
|
|||
|
|
|||
|
#else
|
|||
|
typedef ExitToShellProcPtr ExitToShellUPP;
|
|||
|
|
|||
|
#define CallExitToShellProc(userRoutine) \
|
|||
|
(*(userRoutine))()
|
|||
|
#define NewExitToShellProc(userRoutine) \
|
|||
|
(ExitToShellUPP)(userRoutine)
|
|||
|
#endif
|
|||
|
|
|||
|
#define DisposeExitToShellProc(userRoutine) \
|
|||
|
DisposeRoutineDescriptor(userRoutine)
|
|||
|
|
|||
|
#if defined(powerc)||defined(__powerc)
|
|||
|
#pragma options align=mac68k
|
|||
|
#endif
|
|||
|
struct ExitToShellUPPList{
|
|||
|
struct ExitToShellUPPList* nextProc;
|
|||
|
ExitToShellUPP userProc;
|
|||
|
};
|
|||
|
#if defined(powerc)||defined(__powerc)
|
|||
|
#pragma options align=reset
|
|||
|
#endif
|
|||
|
|
|||
|
typedef struct ExitToShellDataStruct ExitToShellDataRec,* ExitToShellDataPtr,** ExitToShellDataHdl;
|
|||
|
|
|||
|
typedef struct ExitToShellUPPList ExitToShellUPPList,* ExitToShellUPPListPtr,** ExitToShellUPPHdl;
|
|||
|
|
|||
|
#if defined(powerc)||defined(__powerc)
|
|||
|
#pragma options align=mac68k
|
|||
|
#endif
|
|||
|
struct ExitToShellDataStruct{
|
|||
|
unsigned long a5;
|
|||
|
ExitToShellUPPList* userProcs;
|
|||
|
ExitToShellUPP oldProc;
|
|||
|
};
|
|||
|
#if defined(powerc)||defined(__powerc)
|
|||
|
#pragma options align=reset
|
|||
|
#endif
|
|||
|
|
|||
|
/*
|
|||
|
* Static globals used within this file.
|
|||
|
*/
|
|||
|
static ExitToShellDataPtr gExitToShellData = (ExitToShellDataPtr) NULL;
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*
|
|||
|
* TclPlatformExit --
|
|||
|
*
|
|||
|
* This procedure implements the Macintosh specific exit routine.
|
|||
|
* We explicitly callthe ExitHandler function to do various clean
|
|||
|
* up.
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* None.
|
|||
|
*
|
|||
|
* Side effects:
|
|||
|
* We exit the process.
|
|||
|
*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
void
|
|||
|
TclPlatformExit(status)
|
|||
|
int status;
|
|||
|
{
|
|||
|
TclMacExitHandler();
|
|||
|
ExitToShell();
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*
|
|||
|
* TclMacExitHandler --
|
|||
|
*
|
|||
|
* This procedure is invoked after Tcl at the last possible moment
|
|||
|
* to clean up any state Tcl has left around that may cause other
|
|||
|
* applications to crash. For example, this function can be used
|
|||
|
* as the termination routine for CFM applications.
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* None.
|
|||
|
*
|
|||
|
* Side effects:
|
|||
|
* Various cleanup occurs.
|
|||
|
*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
void
|
|||
|
TclMacExitHandler()
|
|||
|
{
|
|||
|
ExitToShellUPPListPtr curProc;
|
|||
|
|
|||
|
/*
|
|||
|
* Loop through all installed Exit handlers
|
|||
|
* and call them. Always make sure we are in
|
|||
|
* a clean state in case we are recursivly called.
|
|||
|
*/
|
|||
|
if ((gExitToShellData) != NULL && (gExitToShellData->userProcs != NULL)){
|
|||
|
|
|||
|
/*
|
|||
|
* Call the installed exit to shell routines.
|
|||
|
*/
|
|||
|
curProc = gExitToShellData->userProcs;
|
|||
|
do {
|
|||
|
gExitToShellData->userProcs = curProc->nextProc;
|
|||
|
CallExitToShellProc(curProc->userProc);
|
|||
|
DisposeExitToShellProc(curProc->userProc);
|
|||
|
DisposePtr((Ptr) curProc);
|
|||
|
curProc = gExitToShellData->userProcs;
|
|||
|
} while (curProc != (ExitToShellUPPListPtr) NULL);
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*
|
|||
|
* TclMacInstallExitToShellPatch --
|
|||
|
*
|
|||
|
* This procedure installs a way to clean up state at the latest
|
|||
|
* possible moment before we exit. These are things that must
|
|||
|
* be cleaned up or the system will crash. The exact way in which
|
|||
|
* this is implemented depends on the architecture in which we are
|
|||
|
* running. For 68k applications we patch the ExitToShell call.
|
|||
|
* For PowerPC applications we just create a list of procs to call.
|
|||
|
* The function ExitHandler should be installed in the Code
|
|||
|
* Fragments terminiation routine.
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* None.
|
|||
|
*
|
|||
|
* Side effects:
|
|||
|
* Installs the new routine.
|
|||
|
*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
OSErr
|
|||
|
TclMacInstallExitToShellPatch(newProc)
|
|||
|
ExitToShellProcPtr newProc;
|
|||
|
{
|
|||
|
ExitToShellUPP exitHandler;
|
|||
|
ExitToShellUPPListPtr listPtr;
|
|||
|
|
|||
|
if (gExitToShellData == (ExitToShellDataPtr) NULL){
|
|||
|
TclMacInitExitToShell(true);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Add the passed in function pointer to the list of functions
|
|||
|
* to be called when ExitToShell is called.
|
|||
|
*/
|
|||
|
exitHandler = NewExitToShellProc(newProc);
|
|||
|
listPtr = (ExitToShellUPPListPtr) NewPtrClear(sizeof(ExitToShellUPPList));
|
|||
|
listPtr->userProc = exitHandler;
|
|||
|
listPtr->nextProc = gExitToShellData->userProcs;
|
|||
|
gExitToShellData->userProcs = listPtr;
|
|||
|
|
|||
|
return noErr;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*
|
|||
|
* ExitToShellPatchRoutine --
|
|||
|
*
|
|||
|
* This procedure is invoked when someone calls ExitToShell for
|
|||
|
* this application. This function performs some last miniute
|
|||
|
* clean up and then calls the real ExitToShell routine.
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* None.
|
|||
|
*
|
|||
|
* Side effects:
|
|||
|
* Various cleanup occurs.
|
|||
|
*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
static pascal void
|
|||
|
ExitToShellPatchRoutine()
|
|||
|
{
|
|||
|
ExitToShellUPP oldETS;
|
|||
|
long oldA5;
|
|||
|
|
|||
|
/*
|
|||
|
* Set up our A5 world. This allows us to have
|
|||
|
* access to our global variables in the 68k world.
|
|||
|
*/
|
|||
|
oldA5 = SetCurrentA5();
|
|||
|
SetA5(gExitToShellData->a5);
|
|||
|
|
|||
|
/*
|
|||
|
* Call the function that invokes all
|
|||
|
* of the handlers.
|
|||
|
*/
|
|||
|
TclMacExitHandler();
|
|||
|
|
|||
|
/*
|
|||
|
* Call the origional ExitToShell routine.
|
|||
|
*/
|
|||
|
oldETS = gExitToShellData->oldProc;
|
|||
|
DisposePtr((Ptr) gExitToShellData);
|
|||
|
SetA5(oldA5);
|
|||
|
CallExitToShellProc(oldETS);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*
|
|||
|
* TclMacInitExitToShell --
|
|||
|
*
|
|||
|
* This procedure initializes the ExitToShell clean up machanism.
|
|||
|
* Generally, this is handled automatically when users make a call
|
|||
|
* to InstallExitToShellPatch. However, it can be called
|
|||
|
* explicitly at startup time to turn off the patching mechanism.
|
|||
|
* This can be used by code resources which could be removed from
|
|||
|
* the application before ExitToShell is called.
|
|||
|
*
|
|||
|
* Note, if we are running from CFM code we never install the
|
|||
|
* patch. Instead, the function ExitHandler should be installed
|
|||
|
* as the terminiation routine for the code fragment.
|
|||
|
*
|
|||
|
* Results:
|
|||
|
* None.
|
|||
|
*
|
|||
|
* Side effects:
|
|||
|
* Creates global state.
|
|||
|
*
|
|||
|
*----------------------------------------------------------------------
|
|||
|
*/
|
|||
|
|
|||
|
void
|
|||
|
TclMacInitExitToShell(usePatch)
|
|||
|
int usePatch;
|
|||
|
{
|
|||
|
if (gExitToShellData == (ExitToShellDataPtr) NULL){
|
|||
|
#if GENERATINGCFM
|
|||
|
gExitToShellData = (ExitToShellDataPtr)
|
|||
|
NewPtr(sizeof(ExitToShellDataRec));
|
|||
|
gExitToShellData->a5 = SetCurrentA5();
|
|||
|
gExitToShellData->userProcs = (ExitToShellUPPList*) NULL;
|
|||
|
#else
|
|||
|
ExitToShellUPP oldExitToShell, newExitToShellPatch;
|
|||
|
short exitToShellTrap;
|
|||
|
|
|||
|
/*
|
|||
|
* Initialize patch mechanism.
|
|||
|
*/
|
|||
|
|
|||
|
gExitToShellData = (ExitToShellDataPtr) NewPtr(sizeof(ExitToShellDataRec));
|
|||
|
gExitToShellData->a5 = SetCurrentA5();
|
|||
|
gExitToShellData->userProcs = (ExitToShellUPPList*) NULL;
|
|||
|
|
|||
|
/*
|
|||
|
* Save state needed to call origional ExitToShell routine. Install
|
|||
|
* the new ExitToShell code in it's place.
|
|||
|
*/
|
|||
|
if (usePatch) {
|
|||
|
exitToShellTrap = _ExitToShell & 0x3ff;
|
|||
|
newExitToShellPatch = NewExitToShellProc(ExitToShellPatchRoutine);
|
|||
|
oldExitToShell = (ExitToShellUPP)
|
|||
|
NGetTrapAddress(exitToShellTrap, ToolTrap);
|
|||
|
NSetTrapAddress((UniversalProcPtr) newExitToShellPatch,
|
|||
|
exitToShellTrap, ToolTrap);
|
|||
|
gExitToShellData->oldProc = oldExitToShell;
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|