home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-05-09 | 8.2 KB | 210 lines | [TEXT/CWIE] |
- /*
- SetGestaltValue1.c
-
- enum{gestaltPsychTable='Psyc'} // this can be whatever you want
-
- error=SetGestaltValue1(gestaltPsychTable,table); // install a table address
- error=SetGestaltValue1(gestaltPsychTable,NULL); // replace the table address with NULL
-
- error=Gestalt(gestaltPsychTable,&tablePtr); // retrieve the table address
-
- SetGestaltValue1.c provides an approximate equivalent for the
- SetGestaltValue() function provided in System 7.5 (see Apple's
- Gestalt.h), but only requires System 7 or better. SetGestaltValue1()
- allows you to install a new Gestalt selector or replace an existing selector
- installed by SetGestalt1. DON'T use SetGestaltValue1() to replace a
- pre-existing selector NOT installed by SetGestalt1 because its attempt
- to free the storage (upp and code) may fail.
-
- The Macintosh Gestalt() function provides a way for many autonomous
- programs to share a global table. All the programs simply call Gestalt()
- with the same selector and Gestalt returns the table address. Any
- program calling Gestalt() to get the table address should check that
- error==0 and that table!=NULL before using the table. To set the
- selector and table address in Gestalt you can either use
- SetGestaltValue1 (this file), which works on all Mac Systems and
- architectures, or you can use Apple's routines.
-
- Instead of using SetGestaltValue1 (this file), you could use Apple's
- routines. System 7.5 provides NewGestaltValue() and SetGestaltValue()
- (see Apple's Gestalt.h). PowerPC computers require System 7.5 or better,
- so your ppc code can safely assume the presence of those routines. If
- your program may be run on 68k computers running an earlier System, then
- your 68k code should link in Apple's GestaltValue.o library, which Apple
- supplies on their developer disks.
-
- Invent your own selector name, e.g. gestaltPsychTable. By convention,
- the selector name should begin with "gestalt" and end with "Table". Its
- value is a four-character code, like 'Psyc'. Apple reserves all the
- lowercase-only codes for itself.
-
- In order for the Gestalt selector routine to stick around, and not cause
- grief to Gestalt by disappearing when the application quits, we follow
- Apple's guidelines and install it in the System heap. Once installed
- it'll stay there until the machine is rebooted. You can't get rid of a
- selector once you've installed it, but you can call SetGestaltValue1()
- again, and assign the response NULL.
-
- The selector function that we install into the System Heap is 68k code,
- because I know how to copy such routines, and have had no success doing
- so with ppc code. To have the 68k code available even when this file is
- compiled for ppc, without resorting to using resources, i.e. multiple files,
- i saved the machine code from a disassembly in a C array.
-
- QUESTION:
- In thinking about the uses of this routine, it occurred to me that if an
- application creates a table in its own heap space and publishes the table's
- address via Gestalt, then it might happen that the application is
- abnormally terminated before it has a chance to NULL the table address
- published by Gestalt. The System would recover the application's memory,
- including the table, but the Gestalt value would persist, dangerously
- providing a pointer to memory that the System considers unassigned. So,
- how can we tell if a table pointer is valid?
-
- ANSWER:
- Every running application has a unique process serial number (psn). An
- application that creates a table in its own heap space and publishes the
- table's address via Gestalt should store its psn in the table. Whenever
- we retrieve a table address via Gestalt we should check the psn field.
- If the table's psn field is not NULL, then we should make sure that that
- process is still running. At the moment, David Brainard and I are only
- worried about MEX files that all run as part of the MATLAB
- application, so it is enough for us to simply make sure that the stored
- psn matches our current psn.
-
- #include <Processes.h>
- ProcessSerialNumber psn;
- Boolean ours;
-
- // when we make the table, mark it as our own
- error=GetCurrentProcess(&table->psn);
-
- // when we access the table, make sure that it's ours
- error=GetCurrentProcess(&psn);
- error=SameProcess(&table->psn,&psn,&ours); // Apple says this is the way to compare psns.
- if(!ours) table is invalid,
-
- HISTORY:
- 5/7/96 dgp wrote it.
- 5/9/96 dgp got it to work on ppc.
- */
-
- #include "VideoToolbox.h"
- //#include <Gestalt.h>
-
- // modified from Gestalt.h because our routine is ALWAYS 68k code.
- #if GENERATINGCFM
- #define New68kSelectorFunctionProc(userRoutine) \
- (SelectorFunctionUPP) NewRoutineDescriptor((ProcPtr)(userRoutine), uppSelectorFunctionProcInfo, kM68kISA)
- #else
- #define New68kSelectorFunctionProc(userRoutine) \
- ((SelectorFunctionUPP) (userRoutine))
- #endif
-
- #if (THINK_C || THINK_CPLUS || SYMANTEC_C)
- #pragma options(!profile)
- #endif
- #if __MWERKS__ && __profile__
- #pragma profile off
- #endif
-
- // There's nothing special about these numbers. We hope that they won't coincide with
- // machine instructions used in the tiny MyGestaltValue program, immediately following.
- #define SELECTOR 0x12345678
- #define RESPONSE 0x87654321
-
- // SetGestaltValue1 copies the compiled version (below) of this code to the
- // System heap and sets the copy's selector and response.
- pascal OSErr MyGestaltValue(OSType selector,long *response); // private
- pascal OSErr MyGestaltValue(OSType selector,long *response)
- {
- if(selector==SELECTOR){
- *response=RESPONSE;
- return 0;
- }else return gestaltUnknownErr;
- }
-
- /*
- MyGestaltValueCode is the 68k compiled code produced by Metrowerks C 8
- for the MyGestaltValue routine above. This allows me to install a 68k
- code version even when this file is compiled for ppc. I've found it easy
- to copy, modify, and install a 68k routine, but haven't succeeded when I
- tried to do the same with a ppc routine, because I'm not quite sure what
- to do about the indirection through the TVector (nor have I found any
- documentation on it.) Apple Developer Tech Support told me that all ppc
- routines are called indirectly via a TVector.
- */
- short myGestaltValueCode[]={
- 0x4E56,0x0000 // LINK A6,#$0000
- ,0x0CAE,0x1234,0x5678 // CMPI.L #$12345678,$000C(A6)
- ,0x000C
- ,0x6610 // BNE.S *+$0012
- ,0x206E,0x0008 // MOVEA.L $0008(A6),A0
- ,0x20BC,0x8765,0x4321 // MOVE.L #$87654321,(A0)
- ,0x426F,0x0010 // CLR.W $0010(A7)
- ,0x6006 // BRA.S *+$0008
- ,0x3F7C,0xEA52,0x0010 // MOVE.W #$EA52,$0010(A7)
- ,0x4E5E // UNLK A6
- ,0x205F // MOVEA.L (A7)+,A0
- ,0x504F // ADDQ.W #$8,A7
- ,0x4ED0 // JMP (A0)
- ,0x8E4D,0x5947,0x4553 // DC.B $80+$0E, 'MYGESTALTVALUE', $00
- ,0x5441,0x4C54,0x5641
- ,0x4C55,0x4500,0x0000
- };
-
- OSErr SetGestaltValue1(OSType selector,long response)
- {
- Ptr ptr;
- OSErr error;
- long value,version;
- SelectorFunctionUPP upp,oldUpp;
- THz heapZone;
- long size;
- unsigned short *wordPtr;
- SelectorFunctionProcPtr functionPtr;
-
- Gestalt(gestaltSystemVersion,&version);
- if(version<0x700)PrintfExit("%s %ld. Sorry. I need System 7 or better.\n",__FILE__,(long)__LINE__);
- functionPtr=(void *)myGestaltValueCode;
- size=sizeof(myGestaltValueCode);
- // copy our function to System Heap
- ptr=NewPtrSys(size);
- if(ptr==NULL)PrintfExit("%s %ld. No space in System Heap.\n",__FILE__,(long)__LINE__);
- BlockMove(functionPtr,ptr,size);
- // Set the copy's selector and response.
- wordPtr=(unsigned short *)ptr;
- wordPtr[3]=selector>>16;
- wordPtr[4]=selector&0xffff;
- wordPtr[10]=response>>16;
- wordPtr[11]=response&0xffff;
- #if GENERATINGPOWERPC
- MakeDataExecutable(ptr,size);
- #else
- FlushCodeCacheRange(ptr,size);
- #endif
- heapZone=GetZone();
- SetZone(SystemZone());
- upp=New68kSelectorFunctionProc(ptr); // allocate UUP in System Heap
- SetZone(heapZone);
- // does our Gestalt selector already exist?
- error=Gestalt(selector,&value);
- if(!error){
- // yes, replace it. (It may persist from an earlier run of MATLAB.)
- error=ReplaceGestalt(selector,upp,&oldUpp);
- if(error)PrintfExit("%s %ld. ReplaceGestalt error %ld.\n",__FILE__,(long)__LINE__,(long)error);
- // free the old function's space in the System Heap
- if(oldUpp!=NULL){
- #if GENERATINGCFM
- DisposePtr((Ptr)oldUpp->routineRecords[0].procDescriptor);
- #endif
- DisposePtr((Ptr)oldUpp);
- }
- }else{
- // no, install it.
- error=NewGestalt(selector,upp);
- if(error)PrintfExit("%s %ld. NewGestalt error %ld.\n",__FILE__,(long)__LINE__,(long)error);
- }
- return error;
- }
-