os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/mac/tclMacExit.c
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
/* 
sl@0
     2
 * tclMacExit.c --
sl@0
     3
 *
sl@0
     4
 *	This file contains routines that deal with cleaning up various state
sl@0
     5
 *	when Tcl/Tk applications quit.  Unfortunantly, not all state is cleaned
sl@0
     6
 *	up by the process when an application quites or crashes.  Also you
sl@0
     7
 *	need to do different things depending on wether you are running as
sl@0
     8
 *	68k code, PowerPC, or a code resource.  The Exit handler code was 
sl@0
     9
 *	adapted from code posted on alt.sources.mac by Dave Nebinger.
sl@0
    10
 *
sl@0
    11
 * Copyright (c) 1995 Dave Nebinger.
sl@0
    12
 * Copyright (c) 1995-1996 Sun Microsystems, Inc.
sl@0
    13
 *
sl@0
    14
 * See the file "license.terms" for information on usage and redistribution
sl@0
    15
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
sl@0
    16
 *
sl@0
    17
 * RCS: @(#) $Id: tclMacExit.c,v 1.4 1999/04/16 00:47:19 stanton Exp $
sl@0
    18
 */
sl@0
    19
sl@0
    20
#include "tclInt.h"
sl@0
    21
#include "tclMacInt.h"
sl@0
    22
#include <SegLoad.h>
sl@0
    23
#include <Traps.h>
sl@0
    24
#include <Processes.h>
sl@0
    25
sl@0
    26
/*
sl@0
    27
 * Various typedefs and defines needed to patch ExitToShell.
sl@0
    28
 */
sl@0
    29
 
sl@0
    30
enum {
sl@0
    31
        uppExitToShellProcInfo = kPascalStackBased
sl@0
    32
};
sl@0
    33
sl@0
    34
#if GENERATINGCFM
sl@0
    35
typedef UniversalProcPtr ExitToShellUPP;
sl@0
    36
sl@0
    37
#define CallExitToShellProc(userRoutine)        \
sl@0
    38
        CallUniversalProc((UniversalProcPtr)(userRoutine),uppExitToShellProcInfo)
sl@0
    39
#define NewExitToShellProc(userRoutine) \
sl@0
    40
        (ExitToShellUPP)NewRoutineDescriptor((ProcPtr)(userRoutine), \
sl@0
    41
		uppExitToShellProcInfo, GetCurrentArchitecture())
sl@0
    42
sl@0
    43
#else
sl@0
    44
typedef ExitToShellProcPtr ExitToShellUPP;
sl@0
    45
sl@0
    46
#define CallExitToShellProc(userRoutine)        \
sl@0
    47
        (*(userRoutine))()
sl@0
    48
#define NewExitToShellProc(userRoutine) \
sl@0
    49
        (ExitToShellUPP)(userRoutine)
sl@0
    50
#endif
sl@0
    51
sl@0
    52
#define DisposeExitToShellProc(userRoutine) \
sl@0
    53
        DisposeRoutineDescriptor(userRoutine)
sl@0
    54
sl@0
    55
#if defined(powerc)||defined(__powerc)
sl@0
    56
#pragma options align=mac68k
sl@0
    57
#endif
sl@0
    58
struct ExitToShellUPPList{
sl@0
    59
        struct ExitToShellUPPList* nextProc;
sl@0
    60
        ExitToShellUPP userProc;
sl@0
    61
};
sl@0
    62
#if defined(powerc)||defined(__powerc)
sl@0
    63
#pragma options align=reset
sl@0
    64
#endif
sl@0
    65
sl@0
    66
typedef struct ExitToShellDataStruct ExitToShellDataRec,* ExitToShellDataPtr,** ExitToShellDataHdl;
sl@0
    67
sl@0
    68
typedef struct ExitToShellUPPList ExitToShellUPPList,* ExitToShellUPPListPtr,** ExitToShellUPPHdl;
sl@0
    69
sl@0
    70
#if defined(powerc)||defined(__powerc)
sl@0
    71
#pragma options align=mac68k
sl@0
    72
#endif
sl@0
    73
struct ExitToShellDataStruct{
sl@0
    74
    unsigned long a5;
sl@0
    75
    ExitToShellUPPList* userProcs;
sl@0
    76
    ExitToShellUPP oldProc;
sl@0
    77
};
sl@0
    78
#if defined(powerc)||defined(__powerc)
sl@0
    79
#pragma options align=reset
sl@0
    80
#endif
sl@0
    81
sl@0
    82
/*
sl@0
    83
 * Static globals used within this file.
sl@0
    84
 */
sl@0
    85
static ExitToShellDataPtr gExitToShellData = (ExitToShellDataPtr) NULL;
sl@0
    86
sl@0
    87

sl@0
    88
/*
sl@0
    89
 *----------------------------------------------------------------------
sl@0
    90
 *
sl@0
    91
 * TclPlatformExit --
sl@0
    92
 *
sl@0
    93
 *	This procedure implements the Macintosh specific exit routine.
sl@0
    94
 *	We explicitly callthe ExitHandler function to do various clean
sl@0
    95
 *	up.  
sl@0
    96
 *
sl@0
    97
 * Results:
sl@0
    98
 *	None.
sl@0
    99
 *
sl@0
   100
 * Side effects:
sl@0
   101
 *	We exit the process.
sl@0
   102
 *
sl@0
   103
 *----------------------------------------------------------------------
sl@0
   104
 */
sl@0
   105
sl@0
   106
void
sl@0
   107
TclpExit(
sl@0
   108
    int status)		/* Ignored. */
sl@0
   109
{
sl@0
   110
    TclMacExitHandler();
sl@0
   111
sl@0
   112
/* 
sl@0
   113
 * If we are using the Metrowerks Standard Library, then we will call its exit so that it
sl@0
   114
 * will get a chance to clean up temp files, and so forth.  It always calls the standard 
sl@0
   115
 * ExitToShell, so the Tcl handlers will also get called.
sl@0
   116
 *   
sl@0
   117
 * If you have another exit, make sure that it does not patch ExitToShell, and does
sl@0
   118
 * call it.  If so, it will probably work as well.
sl@0
   119
 *
sl@0
   120
 */
sl@0
   121
 
sl@0
   122
#ifdef __MSL__    
sl@0
   123
    exit(status);
sl@0
   124
#else
sl@0
   125
    ExitToShell();
sl@0
   126
#endif
sl@0
   127
sl@0
   128
}
sl@0
   129

sl@0
   130
/*
sl@0
   131
 *----------------------------------------------------------------------
sl@0
   132
 *
sl@0
   133
 * TclMacExitHandler --
sl@0
   134
 *
sl@0
   135
 *	This procedure is invoked after Tcl at the last possible moment
sl@0
   136
 *	to clean up any state Tcl has left around that may cause other
sl@0
   137
 *	applications to crash.  For example, this function can be used
sl@0
   138
 *	as the termination routine for CFM applications.
sl@0
   139
 *
sl@0
   140
 * Results:
sl@0
   141
 *	None.
sl@0
   142
 *
sl@0
   143
 * Side effects:
sl@0
   144
 *	Various cleanup occurs.
sl@0
   145
 *
sl@0
   146
 *----------------------------------------------------------------------
sl@0
   147
 */
sl@0
   148
sl@0
   149
void
sl@0
   150
TclMacExitHandler()
sl@0
   151
{
sl@0
   152
    ExitToShellUPPListPtr curProc;
sl@0
   153
sl@0
   154
    /*
sl@0
   155
     * Loop through all installed Exit handlers
sl@0
   156
     * and call them.  Always make sure we are in
sl@0
   157
     * a clean state in case we are recursivly called.
sl@0
   158
     */
sl@0
   159
    if ((gExitToShellData) != NULL && (gExitToShellData->userProcs != NULL)){
sl@0
   160
    
sl@0
   161
	/*
sl@0
   162
	 * Call the installed exit to shell routines.
sl@0
   163
	 */
sl@0
   164
	curProc = gExitToShellData->userProcs;
sl@0
   165
	do {
sl@0
   166
	    gExitToShellData->userProcs = curProc->nextProc;
sl@0
   167
	    CallExitToShellProc(curProc->userProc);
sl@0
   168
	    DisposeExitToShellProc(curProc->userProc);
sl@0
   169
	    DisposePtr((Ptr) curProc);
sl@0
   170
	    curProc = gExitToShellData->userProcs;
sl@0
   171
	} while (curProc != (ExitToShellUPPListPtr) NULL);
sl@0
   172
    }
sl@0
   173
sl@0
   174
    return;
sl@0
   175
}
sl@0
   176

sl@0
   177
/*
sl@0
   178
 *----------------------------------------------------------------------
sl@0
   179
 *
sl@0
   180
 * TclMacInstallExitToShellPatch --
sl@0
   181
 *
sl@0
   182
 *	This procedure installs a way to clean up state at the latest
sl@0
   183
 *	possible moment before we exit.  These are things that must
sl@0
   184
 *	be cleaned up or the system will crash.  The exact way in which
sl@0
   185
 *	this is implemented depends on the architecture in which we are
sl@0
   186
 *	running.  For 68k applications we patch the ExitToShell call.
sl@0
   187
 *	For PowerPC applications we just create a list of procs to call.
sl@0
   188
 *	The function ExitHandler should be installed in the Code 
sl@0
   189
 *	Fragments terminiation routine.
sl@0
   190
 *
sl@0
   191
 * Results:
sl@0
   192
 *	None.
sl@0
   193
 *
sl@0
   194
 * Side effects:
sl@0
   195
 *	Installs the new routine.
sl@0
   196
 *
sl@0
   197
 *----------------------------------------------------------------------
sl@0
   198
 */
sl@0
   199
sl@0
   200
OSErr 
sl@0
   201
TclMacInstallExitToShellPatch(
sl@0
   202
    ExitToShellProcPtr newProc)		/* Function pointer. */
sl@0
   203
{
sl@0
   204
    ExitToShellUPP exitHandler;
sl@0
   205
    ExitToShellUPPListPtr listPtr;
sl@0
   206
sl@0
   207
    if (gExitToShellData == (ExitToShellDataPtr) NULL){
sl@0
   208
	TclMacInitExitToShell(true);
sl@0
   209
    }
sl@0
   210
sl@0
   211
    /*
sl@0
   212
     * Add the passed in function pointer to the list of functions
sl@0
   213
     * to be called when ExitToShell is called.
sl@0
   214
     */
sl@0
   215
    exitHandler = NewExitToShellProc(newProc);
sl@0
   216
    listPtr = (ExitToShellUPPListPtr) NewPtrClear(sizeof(ExitToShellUPPList));
sl@0
   217
    listPtr->userProc = exitHandler;
sl@0
   218
    listPtr->nextProc = gExitToShellData->userProcs;
sl@0
   219
    gExitToShellData->userProcs = listPtr;
sl@0
   220
sl@0
   221
    return noErr;
sl@0
   222
}
sl@0
   223

sl@0
   224
/*
sl@0
   225
 *----------------------------------------------------------------------
sl@0
   226
 *
sl@0
   227
 * ExitToShellPatchRoutine --
sl@0
   228
 *
sl@0
   229
 *	This procedure is invoked when someone calls ExitToShell for
sl@0
   230
 *	this application.  This function performs some last miniute
sl@0
   231
 *	clean up and then calls the real ExitToShell routine.
sl@0
   232
 *
sl@0
   233
 * Results:
sl@0
   234
 *	None.
sl@0
   235
 *
sl@0
   236
 * Side effects:
sl@0
   237
 *	Various cleanup occurs.
sl@0
   238
 *
sl@0
   239
 *----------------------------------------------------------------------
sl@0
   240
 */
sl@0
   241
sl@0
   242
static pascal void
sl@0
   243
ExitToShellPatchRoutine()
sl@0
   244
{
sl@0
   245
    ExitToShellUPP oldETS;
sl@0
   246
    long oldA5;
sl@0
   247
sl@0
   248
    /*
sl@0
   249
     * Set up our A5 world.  This allows us to have
sl@0
   250
     * access to our global variables in the 68k world.
sl@0
   251
     */
sl@0
   252
    oldA5 = SetCurrentA5();
sl@0
   253
    SetA5(gExitToShellData->a5);
sl@0
   254
sl@0
   255
    /*
sl@0
   256
     * Call the function that invokes all
sl@0
   257
     * of the handlers.
sl@0
   258
     */
sl@0
   259
    TclMacExitHandler();
sl@0
   260
sl@0
   261
    /*
sl@0
   262
     * Call the origional ExitToShell routine.
sl@0
   263
     */
sl@0
   264
    oldETS = gExitToShellData->oldProc;
sl@0
   265
    DisposePtr((Ptr) gExitToShellData);
sl@0
   266
    SetA5(oldA5);
sl@0
   267
    CallExitToShellProc(oldETS);
sl@0
   268
    return;
sl@0
   269
}
sl@0
   270

sl@0
   271
/*
sl@0
   272
 *----------------------------------------------------------------------
sl@0
   273
 *
sl@0
   274
 * TclMacInitExitToShell --
sl@0
   275
 *
sl@0
   276
 *	This procedure initializes the ExitToShell clean up machanism.
sl@0
   277
 *	Generally, this is handled automatically when users make a call
sl@0
   278
 *	to InstallExitToShellPatch.  However, it can be called 
sl@0
   279
 *	explicitly at startup time to turn off the patching mechanism.
sl@0
   280
 *	This can be used by code resources which could be removed from
sl@0
   281
 *	the application before ExitToShell is called.
sl@0
   282
 *
sl@0
   283
 *	Note, if we are running from CFM code we never install the
sl@0
   284
 *	patch.  Instead, the function ExitHandler should be installed
sl@0
   285
 *	as the terminiation routine for the code fragment.
sl@0
   286
 *
sl@0
   287
 * Results:
sl@0
   288
 *	None.
sl@0
   289
 *
sl@0
   290
 * Side effects:
sl@0
   291
 *	Creates global state.
sl@0
   292
 *
sl@0
   293
 *----------------------------------------------------------------------
sl@0
   294
 */
sl@0
   295
sl@0
   296
void 
sl@0
   297
TclMacInitExitToShell(
sl@0
   298
    int usePatch)	/* True if on 68k. */
sl@0
   299
{
sl@0
   300
    if (gExitToShellData == (ExitToShellDataPtr) NULL){
sl@0
   301
#if GENERATINGCFM
sl@0
   302
	gExitToShellData = (ExitToShellDataPtr)
sl@0
   303
	  NewPtr(sizeof(ExitToShellDataRec));
sl@0
   304
	gExitToShellData->a5 = SetCurrentA5();
sl@0
   305
	gExitToShellData->userProcs = (ExitToShellUPPList*) NULL;
sl@0
   306
#else
sl@0
   307
	ExitToShellUPP oldExitToShell, newExitToShellPatch;
sl@0
   308
	short exitToShellTrap;
sl@0
   309
	
sl@0
   310
	/*
sl@0
   311
	 * Initialize patch mechanism.
sl@0
   312
	 */
sl@0
   313
	 
sl@0
   314
	gExitToShellData = (ExitToShellDataPtr) NewPtr(sizeof(ExitToShellDataRec));
sl@0
   315
	gExitToShellData->a5 = SetCurrentA5();
sl@0
   316
	gExitToShellData->userProcs = (ExitToShellUPPList*) NULL;
sl@0
   317
sl@0
   318
	/*
sl@0
   319
	 * Save state needed to call origional ExitToShell routine.  Install
sl@0
   320
	 * the new ExitToShell code in it's place.
sl@0
   321
	 */
sl@0
   322
	if (usePatch) {
sl@0
   323
	    exitToShellTrap = _ExitToShell & 0x3ff;
sl@0
   324
	    newExitToShellPatch = NewExitToShellProc(ExitToShellPatchRoutine);
sl@0
   325
	    oldExitToShell = (ExitToShellUPP)
sl@0
   326
	      NGetTrapAddress(exitToShellTrap, ToolTrap);
sl@0
   327
	    NSetTrapAddress((UniversalProcPtr) newExitToShellPatch,
sl@0
   328
		    exitToShellTrap, ToolTrap);
sl@0
   329
	    gExitToShellData->oldProc = oldExitToShell;
sl@0
   330
	}
sl@0
   331
#endif
sl@0
   332
    }
sl@0
   333
}