home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.sys.mac.programmer
- Path: sparky!uunet!mcsun!sun4nl!utrcu1!infnews!heksterb
- From: heksterb@cs.utwente.nl (Ben Hekster)
- Subject: Re: Porting code using fork() to the Mac
- Message-ID: <1992Aug18.113422.28901@cs.utwente.nl>
- Summary: CODE segment-unloading grow zone function
- Sender: usenet@cs.utwente.nl
- Nntp-Posting-Host: utis96
- Organization: University of Twente, Dept. of Computer Science
- References: <1992Aug16.083656.22198@cs.utwente.nl>
- Date: Tue, 18 Aug 1992 11:34:22 GMT
- Lines: 196
-
-
- Hi--
-
- I had a couple of requests to post my CODE segment-unloading grow zone
- function, so here it is.
-
- As you can see, it's actually written in C++ (the Language of
- the Gods), not in Assembly. I've taken this code out of my class
- library and extracted just (hopefully) all the relevant bits. The
- conversion to C shouldn't be much of a problem. Though I suppose some
- people may find it rather sparsely commented, that's the way I like
- it. I prefer to think that it's self-documenting...
-
- I wouldn't necessarily mind rewriting it in 68000 if I thought
- it was worth it. I haven't done any profiling on this code, so I'm not
- yet convinced that it would be, though I can see some nested loops in
- there and some possible `optimizations'.
-
- The reason why this doesn't really bother me is that the grow
- zone function doesn't get called often, and only when you are operating
- close to the limit of available memory. One of the neat things about
- this scheme is that you will never get called nor will any segment ever
- be unloaded if you have enough memory available. You only start paying
- a performance penalty when you are nearly out of memory, which seems
- reasonable.
-
- Remember, if you use this, you probably never have to call
- UnloadSeg again. Just mark any segments that you want to allow to be
- purged as `purgeable'. You may want to keep certain frequently used
- segments resident (i.e., preload and not purgeable). You MUST NOT make
- the segment containing the grow zone function itself purgeable.
-
- Of course, if you can spot any problems with this, I'd be
- obliged if you'd let me know about them. I can come up with some
- scenarios that might cause this to fail but they seem rather unlikely.
- In particular I can't find it documented anywhere whether I can
- actually count on A5 being valid in the gzProc. I suppose that comes
- down to not making any Memory Manager calls without A5 being valid,
- but I don't think that's legal, so it looks like I'm safe.
-
- All I can say is that I and several beta testers have been
- using this code in an application of mine for several months now
- without any apparent problems. Use at your own risk, &c. &c.
-
- Enjoy!
-
- P.S.: View this code with an 8-character tab width. Some of the lines
- are longer than 80 characters, but I've let them wrap instead
- of inserting line breaks or `fmt'ing the code
-
- ----- begins
-
-
- class TApplication {
- protected:
- static pascal long GrowZone(Size cbNeeded); // grow zone function
- struct AddressRange { void *start, *end; }; // location of CODE in memory
- short fNumCODEResources; // number of CODE resources
- AddressRange *fCODEAddresses; // CODE addresses
-
- public:
- static TApplication *gApplication; // last instantiated application
- };
-
-
-
- /* TApplication
- Application constructor
- */
- #pragma segment Initialization
- TApplication::TApplication()
- {
- fCODEAddresses = NULL;
-
- // etc.
- ...
-
- // install grow zone function
- fNumCODEResources = Count1Resources('CODE');
- fCODEAddresses = (AddressRange*) NewPtr(fNumCODEResources * sizeof(AddressRange)); mfault;
- if (fCODEAddresses)
- SetGrowZone(&TApplication::GrowZone);
-
- // leave a pointer for anyone to find me
- gApplication = this;
- }
-
-
- /* ~TApplication
- */
- #pragma segment Termination
- TApplication::~TApplication()
- {
- if (fCODEAddresses) DisposPtr((Ptr) fCODEAddresses);
- }
-
-
- /* CurrentA5
- Returns the current value of A5
- */
- #pragma parameter __D0 CurrentA5
- void *CurrentA5() = 0x200d; // MOVE.L A5,D0
-
-
- /* CurrentA7
- Returns the current value of A7
- */
- #pragma parameter __D0 CurrentA7
- void *CurrentA7() = 0x200f; // MOVE.L A7,D0
-
-
- /* GrowZone
- Grow zone function
- */
- #pragma segment Main
- pascal long TApplication::GrowZone(
- Size cbNeeded // bytes needed
- )
- {
- (void) cbNeeded; // not used
- long unloadedSome = 0;
-
- register AddressRange *codeAddress;
- register short i;
-
- void *mask = StripAddress((Ptr) 0xffffffff);
-
- // find all purgeable but locked CODE resources in memory
- register short numCODEResources = gApplication->fNumCODEResources;
- char saveResLoad = *(char*) 0x0a5e; // from SysEqu.h
- SetResLoad(false);
-
- for (i = 1, codeAddress = gApplication->fCODEAddresses; i <= numCODEResources; i++, codeAddress++) {
- codeAddress->start = NULL;
-
- // is the resource in memory?
- Handle codeH = Get1IndResource('CODE', i);
- if (codeH && *codeH)
- // is it a purgeable but locked resource?
- if ((HGetState(codeH) & 0xe0) == 0xe0) {
- // how big is it?
- Size codeSize = GetHandleSize(codeH);
- if (codeSize > 0) {
- // record the address range so it is eligible for purging
- codeAddress->start = (void*) ((long) *codeH & (long) mask);
- codeAddress->end = (char*) codeAddress->start + codeSize;
- }
- }
- }
-
- if (saveResLoad) SetResLoad(true);
-
- // examine the stack
- Zone &applZone = *ApplicZone();
- enum { CurStackBase = 0x0908 };
- void
- *stackTop = CurrentA7(), // stack to search
- *stackBase = *((void**) CurStackBase),
- *heapStart = &applZone.heapData, // application zone data
- *heapEnd = applZone.bkLim;
-
- // search the stack for references to loaded segments
- enum { CurJTOffset = 0x0934 };
- for (register char *a7 = (char*) stackTop; a7 < stackBase; a7 += 2) {
- // is the address on the stack within the application heap?
- register void *stackData = (void*) (*(long*) a7 & (long) mask);
- if (stackData >= heapStart && stackData < heapEnd)
- // is it in any of the code segments?
- for (i = 1, codeAddress = gApplication->fCODEAddresses; i < numCODEResources; i++, codeAddress++)
- if (codeAddress->start && stackData >= codeAddress->start && stackData < codeAddress->end) {
- // exclude it from unloading
- codeAddress->start = NULL;
- break;
- }
- }
-
- // unload everything that wasn't referenced inside the stack
- for (i = 1, codeAddress = gApplication->fCODEAddresses; i < numCODEResources; i++, codeAddress++)
- // may we unload it?
- if (codeAddress->start) {
- // ready to get it on!
- UnloadSeg((char*) CurrentA5() +
- (*(short*) CurJTOffset) + // beginning of jump table
- (*(short*) codeAddress->start) + // segment's first entry in jump table
- 2 // routine address
- );
- unloadedSome++;
- }
-
- return unloadedSome;
- }
-
- ----- ends
- --
- Ben `Hackster' Hekster | "He bides his time and thinks,
- heksterb@cs.utwente.nl | 'There must be more to life than this!'"
-