home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #18 / NN_1992_18.iso / spool / comp / sys / mac / programm / 14142 < prev    next >
Encoding:
Text File  |  1992-08-18  |  6.6 KB  |  210 lines

  1. Newsgroups: comp.sys.mac.programmer
  2. Path: sparky!uunet!mcsun!sun4nl!utrcu1!infnews!heksterb
  3. From: heksterb@cs.utwente.nl (Ben Hekster)
  4. Subject: Re: Porting code using fork() to the Mac
  5. Message-ID: <1992Aug18.113422.28901@cs.utwente.nl>
  6. Summary: CODE segment-unloading grow zone function
  7. Sender: usenet@cs.utwente.nl
  8. Nntp-Posting-Host: utis96
  9. Organization: University of Twente, Dept. of Computer Science
  10. References: <1992Aug16.083656.22198@cs.utwente.nl>
  11. Date: Tue, 18 Aug 1992 11:34:22 GMT
  12. Lines: 196
  13.  
  14.  
  15. Hi--
  16.  
  17. I had a couple of requests to post my CODE segment-unloading grow zone
  18. function, so here it is.
  19.  
  20.     As you can see, it's actually written in C++ (the Language of
  21. the Gods), not in Assembly.  I've taken this code out of my class
  22. library and extracted just (hopefully) all the relevant bits.  The
  23. conversion to C shouldn't be much of a problem.  Though I suppose some
  24. people may find it rather sparsely commented, that's the way I like
  25. it.  I prefer to think that it's self-documenting...
  26.  
  27.     I wouldn't necessarily mind rewriting it in 68000 if I thought
  28. it was worth it.  I haven't done any profiling on this code, so I'm not
  29. yet convinced that it would be, though I can see some nested loops in
  30. there and some possible `optimizations'.
  31.  
  32.     The reason why this doesn't really bother me is that the grow
  33. zone function doesn't get called often, and only when you are operating
  34. close to the limit of available memory.  One of the neat things about
  35. this scheme is that you will never get called nor will any segment ever
  36. be unloaded if you have enough memory available.  You only start paying
  37. a performance penalty when you are nearly out of memory, which seems
  38. reasonable.
  39.  
  40.     Remember, if you use this, you probably never have to call
  41. UnloadSeg again.  Just mark any segments that you want to allow to be
  42. purged as `purgeable'.  You may want to keep certain frequently used
  43. segments resident (i.e., preload and not purgeable).  You MUST NOT make
  44. the segment containing the grow zone function itself purgeable.
  45.  
  46.     Of course, if you can spot any problems with this, I'd be
  47. obliged if you'd let me know about them.  I can come up with some
  48. scenarios that might cause this to fail but they seem rather unlikely.
  49. In particular I can't find it documented anywhere whether I can
  50. actually count on A5 being valid in the gzProc.  I suppose that comes
  51. down to not making any Memory Manager calls without A5 being valid,
  52. but I don't think that's legal, so it looks like I'm safe.
  53.  
  54.     All I can say is that I and several beta testers have been
  55. using this code in an application of mine for several months now
  56. without any apparent problems.  Use at your own risk, &c. &c.
  57.  
  58. Enjoy!
  59.  
  60. P.S.:    View this code with an 8-character tab width.  Some of the lines
  61.     are longer than 80 characters, but I've let them wrap instead
  62.     of inserting line breaks or `fmt'ing the code
  63.  
  64. ----- begins
  65.  
  66.  
  67. class TApplication {
  68. protected:
  69.     static pascal long GrowZone(Size cbNeeded);        // grow zone function
  70.     struct AddressRange { void *start, *end; };        // location of CODE in memory
  71.     short        fNumCODEResources;            // number of CODE resources
  72.     AddressRange    *fCODEAddresses;            // CODE addresses
  73.  
  74. public:
  75.     static TApplication *gApplication;            // last instantiated application
  76.     };
  77.  
  78.  
  79.  
  80. /*    TApplication
  81.     Application constructor
  82. */
  83. #pragma segment Initialization
  84. TApplication::TApplication()
  85. {
  86. fCODEAddresses = NULL;
  87.  
  88. // etc.
  89. ...
  90.  
  91. // install grow zone function
  92. fNumCODEResources = Count1Resources('CODE');
  93. fCODEAddresses = (AddressRange*) NewPtr(fNumCODEResources * sizeof(AddressRange)); mfault;
  94. if (fCODEAddresses)
  95.     SetGrowZone(&TApplication::GrowZone);
  96.  
  97. // leave a pointer for anyone to find me
  98. gApplication = this;
  99. }
  100.  
  101.  
  102. /*    ~TApplication
  103. */
  104. #pragma segment Termination
  105. TApplication::~TApplication()
  106. {
  107. if (fCODEAddresses) DisposPtr((Ptr) fCODEAddresses);
  108. }
  109.  
  110.  
  111. /*    CurrentA5
  112.     Returns the current value of A5
  113. */
  114. #pragma parameter __D0 CurrentA5
  115. void *CurrentA5() = 0x200d;                    // MOVE.L A5,D0
  116.  
  117.  
  118. /*    CurrentA7
  119.     Returns the current value of A7
  120. */
  121. #pragma parameter __D0 CurrentA7
  122. void *CurrentA7() = 0x200f;                    // MOVE.L A7,D0
  123.  
  124.  
  125. /*    GrowZone
  126.     Grow zone function
  127. */
  128. #pragma segment Main
  129. pascal long TApplication::GrowZone(
  130.     Size        cbNeeded                // bytes needed
  131.     )
  132. {
  133. (void) cbNeeded;                        // not used
  134. long unloadedSome = 0;
  135.  
  136. register AddressRange *codeAddress;
  137. register short i;
  138.  
  139. void *mask = StripAddress((Ptr) 0xffffffff);
  140.  
  141. // find all purgeable but locked CODE resources in memory
  142. register short numCODEResources = gApplication->fNumCODEResources;
  143. char saveResLoad = *(char*) 0x0a5e;                // from SysEqu.h
  144. SetResLoad(false);
  145.  
  146. for (i = 1, codeAddress = gApplication->fCODEAddresses; i <= numCODEResources; i++, codeAddress++) {
  147.     codeAddress->start = NULL;
  148.  
  149.     // is the resource in memory?
  150.     Handle codeH = Get1IndResource('CODE', i);
  151.     if (codeH && *codeH)
  152.         // is it a purgeable but locked resource?
  153.         if ((HGetState(codeH) & 0xe0) == 0xe0) {
  154.             // how big is it?
  155.             Size codeSize = GetHandleSize(codeH);
  156.             if (codeSize > 0) {
  157.                 // record the address range so it is eligible for purging
  158.                 codeAddress->start = (void*) ((long) *codeH & (long) mask);
  159.                 codeAddress->end = (char*) codeAddress->start + codeSize;
  160.                 }
  161.             }
  162.     }
  163.  
  164. if (saveResLoad) SetResLoad(true);
  165.  
  166. // examine the stack
  167. Zone &applZone = *ApplicZone();
  168. enum { CurStackBase = 0x0908 };
  169. void
  170.     *stackTop = CurrentA7(),                // stack to search
  171.     *stackBase = *((void**) CurStackBase),
  172.     *heapStart = &applZone.heapData,            // application zone data
  173.     *heapEnd = applZone.bkLim;
  174.  
  175. // search the stack for references to loaded segments
  176. enum { CurJTOffset = 0x0934 };
  177. for (register char *a7 = (char*) stackTop; a7 < stackBase; a7 += 2) {
  178.     // is the address on the stack within the application heap?
  179.     register void *stackData = (void*) (*(long*) a7 & (long) mask);
  180.     if (stackData >= heapStart && stackData < heapEnd)
  181.         // is it in any of the code segments?
  182.         for (i = 1, codeAddress = gApplication->fCODEAddresses; i < numCODEResources; i++, codeAddress++)
  183.             if (codeAddress->start && stackData >= codeAddress->start && stackData < codeAddress->end) {
  184.                 // exclude it from unloading
  185.                 codeAddress->start = NULL;
  186.                 break;
  187.                 }
  188.     }
  189.  
  190. // unload everything that wasn't referenced inside the stack
  191. for (i = 1, codeAddress = gApplication->fCODEAddresses; i < numCODEResources; i++, codeAddress++)
  192.     // may we unload it?
  193.     if (codeAddress->start) {
  194.         // ready to get it on!
  195.         UnloadSeg((char*) CurrentA5() +
  196.             (*(short*) CurJTOffset) +        // beginning of jump table
  197.             (*(short*) codeAddress->start) +    // segment's first entry in jump table
  198.             2                    // routine address
  199.             );
  200.         unloadedSome++;
  201.         }
  202.  
  203. return unloadedSome;
  204. }
  205.  
  206. ----- ends
  207. -- 
  208. Ben `Hackster' Hekster        | "He bides his time and thinks,
  209. heksterb@cs.utwente.nl        |  'There must be more to life than this!'"
  210.