home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-08-05 | 5.7 KB | 138 lines | [TEXT/CWIE] |
- /*
- AtExitToShell.c
-
- void YourFunction(void);
-
- error=AtExitToShell(YourFunction);
-
- AtExitToShell(YourFunction) requests that your function be called when the
- application quits, i.e. calls the ExitToShell trap, which tells the MacOS that
- it's done. Your function must have no arguments and no return value.
-
- (MATLAB: If you compile this file as a MEX resource, to be called from MATLAB,
- then your call to AtExitToShell is a request that your function be called when
- the MEX resource is flushed from memory.)
-
- Many VideoToolbox routines set up interrupt service routines that must be killed
- before the program goes away. We want to kill these whether we quit via exit(),
- abort(), or the ExitToShell trap is invoked directly, e.g. if user types "ES"
- in MacsBug. The only way to be sure of killing something before the application
- goes away is to attach its killer, by patching, to the ExitToShell trap. That's
- what's done here.
-
- AtExitToShell() is closely modeled on the ANSI function atexit(). I wrote it to
- overcome the restrictive implementation of atexit() and _atexit() in CodeWarrior:
- they only invoke your functions if the ANSI function exit() is called, NOT if
- you call abort(), or the user types "ES" in MacsBug. I think that AtExitToShell
- is equivalent to the non-ANSI _atexit() routine provided by the Symantec THINK C
- environment.
-
- The registration list (of user functions) is last-in, first-out. When you
- eventually quit, your functions will be called in reverse of the order in which
- you registered them. No checking is made for duplication: the same function may
- be registed multiple times, and will be called multiple times.
-
- CAUTION: your application's runtime environment (e.g. stdio) will normally have
- shut itself down by the time it calls ExitToShell(), so a function scheduled for
- that time should not assume the availability of such services (e.g. printf).
- There's no restriction on the use of MacOS services.
-
- MATLAB: the Standard C atexit() and THINK C _atexit() routines should not be
- used in MATLAB code resources, because they aren't designed to handle the
- situation of code that may be flushed any time MATLAB executes "clear mex" or
- "clear all", at a time unrelated to exiting of the MATLAB application itself.
- Instead, MATLAB provides mexAtExit(), which allows you to register one callback
- per MEX file, which is called when the MEX file is flushed. (The problem with using
- mexAtExit, is that it's hard for any particular subroutine to know whether somebody
- else has already used up the single available slot in the call-back table.)
- In order to make your C subroutines as portable and autonomous as possible, you may
- prefer to use this AtExitToShell() which allows you to register lots of callback
- routines, and registers itself, once, with mexAtExit.
-
- CAUTION: Since MATLAB registers only one function per MEX it is important that
- you consistently adopt one strategy. Either make lots of calls to AtExitToShell
- (and NONE to mexAtExit), or just one call to mexAtExit. If you call both AtExitToShell
- and mexAtExit then one will displace the other in MATLAB's one-entry table.
-
- The code to patch ExitToShell is based on examples that appeared in UseNet
- csmp-digest-v3-046 by Kevin Bell (kbell@cs.utexas.edu) and Bill Hofmann
- (wdh@netcom.com) in response to a query by Steve Coy (stevec@jolt.mpx.com.au)
-
- HISTORY:
- 10/27/94 dgp wrote the ExitToShell patch, based on code from UseNet csmp-digest.
- 6/17/95 dgp wrote AtExitToShell.c
- 7/1/95 dgp made compatible with pre-universal apple headers.
- Disable if MATLAB is true. Added comments about MATLAB.
- 7/17/95 dgp made compatible with pre-universal headers
- 4/19/96 dgp call mexAtExit(). I know this is ok for PPC, but may not work for 68k.
- 6/10/96 dgp fixed initialization error when MATLAB is true.
- 6/10/96 dgp added a couple paragraphs explaining its use in MATLAB MEX files.
- 6/11/96 dgp In response to concerns raised by David Brainard, I added text above
- warning about the danger of calling BOTH AtExitToShell and mexAtExit, and
- I made the A5 stuff conditional on !MATLAB.
- 8/5/96 dgp #undef mexAtExit to make sure we call the real McCoy.
- */
- #include "VideoToolbox.h"
- #ifndef __TRAPS__
- #include <Traps.h> // _ExitToShell
- #endif
- #include <SegLoad.h> // ExitToShell()
- #if UNIVERSAL_HEADERS
- typedef UniversalProcPtr TrapAddressType;
- #else
- #define UniversalProcPtr ProcPtr
- #define NewRoutineDescriptor(a,b,c) a
- typedef long TrapAddressType;
- #endif
- static pascal void MyExitToShell(void);
- #define FUNCTIONS 35
- static UniversalProcPtr oldExitToShellTrapAddress=NULL; // save address of real ExitToShell trap.
- static void (*userFunction[FUNCTIONS])(void); // table of user functions to be called at exit.
-
- int AtExitToShell(void (*userFunctionPtr)(void))
- {
- #if !MATLAB
- UniversalProcPtr myExitToShellUPP;
- #endif
- int i;
- static Boolean firstTime=1;
-
- if(firstTime){
- #if !MATLAB
- myExitToShellUPP=NewRoutineDescriptor((ProcPtr)MyExitToShell
- ,kPascalStackBased,GetCurrentISA());
- oldExitToShellTrapAddress=(UniversalProcPtr)GetToolTrapAddress(_ExitToShell);
- SetToolTrapAddress((TrapAddressType)myExitToShellUPP,_ExitToShell);
- #else
- // Ask MATLAB to call MyExitToShell just before disposing of our MEX resource.
- #undef mexAtExit
- mexAtExit((void *)MyExitToShell);
- #endif
- for(i=0;i<FUNCTIONS;i++)userFunction[i]=NULL;
- firstTime=0;
- }
- for(i=0;i<FUNCTIONS;i++)if(userFunction[i]==NULL){
- userFunction[i]=userFunctionPtr;
- return 0; // success
- }
- return 1; // failure: the table's already full
- }
-
- static pascal void MyExitToShell(void)
- {
- int i;
-
- #if !MATLAB
- SetCurrentA5();
- SetToolTrapAddress((TrapAddressType)oldExitToShellTrapAddress,_ExitToShell);
- #endif
-
- for(i=FUNCTIONS-1;i>=0;i--)if(userFunction[i]!=NULL){
- (*userFunction[i])();
- }
-
- #if !MATLAB
- ExitToShell();
- #endif
- }
-