home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-01-07 | 41.3 KB | 1,714 lines | [TEXT/MPS ] |
- /*$P*/
- /*[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]*/
- /* UMemory.inc1.p */
- /* Copyright © 1985-1990 by Apple Computer, Inc. All rights reserved. */
- #ifndef __UMEMEORY__
- #include "UMemory.h"
- #endif
-
- #ifndef __UFAILURE__
- #include "UFailure.h"
- #endif
-
- #ifndef __MEMORY__
- #include "Memory.h"
- #endif
-
- #ifndef __TEXTEDIT__
- #include "Textedit.h"
- #endif
-
- #ifndef __OSUTILS__
- #include "OSUtils.h"
- #endif
-
- #ifndef __UMACAPPUTILITIES__
- #include "UMacAppUtilities.h"
- #endif
-
- #ifndef __SYSEQU__
- #include "SysEqu.h"
- #endif
-
- #ifndef __TRAPS__
- #include "Traps.h"
- #endif
-
- #ifndef __DEVICES__
- #include "Devices.h"
- #endif
-
- #ifndef __ULOMEM__
- #include "ULoMem.h"
- #endif
-
- #ifndef __TOOLUTILS__
- #include "ToolUtils.h"
- #endif
-
- #ifndef __RESOURCES__
- #include "Resources.h"
- #endif
-
- #ifndef __PACKAGES__
- #include "Packages.h"
- #endif
-
- #ifndef __ERRORS__
- #include "Errors.h"
- #endif
-
- #ifndef __UDEBUG__
- #include "UDebug.h"
- #endif
-
- #ifndef __SEGLOAD__
- #include "SegLoad.h"
- #endif
-
- #if !qDebugTheDebugger
- #pragma W+
- #pragma R-
- #pragma Init-
- #pragma OV-
- #endif
-
- // Globals to this module and externally available.
- extern Size gMaxLockedRsrc;
- #if qDebug
- extern Boolean gMemMgtBreak = false;
- extern Boolean gRsrcReport = false;
- extern Boolean gSegReport = false;
- #endif
-
- HandleListHandle gSysMemList;
- HandleListHandle gApp1MemList;
- HandleListHandle gApp2MemList;
- HandleListHandle gCodeSegs;
- BoolListHandle gIsLoadedSeg;
- BoolListHandle gIsResidentSeg;
- short gCodeRefNum;
- Boolean gUnloadAllSegs;
- ProcPtr gGZPurgeNotify;
-
- // Static, globals to this module. Many of these are static by convention, but we don't
- // declare them as static because people may want to examine them.
-
- static Boolean pDuringGrowZone;
- Size pSzCodeReserve;
- Boolean pReserveExists;
- Handle pMemReserve;
- Handle pCodeReserve;
- Boolean pOKCodeReserve;
- Boolean pPermAllocation;
- short pMaxSegNum;
- Size pSzMemReserve;
- short pOldResFile;
- Boolean pLoadSegCalledFromOwnApp;
- TrapPatch pSegLoadPatch;
- LongListHandle pSegSize;
-
- // Function prototypes for some routines in this module.
-
- pascal long GrowZoneProc (Size needed);
- pascal void BuildCodeReserve (Size allocLim, Boolean fromGZ);
- pascal Boolean IsHandleEligible (Handle h);
-
- // Function prototypes for the routines in UMemory.a
-
- pascal void ALoadMacAppSeg (void);
- pascal void APostLoadMacAppSeg (void);
-
- /* LoadSeg is Patched to call ALoadMacAppSeg, which in turn calls
- LoadMacAppSegment. ALoadMacAppSeg can only be referenced as a
- procedure pointer, because no args are declared */
-
- // Other function prototypes that are externally defined.
-
- typedef pascal void (*DoToFrameType) (long, long, long, long, void*);
-
- pascal void EachFrameDo (long calleeFrame, long ppc,
- pascal void DoToFrame (long calleeFrame,
- long ppc,
- long callerFrame,
- long itsFrame,
- void* scopeLink),
- void *scopeLink);
-
- pascal Boolean PreloadSegment (short segNum);
-
- pascal void CallNotify (Handle h, ProcPtr routine) = { 0x205F, 0x4E90 }; // MOVE.L (A7)+,A0; JSR (A0)
-
- /*--------------------------------------------------------------------------------------------------*/
-
- /*
- These "MAFoo" functions are primarily for THINK™ Pascal compatibility (but useful in the larger
- problem of multiple open resource maps in general); when running under the THINK™ environment,
- CODE resources are not found in the same resource file as other application resources, so a
- UseResFile call needs to be made to bring the project resource file into the search path.
- "gCodeRefNum" is set up at initialization time.
- !!! A much more general solution to "the resource problem" appears to be warranted.
- */
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
-
- pascal Handle MAGet1Resource (ResType rType, short rID)
- {
- short oldResFile;
- Handle resource;
-
- oldResFile = MAUseResFile (gCodeRefNum);
- resource = Get1Resource (rType, rID);
- MAUseResFile (oldResFile);
-
- return resource;
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
-
- pascal Handle MAGet1NamedResource (ResType rType, const Str255& name)
- {
- short oldResFile;
- Handle namedResource;
-
- oldResFile = MAUseResFile (gCodeRefNum);
- namedResource = Get1NamedResource (rType, name);
- MAUseResFile (oldResFile);
-
- return namedResource;
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
-
- pascal Handle MAGet1IndResource (ResType rType, short index)
- {
- short oldResFile;
- Handle indResource;
-
- oldResFile = MAUseResFile (gCodeRefNum);
- indResource = Get1IndResource (rType, index);
- MAUseResFile (oldResFile);
-
- return indResource;
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
-
- pascal short MACount1Resources (ResType rType)
- {
- short oldResFile;
- short resourceCnt;
-
- oldResFile = MAUseResFile (gCodeRefNum);
- resourceCnt = Count1Resources (rType);
- MAUseResFile (oldResFile);
-
- return resourceCnt;
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
-
- pascal Handle MAGetResource (ResType rType, short rID)
- {
- Handle h;
- short oldResFile;
-
- oldResFile = MAUseResFile (gCodeRefNum);
- h = GetResource (rType, rID);
- MAUseResFile (oldResFile);
-
- return HomeResFile (h) != gCodeRefNum ? NULL : h;
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
-
- pascal Handle MAGetNamedResource (ResType rType, const Str255& name)
- {
- Handle h;
- short oldResFile;
-
- oldResFile = MAUseResFile (gCodeRefNum);
- h = GetNamedResource (rType, name);
- MAUseResFile (oldResFile);
-
- return HomeResFile (h) != gCodeRefNum ? NULL : h;
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
-
- pascal Handle MAGetIndResource(ResType rType, short index)
- {
- Handle h;
- short oldResFile;
-
- oldResFile = MAUseResFile (gCodeRefNum);
- h = GetIndResource (rType, index);
- MAUseResFile (oldResFile);
-
- return HomeResFile (h) != gCodeRefNum ? NULL : h;
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
-
- pascal short MACountResources(ResType rType)
- {
- short oldResFile;
- short resourceCnt;
-
- oldResFile = MAUseResFile (gCodeRefNum);
- resourceCnt = CountResources (rType);
- MAUseResFile (oldResFile);
-
- return resourceCnt;
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
-
- pascal Handle GetSegResource (short segNum)
- {
- return MAGet1Resource (kCode, segNum);
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMiniInit
-
- pascal void AddAllRsrc (ResType rType, HandleListHandle toList)
- {
- Boolean oldResLoad;
- short i, nResources, theID;
- Handle h;
- ResType theType;
- Str255 theName;
-
- oldResLoad = GetResLoad ();
- SetResLoad (false);
-
- nResources = CountResources (rType);
- for (i=1; i<=nResources; i++)
- {
- h = GetIndResource (rType, i);
- GetResInfo (h, theID, theType, theName);
-
- /* If there is a ROM resource for this type and ID, don't put it
- on the list. */
-
- UseROMMap (false);
- h = GetResource (rType, theID);
- UseROMMap (false);
- if (HomeResFile (h) != 1)
- AddHandle (h, toList);
- }
-
- SetResLoad (oldResLoad);
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMiniInit
-
- pascal void AddHandle(Handle h, HandleListHandle toList)
- {
- long offset;
-
- offset = Munger ((Handle) toList, 0, NULL, 0, (Ptr) &h, 4);
- FailMemError ();
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMiniInit
-
- pascal long AddSegSizes (Handle segRsrc)
- {
- SignedByte savedState;
- SignedBytePtr p;
- Boolean oldResLoad;
- long total;
- Handle seg;
- short i;
- Str255 s;
-
- savedState = LockHandleHigh (segRsrc);
-
- oldResLoad = GetResLoad ();
- SetResLoad (false);
-
- p = (SignedBytePtr) *segRsrc;
- i = *((IntegerPtr) p);
- p += 2;
-
- total = 0;
-
- for (; i>0; i--, p+=*p+1)
- {
- BlockMove ((Ptr) p, (Ptr) &s, *p + 1);
- seg = MAGet1NamedResource (kCode, s);
- if (seg != NULL)
- total += SizeResource (seg) + 8;
- }
-
- SetResLoad (oldResLoad);
- HSetState (segRsrc, savedState);
-
- return total;
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
- #pragma Push
- #if qTrace
- #pragma D+
- #endif
-
- pascal void BuildAllReserves ()
-
- {
- static const short initVal = 0xF7;
-
- Boolean oldPerm;
- #if qDebug
- Size theSize;
- #endif
-
- /* set the permanent flag to ensure that the code reserve is
- actually allocated and not given up to the low space reserve */
-
- oldPerm = pPermAllocation;
- pPermAllocation = true;
-
- BuildCodeReserve (kGZMaxAlloc, false); // make sure code reserve is OK
-
- // reallocate the low space handle, if necessary
-
- if (IsHandlePurged (pMemReserve))
- {
- ReallocHandle (pMemReserve, pSzMemReserve);
- #if qDebug
- theSize = GetHandleSize (pMemReserve);
- #pragma Push
- #pragma R-
- if (theSize != 0)
- BlockSet (*pMemReserve, theSize, initVal);
- #pragma Pop
- #endif
- }
-
- pPermAllocation = oldPerm; // reset the permanent flag
- }
- #pragma Pop
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
- #pragma Push
- #if qTrace
- #pragma D+
- #endif
-
- pascal void BuildCodeReserve(Size allocLim, Boolean fromGZ)
- {
- static const short initVal = 0xF7;
-
- Size needed, avail;
- Handle canPurge = 0;
- #if qDebug
- Size theSize;
- #endif
-
- pOKCodeReserve = true; // default value
-
- #if qDebug
- pReserveShortfall = 0;
-
- if (!pPermAllocation)
- ProgramBreak ("BuildCodeReserve called with pPermAllocation = FALSE");
- #endif
-
- if (!pReserveExists)
- {
- pReserveExists = true; // default value
-
- // free the current code reserve
- if (IsHandleEligible (pCodeReserve))
- EmptyHandle (pCodeReserve);
-
- // compute amt actually needed
- needed = Min (pSzCodeReserve - TotalTempSize (FALSE, canPurge) - 8, allocLim);
-
- if (needed > 0)
- {
- // make as much memory available as possible
- if (IsHandleEligible (pMemReserve))
- EmptyHandle (pMemReserve);
-
- if (fromGZ) // Never purge or compact from GrowZone
- avail = allocLim;
- else
- {
- PurgeMem (needed);
- avail = CompactMem (needed);
- }
-
- if (avail < needed) // could not get the whole reserve
- {
- #if qDebug
- pReserveShortfall = needed - avail;
- #endif
- pOKCodeReserve = false;
- pReserveExists = false;
-
- needed = avail; // get the most we can
- }
-
- if (!fromGZ && (IsHandlePurged (pCodeReserve) || IsHandleEligible (pCodeReserve)))
- ReallocHandle (pCodeReserve, needed);
- #if qDebug
- theSize = GetHandleSize (pCodeReserve);
- #pragma Push
- #pragma R-
- if (theSize != 0)
- BlockSet (*pCodeReserve, theSize, initVal);
- #pragma Pop
- #endif
- if (!IsHandlePurged (pCodeReserve))
- {
- /* Large handles are almost as bad as nonrelocatable blocks.
- Try to get this guy out of the way, just in case.*/
-
- if (!fromGZ)
- MoveHHi (pCodeReserve);
- }
- }
- }
- }
- /*$Pop*/
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
-
- pascal Boolean CheckReserve ()
- {
- BuildAllReserves ();
- return pOKCodeReserve;
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #if qDebug
- #pragma segment MAMemoryRes
-
- pascal void CheckRsrcUsage ()
- {
- long sz;
- Handle h;
- Str255 s;
-
- sz = TotalTempSize (true, h);
- if (sz > gMaxLockedRsrc)
- {
- gMaxLockedRsrc = sz;
- if (gRsrcReport)
- {
- NumToString (gMaxLockedRsrc, s);
- s = " = New maximum resources usage: " + s + " =";
- ProgramReport (s, gMemMgtBreak);
- }
- }
- }
- #endif
-
- /*--------------------------------------------------------------------------------------------------*/
- #if qDebug
- #pragma segment MADebug
-
- pascal void DoChangeReserve (Boolean alter,
- Size& codeReserve, Size& codeShort, Size& lowSpaceReserve,
- Boolean& gotCode, Boolean& gotLowSpace)
- {
- long x;
- Str255 s;
-
- if (alter)
- {
- cout << "code reserve size = " << pSzCodeReserve << " ";
- if (pOKCodeReserve)
- cout << " (OK)\n";
- else
- cout << " (gone)\n";
-
- cout << "low space reserve size = " << pSzMemReserve << " ";
- if (!IsHandlePurged (pMemReserve))
- cout << " (OK)\n";
- else
- cout << " (gone)\n";
-
- cout << "\n";
-
- cout << "New code reserve (-1 == no change): ";
- cin >> x;
- if (x >= 0)
- codeReserve = x;
- else
- codeReserve = pSzCodeReserve;
-
- cout << "New low space reserve (-1 == no change): ";
- cin >> x;
- if (x >= 0)
- lowSpaceReserve = x;
- else
- lowSpaceReserve = pSzMemReserve;
-
- cout << "Reset max resource usage (Y or N) [N]? ";
- cin >> s;
- if (s != "")
- {
- if ((s[1] == 'y') || (s[1] == 'Y'))
- gMaxLockedRsrc = 0;
- }
-
- cout << "\n";
-
- SetReserveSize (codeReserve, lowSpaceReserve);
- }
- else
- BuildAllReserves ();
-
- codeReserve = pSzCodeReserve;
- codeShort = pReserveShortfall;
- lowSpaceReserve = pSzMemReserve;
- gotCode = pOKCodeReserve;
- gotLowSpace = !IsHandlePurged (pMemReserve);
- }
- #endif
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMiniInit
-
- /* Called from InitUMemory so that InitUMemory can be in the main segment
- and this code can be in another (unloadable) segment. */
-
- pascal void DoInitUMemory (Size& sizeTempReserve, Size sizeLowSpaceReserve)
- {
- struct Mem { long codeVal, lowSpaceVal, stackVal; };
- typedef Mem *MemPtr, **MemHandle;
-
- short i, rsrcCnt;
- Boolean oldResLoad;
- Handle seg, h;
- long StackTot;
- short rsrcID;
- ResType rsrcType;
- Str255 rsrcName;
- short lastRsrc;
- short mainSegment, utilitySegment;
-
- // Initialize memory management globals
-
- pPermAllocation = false;
- pMemReserve = NewHandle (0);
- FailNIL (pMemReserve);
-
- pSzMemReserve = 0;
- pCodeReserve = NewHandle (0);
- FailNIL (pCodeReserve);
-
- pSzCodeReserve = 0;
- gGZPurgeNotify = NULL;
- pOKCodeReserve = true;
- pReserveExists = false;
-
- gUnloadAllSegs = true;
-
- gCodeRefNum = HomeResFile (GetResource (kCode, 1)); /* Get homeresfile of "Main". It better be
- there!!*/
- pMaxSegNum = 0;
-
- //###########################################
- // No resource loading
-
- oldResLoad = GetResLoad ();
- SetResLoad (false);
-
- // Figure the highest segment number
- lastRsrc = MACount1Resources (kCode);
-
- /* some development systems may not have contiguous numbering of CODE segments.
- try to be polite about handling it */
-
- for (i=1; i<= lastRsrc; i++)
- {
- seg = MAGet1IndResource (kCode, i);
-
- /* we only have an index… find the real resource ID and keep track
- of the highest one */
-
- if (seg != NULL)
- {
- GetResInfo (seg, rsrcID, rsrcType, rsrcName);
- pMaxSegNum = (short) Max (rsrcID, pMaxSegNum);
- }
- }
-
- SetResLoad (oldResLoad); // in case of failure
-
- // Allocate the master segment lists.
- gCodeSegs = (HandleListHandle) NewHandle (pMaxSegNum * sizeof (Handle));
- FailNIL (gCodeSegs);
-
- gIsResidentSeg = (BoolListHandle) NewHandle (sizeof (Boolean) * pMaxSegNum);
- FailNIL (gIsResidentSeg);
-
- gIsLoadedSeg = (BoolListHandle) NewHandle (sizeof (Boolean) * pMaxSegNum);
- FailNIL (gIsLoadedSeg);
-
- /* (NOTE: assumes application doesn't change the CODE segment size at runtime
- (a very safe assumption)). Used in GetSegFromPC. */
-
- pSegSize = (LongListHandle) NewHandle (sizeof (long) * pMaxSegNum);
- FailNIL (pSegSize);
-
- oldResLoad = GetResLoad (); // OK, suppress segment loading again
- SetResLoad (false); /* !!! Need an MAResLoad that returns old
- state */
-
- // Initialize segment lists.
-
- for (i=1; i<=pMaxSegNum; i++)
- (*gIsResidentSeg)[i] = false;
-
- // Segments and their sizes and actual loaded state (helps catch preloads)
-
- for (i=1; i<=pMaxSegNum; i++)
- {
- seg = GetSegResource (i);
- (*gCodeSegs)[i] = seg;
- if (seg != NULL) // seg is non-nil if the segment number
- {
- (*pSegSize)[i] = SizeResource (seg);
- (*gIsLoadedSeg)[i] = IsHandleLocked (seg);
- }
- else
- {
- (*pSegSize)[i] = 0;
- (*gIsLoadedSeg)[i] = false;
- }
- }
-
- SetResLoad(oldResLoad);
- //###########################################
-
- mainSegment = GetSegNumber ((ProcPtr) &InitUMemory); // Main is always resident
- (*gIsResidentSeg)[mainSegment] = true;
- (*gIsLoadedSeg)[mainSegment] = true;
-
- utilitySegment = GetSegNumber ((ProcPtr) &UnloadAllSegments); // Utilities are always resident
- (*gIsResidentSeg)[utilitySegment] = true;
- (*gIsLoadedSeg)[utilitySegment] = true;
-
- // init the gSysMemList
-
- gSysMemList = HandleListHandle (NewHandle (0));
- FailNIL (gSysMemList);
-
- AddAllRsrc ('LDEF', gSysMemList);
- AddAllRsrc ('CDEF', gSysMemList);
- AddAllRsrc ('MDEF', gSysMemList);
- AddAllRsrc ('WDEF', gSysMemList);
- AddAllRsrc ('PACK', gSysMemList);
-
- // Compute memory slop needed
-
- sizeTempReserve = 0;
- sizeLowSpaceReserve = 0;
- StackTot = 0;
-
- rsrcCnt = CountResources ('seg!');
- for (i=1; i<rsrcCnt; i++)
- {
- h = GetIndResource ('seg!', i);
- sizeTempReserve += AddSegSizes (h);
- ReleaseResource (h);
- }
-
- rsrcCnt = CountResources ('mem!');
- for (i=1; i<rsrcCnt; i++)
- {
- h = GetIndResource ('mem!', i);
- {
- const Mem& memH = **((MemHandle) h);
-
- sizeTempReserve += memH.codeVal;
- sizeLowSpaceReserve += memH.lowSpaceVal;
- StackTot += memH.stackVal;
- }
- ReleaseResource (h);
- }
-
- SetStackSpace (StackTot);
-
- MaxApplZone ();
-
- gApp1MemList = NULL;
- gApp2MemList = NULL;
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
-
- pascal void FailNoReserve ()
- {
- if (!CheckReserve ())
- Failure (memFullErr, 0);
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
-
- pascal void FailSpaceIsLow ()
- {
- #if qDebug
- MAName s;
-
- if (gAskFailure && CanReadLn ())
- {
- GetCallersMethodName (s);
- if (ReadYesNo ("FailSpaceIsLow called by " + s + ". Return true(Y or N) [N]? "))
- Failure (memFullErr, 0);
- }
- #endif
-
- if (MemSpaceIsLow ())
- Failure (memFullErr, 0);
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma Push
- #if qTrace
- #pragma D+
- #endif
- #pragma segment MAMemoryRes
-
- pascal void GetReserveSize (Size& szCodeReserve, Size& szMemReserve)
- {
- szCodeReserve = pSzCodeReserve;
- szMemReserve = pSzMemReserve;
- }
- #pragma Pop
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma Push
- #if qTrace
- #pragma D+
- #endif
- /* no %_BP/%_EP allowed in here, because we
- cannot call to any other segment from this
- procedure */
- #pragma segment MAMemoryRes // Shouldn't be unloaded
-
- pascal short GetSegFromPC (long ppc)
- {
- long pc, segStart;
- short i;
- Handle seg;
-
- pc = *((LongIntPtr) ppc);
-
- /* Since GetSegFromPC may be called before gCodeSegs is set up, we have to test if gCodeSegs == NULL
- before using it. */
-
- if (gCodeSegs != NULL)
- for (i=1; i<=pMaxSegNum; i++)
- {
- seg = (*gCodeSegs)[i]; // get segment handle
- if ((seg != NULL) && !IsHandlePurged (seg)) // it's in memory
- {
- segStart = StripLong(*seg); // get segment start
- if ((pc >= segStart) && (pc < segStart + (*pSegSize)[i]))
- return i;
- }
- }
-
- return 0; // default return
- }
- #pragma Pop
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma Push
- #if qTrace
- #pragma D+
- #endif
- /* no %_BP/%_EP allowed in here, because we
- cannot call to any other segment from this
- procedure */
-
- #pragma segment MAMemoryRes /* must be in Main segment because we call
- this in order to make the resident segment
- resident */
-
- pascal short GetSegNumber (ProcPtr aProc)
- /* Gets seg number from a Jump table address */
- {
- static const short kLoaded = 0x4EF9; // if loaded then a JMP instruction
- static const short kUnLoaded = 0x3F3C; // if unloaded then a LoadSeg trap
-
- if (*((IntegerPtr) aProc) == kLoaded) // loaded segment
- return *((IntegerPtr) ((Ptr) aProc - 2));
- else if ((*IntegerPtr(aProc)) == kUnLoaded) // unloaded segment
- return *((IntegerPtr) ((Ptr) aProc + 2));
- else /* routine that computed &proc was in same
- segment as the proc */
- {
- #if qDebug
- ProgramBreak("GetSegNumber was not passed an jump table address");
- #endif
- return 0;
- }
- }
- #pragma Pop
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
- #pragma Push
- #if qTrace
- #pragma D+
- #endif
-
- pascal Size GetSegSize (short segNum)
- {
- return (*pSegSize)[segNum];
- }
- #pragma Pop
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
- #pragma Push
- #if qTrace
- #pragma D+
- #endif
-
- pascal long GrowZoneProc (Size)
- {
- long result, reserveSize, OldA5;
- Handle canPurge;
- Size codeSize;
-
- OldA5 = SetCurrentA5 (); // Can be called from other worlds
-
- result = 0; // default is to fail
-
- if (!pDuringGrowZone) // prevent re-entrancy
- {
- pDuringGrowZone = true;
-
- // on a temp alloc, free all code slack immediately
-
- if (!pPermAllocation && IsHandleEligible (pCodeReserve))
- {
- EmptyHandle (pCodeReserve);
- pReserveExists = false;
- result = 1;
- }
-
- if (result == 0) /* try harder: see if we can purge a code
- segment or reduce the code reserve handle
- */
- {
- // compute size of resources currently in memory
-
- codeSize = TotalTempSize (false, canPurge);
-
- // see if the code reserve handle is too large
-
- if (IsHandleEligible (pCodeReserve))
- /* we have a code reserve handle; this implies permanent allocation,
- otherwise the handle would have been emptied above */
- {
- reserveSize = GetHandleSize (pCodeReserve);
-
- /* the following test is an optimization to avoid calling
- BuildCodeReserve if there is no hope of reducing
- the code reserve handle */
-
- if (codeSize + reserveSize + 8 > pSzCodeReserve)
- { // reserve is too big
- pReserveExists = false;
- // this should lower the code reserve
- BuildCodeReserve (reserveSize, true);
-
- // see if we succeeded in freeing some memory
- if (IsHandlePurged (pCodeReserve))
- result = 1;
- else if (GetHandleSize (pCodeReserve) < reserveSize)
- result = 1;
- }
- }
-
- if ((result == 0) && (canPurge != NULL) && (!pPermAllocation ||
- IsHandlePurged (pCodeReserve))) /* got something; only purge it if this is
- temporary || we know there is too much
- code in memory already */
- {
- if (gGZPurgeNotify != NULL)
- CallNotify (canPurge, gGZPurgeNotify);
-
- reserveSize = GetHandleSize (canPurge);
- HPurge (canPurge);
- EmptyHandle (canPurge);
- pReserveExists = false;
-
- if (pPermAllocation) // don't free too much however
- BuildCodeReserve (reserveSize, true);
-
- result = 1;
- }
- }
-
- if ((result == 0) && IsHandleEligible (pMemReserve)) /* last ditch attempt-free emergency
- reserve*/
- {
- EmptyHandle (pMemReserve);
- result = 1;
- }
-
- pDuringGrowZone = false;
- }
-
- OldA5 = SetA5 (OldA5);
-
- return result;
- }
- #pragma Pop
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
- #pragma Push
- #if qTrace
- #pragma D+
- #endif
-
- pascal Boolean IsHandleEligible (Handle h)
- {
- if (h == NULL)
- return false; // Thanks Pillar!
- else if (IsHandlePurged (h))
- return false;
- else
- return (h != GetGZMoveHnd ()) && (h != GetGZRootHnd ());
- }
- #pragma Pop
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes /* Must be in same segment as grow zone proc */
- #pragma Push
- #if qTrace
- #pragma D+
- #endif
-
- pascal void InstallGrowZoneProc ()
- /* Once called the grow zone proc's segment CAN!be moved since we're passing a NON-JT address
- to SetGrowZone (so we can be called from "other worlds" */
- {
- THz aZone;
-
- pDuringGrowZone = false;
- aZone = ApplicZone ();
- aZone->flags |= 0x0400;
-
- /* set the Memory Manager bit that says to always call the
- Grow Zone proc, even in "non-critical" situations */
-
- SetGrowZone (&GrowZoneProc);
- }
- #pragma Pop
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment Main /* Must be in main segment and called from main segment */
-
- pascal void InitUMemory ()
- {
-
- Size codeRes, lowSpaceRes = 0;
- Handle miniInitSeg;
-
- /* Get these segments out of the way so that when DoInitUMemory gets called and the next
- block of master pointers gets allocated they won't constipate the heap */
-
- miniInitSeg = GetResource (kCode, GetSegNumber ((ProcPtr) &DoInitUMemory));
- if (miniInitSeg != NULL)
- {
- UnloadSeg (&DoInitUMemory);
- LockHandleHigh (miniInitSeg);
- }
-
- DoInitUMemory (codeRes, lowSpaceRes);
-
- UnloadAllSegments (); /* get init segment(s) out of middle of heap,
- so SetReserveSize has maximum space to
- work with */
-
- if (miniInitSeg != NULL) /* Yes, this would eventually get purged if
- the space was needed badly enough, but
- that happens very late in the game and can
- confound the unwary */
- EmptyHandle (miniInitSeg);
-
- InstallGrowZoneProc ();
-
- SetReserveSize (codeRes, lowSpaceRes);
- if (!pOKCodeReserve) /* couldn't get code reserve. Can't continue */
- Failure(memFullErr, 0);
- else
- {
- // Set up the LoadSeg patch
-
- //!!! needs fixing before final!!!
- if (!qModelFar)
- FailOSErr (PatchTrap (pSegLoadPatch, _LoadSeg, (Ptr) &ALoadMacAppSeg));
- }
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma Push
- #if qTrace
- #pragma D+
- #endif
- /* no %_BP/%_EP allowed in here, because we
- cannot call to any other segment from this
- procedure */
-
- #pragma segment MAMemoryRes // must be in Main segment
-
- pascal long LoadMacAppSegment (short segNum)
- {
- #if qDebug
- short id;
- ResType kind;
- Str255 segName;
- MAName s;
- Handle seg;
- #endif
- long A5RegisterOnEntry;
- long loadMacAppSegment;
-
- A5RegisterOnEntry = SetCurrentA5 (); // ***** Called from trap patches *****
-
- loadMacAppSegment = pSegLoadPatch.oldTrapAddr; // Where to go next
-
- if (GetA5 () != A5RegisterOnEntry)
- {
- // not called from our application… don't do patch behaviour. Thank you McSink!
- pLoadSegCalledFromOwnApp = false;
- if (SetA5 (A5RegisterOnEntry) != 0);
- }
- else
- {
- pLoadSegCalledFromOwnApp = true;
- pOldResFile = MAUseResFile (gCodeRefNum); /* Must set a global because we return from
- this function and then forward to the
- actual segment loader which should also be
- pointing to the _now_ correct resfile.
- When we get called back again in
- PostLoadMacAppSegment we will restore the
- old resFile as the current resFile. Sorry
- about the global. */
-
- #if qDebug
- if (!GetResLoad ())
- {
- SetResLoad (true);
- ProgramBreak ("Whoops… LoadSeg called with resload set false");
- Failure (minErr, 0); /*??? Assign an error code someday or
- setresload to true ???*/
- }
-
- #endif
-
- if (!PreloadSegmentResource(segNum))
- {
- #if qDebug
- GetCallersMethodName (s);
- SetResLoad (false);
- seg = MAGet1Resource (kCode, segNum);
-
- GetResInfo (seg, id, kind, segName);
- SetResLoad (true);
- ProgramBreak ("In " + s + form (" couldn''t load segment: %d", segNum) + segName);
- #endif
- Failure (memFullErr, 0);
- }
-
- (*gIsLoadedSeg)[segNum] = true;
-
- #if qDebug
- if (gSegReport)
- {
- // Cause the debugger to break at the start of the next routine.
- gReportNext = true;
- GetResInfo ((*gCodeSegs)[segNum], id, kind, segName);
- gReportInfo = form (" *** Segment Loaded: %d ", segNum) + segName;
- gSingleStep = gMemMgtBreak;
- }
- #endif
-
- }
-
- return loadMacAppSegment;
- }
- #pragma Pop
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma Push
- #if qTrace
- #pragma D+
- #endif
- /* no %_BP/%_EP allowed in here, because we
- cannot call to any other segment from this
- procedure */
- #pragma Z+
- #pragma segment MAMemoryRes // must be in Main segment
-
- pascal void PostLoadMacAppSegment ()
- {
- long A5RegisterOnEntry;
-
- A5RegisterOnEntry = SetCurrentA5 (); // ***** Called from trap patches *****
-
- if (GetA5 () != A5RegisterOnEntry || !pLoadSegCalledFromOwnApp)
- {
- // not called from our application… don't do patch behaviour. Thank you McSink!
- SetA5 (A5RegisterOnEntry);
- }
- else
- {
- // Called back from our glue. Restores current res file pointer.
- if (pLoadSegCalledFromOwnApp)
- MAUseResFile (pOldResFile);
- SetA5 (A5RegisterOnEntry);
- }
- }
- #pragma Pop
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes // Must be in Main segment
-
- pascal void LoadResidentSegments ()
- {
- short resIndex, i, offset, segNumber, rsrcCnt;
- Handle nameList, seg;
- SignedBytePtr p;
- Str255 name;
- ResType theType;
-
- rsrcCnt = CountResources('res!');
- for (resIndex=1; resIndex<=rsrcCnt; resIndex++)
- {
- nameList = GetIndResource ('res!', resIndex);
- HNoPurge (nameList);
-
- offset = 2;
- for (i=1; i<=*((IntegerPtr) *nameList); i++)
- {
- p = (SignedBytePtr) *nameList + offset;
- BlockMove ((Ptr) p, (Ptr) &name, *p + 1);
- offset += name.Length () + 1;
-
- seg = MAGet1NamedResource (kCode, name);
-
- if (seg != NULL)
- {
- GetResInfo (seg, segNumber, theType, name);
- SetResidentSegment (segNumber, true);
- }
- }
-
- HPurge (nameList);
- ReleaseResource (nameList);
- }
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
-
- pascal Boolean MemSpaceIsLow ()
- {
- BuildAllReserves ();
- return IsHandlePurged (pMemReserve);
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
-
- pascal Handle NewPermHandle (Size logicalSize)
- {
- static const short initVal = 0xF3; // odd at all byte boundaries
-
- Boolean priorPerm;
- Handle aHandle;
-
- priorPerm = PermAllocation (true);
- aHandle = NewHandle (logicalSize);
- pPermAllocation = priorPerm;
- FailNIL (aHandle);
- #pragma Push
- #pragma R-
- if (qDebug)
- BlockSet (*aHandle, logicalSize, initVal);
- #pragma Pop
- return aHandle;
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
-
- pascal Ptr NewPermPtr (Size logicalSize)
- {
- static const short initVal = 0xF3; // odd at all byte boundaries
-
- Boolean priorPerm;
- Ptr aPtr;
-
-
- priorPerm = PermAllocation (true);
- aPtr = NewPtr (logicalSize);
- pPermAllocation = priorPerm;
- FailNIL (aPtr);
- #pragma Push
- #pragma R-
- if (qDebug)
- BlockSet(aPtr, logicalSize, initVal);
- #pragma Pop
- return aPtr;
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma Push
- #if qTrace
- #pragma D+
- #endif
- #pragma segment MAMemoryRes
-
- pascal Boolean PermAllocation (Boolean permanent)
- {
- Boolean permAllocation = pPermAllocation;
-
- if (permanent != pPermAllocation)
- {
- pPermAllocation = permanent;
- if (permanent)
- BuildCodeReserve (kGZMaxAlloc, false);
- }
-
- return permAllocation;
- }
- #pragma Pop
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma Push
- #if qTrace
- #pragma D+
- #endif
- /* no %_BP/%_EP allowed in here, because we
- cannot call to any other segment from this
- procedure */
- #pragma segment MAMemoryRes // must be in Main segment
-
- class LWithCodeResFileDo {
- short& fSegNum;
- Handle& fSeg;
- public:
- LWithCodeResFileDo (short& segNum, Handle& seg) : fSegNum (segNum), fSeg (seg) { }
- pascal void DoGetSegHandle ()
- { fSeg = Get1Resource (kCode, fSegNum); }
- };
-
- pascal Boolean PreloadSegmentResource (short segNum)
- {
- Handle seg;
- LWithCodeResFileDo scopeLink (segNum, seg);
-
- if (qDebug && pPermAllocation)
- {
- cout << "segment # = " << segNum;
- ProgramBreak ("Trying to load a segment with PermAllocation == true.");
- }
-
- WithCodeResFileDo ((DoWithResFileType) &LWithCodeResFileDo::DoGetSegHandle, &scopeLink);
-
- if (seg == NULL)
- return false;
- else
- {
- if (!IsHandleLocked (seg)) // not yet locked
- LockHandleHigh (seg);
- return true;
- }
- }
- #pragma Pop
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
-
- pascal void RemHandle (Handle h, HandleListHandle toList)
- {
- long p, maxP, offset;
-
- p = (long) *toList; // Address of first element
- maxP = p + GetHandleSize ((Handle) toList); // Address past last element
-
- // Skip elements until item is found
- while ((p < maxP) && *((LongIntPtr) p) != (long) h)
- p += sizeof (Handle);
-
- if (p < maxP) // Item was found
- {
- offset = Munger ((Handle) toList, p - (long) *toList,
- NULL, sizeof (Handle), (Ptr) &h, 0);
- FailMemError ();
- }
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
- #pragma Push
- #if qTrace
- #pragma D+
- #endif
-
- typedef Handle *HandlePtr;
-
- pascal void ScanList (HandleListHandle list, DoToHandlesType DoToHandle, void *)
- {
- short i = (short) (GetHandleSize ((Handle) list) / sizeof (Handle));
- HandlePtr p = (HandlePtr) *list;
-
- for (; i>0; i--, p++)
- DoToHandle (*p, NULL);
- }
-
- pascal void ScanHandles (DoToHandlesType DoToHandle, void *)
- {
- ScanList (gCodeSegs, DoToHandle, NULL);
- if (gApp1MemList != NULL)
- ScanList (gApp1MemList, DoToHandle, NULL);
- ScanList (gSysMemList, DoToHandle, NULL);
- if (gApp2MemList != NULL)
- ScanList (gApp2MemList, DoToHandle, NULL);
- }
- #pragma Pop
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
-
- pascal void SetPermHandleSize (Handle h, Size newSize)
- {
- static const short initVal = 0xF3;
-
- Boolean priorPerm;
- #if qDebug
- Size oldSize;
- #endif
-
- priorPerm = PermAllocation (true);
- #if qDebug
- oldSize = GetHandleSize (h);
- #endif
- SetHandleSize (h, newSize);
- pPermAllocation = priorPerm; /* Since we are in the memory unit we can
- break the encapsulation of the
- PermAllocation Call to just set the
- pPermAllocation flag back directly. This
- lets us be assured that no operations have
- occurred that would invalidate the MemErr
- flag… thus the following call will give a
- true result*/
- FailMemError ();
- #if qDebug
- #pragma Push
- #pragma R-
- if (oldSize < newSize)
- BlockSet ((Ptr) *h + oldSize, newSize - oldSize, initVal);
- #pragma Pop
- #endif
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
-
- pascal void SetPermPtrSize (Ptr p, Size newSize)
- {
- static const short initVal = 0xF5;
-
- Boolean priorPerm;
- #if qDebug
- Size oldSize;
- #endif
-
- priorPerm = PermAllocation (true);
- #if qDebug
- oldSize = GetPtrSize (p);
- #endif
- SetPtrSize (p, newSize);
- pPermAllocation = priorPerm; /* Since we are in the memory unit we can
- break the encapsulation of the
- PermAllocation Call to just set the
- pPermAllocation flag back directly. This
- lets us be assured that no operations have
- occurred that would invalidate the MemErr
- flag… thus the following call will give a
- true result*/
- FailMemError ();
- #if qDebug
- #pragma Push
- #pragma R-
- if (oldSize < newSize)
- BlockSet ((Ptr) p + oldSize, newSize - oldSize, initVal);
- #pragma Pop
- #endif
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
-
- pascal void SetReserveSize (Size forCode, Size forOther)
- {
- pSzCodeReserve = forCode;
- pSzMemReserve = forOther;
-
- // Since the numbers have changed, make sure we start from scratch.
- pReserveExists = false;
- EmptyHandle (pMemReserve);
-
- BuildAllReserves ();
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma Push
- #if qTrace
- #pragma D+
- #endif
- /* no %_BP/%_EP allowed in here, because we
- cannot call to any other segment from this
- procedure */
- #pragma segment MAMemoryRes // must be in Main segment
-
- pascal void SetResidentSegment(short segNum, Boolean makeResident)
- {
- #if qDebug
- short id;
- ResType kind;
- Str255 segName;
- MAName s;
- Handle seg;
- #endif
-
- //!!! needs fixing before final!!!
- if (qModelFar)
- return;
-
- if (makeResident)
- {
- (*gIsResidentSeg)[segNum] = true;
- if (!PreloadSegment (segNum))
- {
- #if qDebug
- GetCallersMethodName (s);
- SetResLoad (false);
- seg = MAGet1Resource (kCode, segNum);
- SetResLoad (true);
- GetResInfo (seg, id, kind, segName);
- ProgramBreak ("In " + s + form (" couldn''t load segment: %d", segNum) + segName);
- #endif
- Failure (memFullErr, 0);
- }
- }
- else
- (*gIsResidentSeg)[segNum] = false;
- }
- #pragma Pop
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMiniInit
-
- pascal void SetStackSpace (long numBytes)
- {
- long newLimit;
-
- newLimit = (long) GetCurStackBase () - numBytes;
- if ((long) GetApplLimit () > newLimit)
- SetApplLimit ((Ptr) newLimit);
- }
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
- #pragma Push
- #if qTrace
- #pragma D+
- #endif
-
- class LTotalTempSize {
- Boolean& fJustLocked;
- Handle& fCanPurge;
- Size& fTotal;
- THz& fApplZone;
- public:
- LTotalTempSize (Boolean& justLocked, Handle& canPurge, Size& total, THz& applZone)
- : fJustLocked (justLocked), fCanPurge (canPurge), fTotal (total), fApplZone (applZone) { }
-
- pascal void TotalUp(Handle h)
- {
- Boolean hIsLocked;
-
- if (!IsHandlePurged (h)) // in memory already
- if (HandleZone (h) == fApplZone) // in application heap
- {
- HNoPurge (h);
-
- hIsLocked = IsHandleLocked (h);
-
- if (!fJustLocked || hIsLocked)
- fTotal += GetHandleSize (h) + 8;
- // add in the size plus heap overhead
-
- if (!hIsLocked)
- if (fCanPurge == NULL)
- if (IsHandleEligible (h))
- fCanPurge = h;
- }
- }
- };
-
- pascal Size TotalTempSize (Boolean justLocked, Handle& canPurge)
- {
- Size total;
- THz applZone;
- LTotalTempSize scopeLink (justLocked, canPurge, total, applZone);
-
- canPurge = NULL;
- total = 0;
- applZone = ApplicZone ();
-
- ScanHandles ((DoToHandlesType) <otalTempSize::TotalUp, &scopeLink);
-
- return total;
- }
- #pragma Pop
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma segment MAMemoryRes
- #pragma Push
- #if qTrace
- #pragma D+
- #endif
-
- pascal void WithCodeResFileDo (pascal void (*DoWithResFile) (void* scopeLink), void* scopeLink)
- {
- short oldResFile;
-
- oldResFile = MAUseResFile (gCodeRefNum);
- DoWithResFile (scopeLink);
- MAUseResFile (oldResFile);
- }
- #pragma Pop
-
- /*--------------------------------------------------------------------------------------------------*/
- #pragma Push
- #if qTrace
- #pragma D+
- #endif
- /* no %_BP/%_EP allowed in here, because we
- cannot call to any other segment from this
- procedure */
- #pragma segment MAMemoryRes // must be in Main segment
-
- class LUnloadAllSegments {
- Handle& seg;
- long& jmpTablePtr;
- public:
- LUnloadAllSegments (Handle& aSeg, long& aJmpTablePtr)
- : seg (aSeg), jmpTablePtr (aJmpTablePtr) { }
-
- pascal void DoToFrame (long, long ppc,
- long, long)
- {
- short seg;
-
- seg = GetSegFromPC (ppc);
- if ((seg != 0) && !((*gIsResidentSeg)[seg] && (*gIsLoadedSeg)[seg]))
- {
- cout << "Segment#: " << seg;
- ProgramBreak("I really don''t think that you want to unload a segment into which you are going to return!");
- }
- }
-
- pascal void UnloadEm ()
- {
- short i;
-
- for (i=1; i<=pMaxSegNum; i++)
- {
- if (!(*gIsResidentSeg)[i] && (*gIsLoadedSeg)[i])
- {
- seg = (*gCodeSegs)[i];
- if ((seg != NULL) && !IsHandlePurged (seg))
- {
- UnloadSeg ((Ptr) jmpTablePtr + **((IntegerHandle) seg) + 2);
- (*gIsLoadedSeg)[i] = false;
- }
- }
- }
- }
- };
-
- pascal void UnloadAllSegments (void)
- {
- long jumpTablePtr;
- Handle seg;
-
- //!!! needs fixing before final!!!
- if (qModelFar)
- return;
-
- #if qDebug
- CheckRsrcUsage ();
- #endif
-
- if (gUnloadAllSegs)
- {
- jumpTablePtr = (long ) GetA5 () + GetCurJTOffset ();
-
- LUnloadAllSegments localScope (seg, jumpTablePtr);
- #if qDebug
- EachFrameDo ((long) GetCurStackFramePtr (),
- (long) GetCurStackFramePtr () + 4,
- (DoToFrameType) &LUnloadAllSegments::DoToFrame, &localScope);
- #endif
-
- WithCodeResFileDo ((DoWithResFileType) &LUnloadAllSegments::UnloadEm, &localScope);
-
- if (gSegReport)
- ProgramReport (" *** Just unloaded all segments ***", gMemMgtBreak);
- }
- }
- #pragma Pop
-
- /*--------------------------------------------------------------------------------------------------*/
- #if qDebug
- #pragma segment MADebug
-
- pascal void WriteReserves ()
- /* WRITELN's the temporary reserve and low-memory reserves in the
- debug window. */
-
- {
- WrLblPtr ("Temporary reserve (pCodeReserve)", (long) pCodeReserve);
- cout << "\n";
- WrLblPtr ("Low-memory reserve (pMemReserve)", (long) pMemReserve);
- cout << "\n";
- }
- #endif
-