mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-28 16:31:01 +00:00
614 lines
19 KiB
C
614 lines
19 KiB
C
|
/*
|
|||
|
File: MemoryMgr24Patches.c
|
|||
|
|
|||
|
Contains: Process Mgr heap routines that manipulate data blocks according to the
|
|||
|
24-bit memory manager structures. MemoryMgr24Patches.c and
|
|||
|
MemoryMgr32Patches.c are virtually identical in source code. The header
|
|||
|
files each uses, though, determines the how the block header access
|
|||
|
macros are expanded. This (hopefully) makes it easier to maintain given
|
|||
|
the 24/32 duality imposed on us.
|
|||
|
|
|||
|
Written by: Phil Goldman
|
|||
|
|
|||
|
Copyright: <EFBFBD> 1986-1992 by Apple Computer, Inc., all rights reserved.
|
|||
|
|
|||
|
Change History (most recent first):
|
|||
|
|
|||
|
<11> 6/22/92 DTY #1033275 <csd>: Remove last change. The quad alignment is now
|
|||
|
done inside NewHiProcessManagerHandle or whatever it<EFBFBD>s called
|
|||
|
inside MemoryMgrPatches.c.
|
|||
|
<10> 6/12/92 pvh #1032359: Added quad word alignment code in ChipFromFreeBlock
|
|||
|
function so that we are properly aligned with the rest of the
|
|||
|
Memory manager on 68040 Macs.
|
|||
|
<9> 10/28/91 SAM/KSM Rolled in Regatta change.
|
|||
|
|
|||
|
Regatta Change History:
|
|||
|
|
|||
|
<1> 8/8/91 SAM (RMP) Fixed MoveHeap bug where slop wasn't taken into account when
|
|||
|
calculating zcbFree.
|
|||
|
7.0 History:
|
|||
|
|
|||
|
<8> 5/23/91 dba do a style of coercion that MPW 3.2 C likes
|
|||
|
<7> 4/9/91 DFH VL, #83672 : Added GetProcessMgrHiMaxBlock.
|
|||
|
<6> 3/15/91 DFH sad,WS#DFH-910315a: Fixed GetProcessMgrLoFreeBytes to not
|
|||
|
dereference sawInterestingBlock parameter if handleOfInterest is
|
|||
|
nil.
|
|||
|
<5> 3/4/91 DFH JWM,WS#DFH-910226b: Fixed GetSystemHiFreeBytes loop termination.
|
|||
|
Was counting the zone trailer.
|
|||
|
<4> 2/21/91 DFH dba,#82504, #82681, #83168, #83182, #83207: Process Mgr heap
|
|||
|
allocation now makes sure there is sufficient memory in the
|
|||
|
system heap even when ProcessMgr zone doesn't need to grow.
|
|||
|
<2> 11/21/90 DFH Fixed GZ parameter adjustments to deal correctly with boundary
|
|||
|
conditions. Also, use ROUTINE_ADDR when setting gzProc, to
|
|||
|
bypass jumptable.
|
|||
|
<0> x/xx/86 PYG New Today.
|
|||
|
|
|||
|
*/
|
|||
|
|
|||
|
#include <types.h>
|
|||
|
#include <memory.h>
|
|||
|
#include <menus.h>
|
|||
|
#include <files.h>
|
|||
|
#include <quickdraw.h>
|
|||
|
#include <windows.h>
|
|||
|
#include <osutils.h>
|
|||
|
#include <devices.h>
|
|||
|
#include <retrace.h>
|
|||
|
#include <errors.h>
|
|||
|
|
|||
|
#include "Glue.h"
|
|||
|
#include "Lomem.h"
|
|||
|
#include "Data.h"
|
|||
|
#include "SysMisc.h"
|
|||
|
#include "Zone.h"
|
|||
|
#include "Zone24.h"
|
|||
|
|
|||
|
#pragma segment zone24_tools
|
|||
|
|
|||
|
/* ZoneMPBlockPtr24. Locate the master pointer block for the given zone */
|
|||
|
Ptr
|
|||
|
ZoneMPBlockPtr24(THz pZone)
|
|||
|
{
|
|||
|
return((Ptr)pZone + SIZEOF_ZONE_HEADER + SIZEOF_BLOCK_HEADER);
|
|||
|
}
|
|||
|
|
|||
|
/* MakeNonRelocatable24. Given a pointer to a block's data, convert the block type
|
|||
|
* to "nonrelocatable".
|
|||
|
* Assumes block is from THEZONE.
|
|||
|
*/
|
|||
|
void
|
|||
|
MakeNonRelocatable24(Ptr pBlock)
|
|||
|
{
|
|||
|
pBlock -= SIZEOF_BLOCK_HEADER;
|
|||
|
BLOCK_HANDLE((HeapBlockPtr)pBlock) = (Handle)THEZONE;
|
|||
|
TAGBYTE((HeapBlockPtr)pBlock) = nRelTagVal;
|
|||
|
}
|
|||
|
|
|||
|
/* GetProcessMgrLoFreeBytes24. Find out how many free or purgeable bytes there are below
|
|||
|
* the lowest immovable block in the Process Mgr heap. Size returned is physical byte
|
|||
|
* count. As a side benefit, this routine also tells the caller whether the specified
|
|||
|
* handle was encountered in this low range. Finding the block implies that freeing or
|
|||
|
* shrinking it would donate free space area of the Process Mgr heap into which the
|
|||
|
* system heap can grow.
|
|||
|
*/
|
|||
|
u_size
|
|||
|
GetProcessMgrLoFreeBytes24(Handle handleOfInterest, Boolean *sawInterestingBlock)
|
|||
|
{
|
|||
|
HeapBlockPtr heapBlockPtr, blockOfInterest;
|
|||
|
u_size blockSize, loFreeBytes;
|
|||
|
unsigned int blockTags;
|
|||
|
unsigned int blockFlags;
|
|||
|
|
|||
|
/* Convert Handle to physical block address. This works fine even if the handle
|
|||
|
* has been purged (physical address will not be found in the loop), but of course
|
|||
|
* we are never called with a purged handle, anyway.
|
|||
|
*/
|
|||
|
if (handleOfInterest != nil)
|
|||
|
{
|
|||
|
blockOfInterest = (HeapBlockPtr) ((((u_long) (*handleOfInterest)) & LO3BYTES) - SIZEOF_BLOCK_HEADER);
|
|||
|
*sawInterestingBlock = false;
|
|||
|
}
|
|||
|
else
|
|||
|
blockOfInterest = nil;
|
|||
|
|
|||
|
/* Skip dummy block */
|
|||
|
heapBlockPtr = &ProcessMgrZone->heapData;
|
|||
|
(Ptr)heapBlockPtr += BLOCK_SIZE(heapBlockPtr);
|
|||
|
loFreeBytes = 0;
|
|||
|
|
|||
|
/* Walk the heap. Use infinite for loop instead of while loop, since we are guaranteed
|
|||
|
* to find at least one non-relocatable block (e.g. a master pointer block).
|
|||
|
*/
|
|||
|
for (;;)
|
|||
|
{
|
|||
|
blockTags = (unsigned int) TAGBYTE(heapBlockPtr);
|
|||
|
blockSize = BLOCK_SIZE(heapBlockPtr);
|
|||
|
|
|||
|
/* Are we looking at the interesting block? */
|
|||
|
if (heapBlockPtr == blockOfInterest)
|
|||
|
*sawInterestingBlock = true;
|
|||
|
|
|||
|
/* Count this block in if it is free or purgeable. Stop when we reach
|
|||
|
* an immovable block (assume unrecognized block is immovable).
|
|||
|
*/
|
|||
|
if (blockTags == freeTagVal)
|
|||
|
loFreeBytes += blockSize;
|
|||
|
else if (blockTags == relTagVal)
|
|||
|
{
|
|||
|
blockFlags = (unsigned int) MP_TAGBYTE(heapBlockPtr,ProcessMgrZone);
|
|||
|
if ((blockFlags & lockedMPTagFlag) != 0)
|
|||
|
break;
|
|||
|
else if ((blockFlags & purgeableMPTagFlag) != 0)
|
|||
|
loFreeBytes += blockSize;
|
|||
|
}
|
|||
|
else
|
|||
|
break;
|
|||
|
|
|||
|
(Ptr)heapBlockPtr += blockSize;
|
|||
|
}
|
|||
|
|
|||
|
return(loFreeBytes);
|
|||
|
}
|
|||
|
|
|||
|
/* GetSystemHiFreeBytes24. Find out how many free or purgeable bytes there are above
|
|||
|
* the highest immovable block in the system heap. Size returned is physical byte count.
|
|||
|
*/
|
|||
|
u_size
|
|||
|
GetSystemHiFreeBytes24(void)
|
|||
|
{
|
|||
|
HeapBlockPtr heapBlockPtr;
|
|||
|
u_size blockSize, hiFreeBytes;
|
|||
|
unsigned int blockTags;
|
|||
|
unsigned int blockFlags;
|
|||
|
|
|||
|
hiFreeBytes = 0;
|
|||
|
|
|||
|
/* Begin at the beginning */
|
|||
|
heapBlockPtr = &SYSZONE->heapData;
|
|||
|
|
|||
|
/* Walk the heap */
|
|||
|
while (heapBlockPtr < SYSZONE->bkLim)
|
|||
|
{
|
|||
|
blockTags = (unsigned int) TAGBYTE(heapBlockPtr);
|
|||
|
blockSize = BLOCK_SIZE(heapBlockPtr);
|
|||
|
|
|||
|
/* Count this block in if it is free or purgeable. Reset the counter if the
|
|||
|
* if the block is non-relocatable, relocatable but locked, or of some unknown
|
|||
|
* new type, since we require memory above all such blocks.
|
|||
|
*/
|
|||
|
if (blockTags == freeTagVal)
|
|||
|
hiFreeBytes += blockSize;
|
|||
|
else if (blockTags == relTagVal)
|
|||
|
{
|
|||
|
blockFlags = (unsigned int) MP_TAGBYTE(heapBlockPtr,SYSZONE);
|
|||
|
if ((blockFlags & lockedMPTagFlag) != 0)
|
|||
|
hiFreeBytes = 0;
|
|||
|
else if ((blockFlags & purgeableMPTagFlag) != 0)
|
|||
|
hiFreeBytes += blockSize;
|
|||
|
}
|
|||
|
else
|
|||
|
hiFreeBytes = 0;
|
|||
|
|
|||
|
(Ptr)heapBlockPtr += blockSize;
|
|||
|
}
|
|||
|
|
|||
|
return(hiFreeBytes);
|
|||
|
}
|
|||
|
|
|||
|
/* ExtendZone24. Extend the given zone upwards cbNeeded bytes by changing the
|
|||
|
* trailer block into a free block and creating a new block right after it. This
|
|||
|
* parallels procedure ZoneAdjustEnd() in ROM.
|
|||
|
* NOTE: This must be extended in blocks of at least MIN_PHYSICAL_SIZE, as we need
|
|||
|
* to create a new free block underneath the current trailer block.
|
|||
|
* A5 world needed: None
|
|||
|
*/
|
|||
|
void
|
|||
|
ExtendZone24(THz theZone, unsigned long cbNeeded)
|
|||
|
{
|
|||
|
HeapBlockPtr oldBkLim,newBkLim;
|
|||
|
|
|||
|
assert(cbNeeded >= MIN_PHYSICAL_SIZE);
|
|||
|
|
|||
|
/* Get current zone trailer block and calc address of the new one */
|
|||
|
(Ptr)oldBkLim = theZone->bkLim;
|
|||
|
(Ptr)newBkLim = (Ptr)oldBkLim + cbNeeded;
|
|||
|
|
|||
|
/* Enlarge the zone trailer to the amount of the extension */
|
|||
|
CLEAR_BLOCK_ATTRS(oldBkLim);
|
|||
|
BLOCK_SIZE(oldBkLim) = cbNeeded;
|
|||
|
TAGBYTE(oldBkLim) = freeTagVal;
|
|||
|
|
|||
|
/* Init the block header of the new zone trailer */
|
|||
|
CLEAR_BLOCK_ATTRS(newBkLim);
|
|||
|
BLOCK_SIZE(newBkLim) = MIN_PHYSICAL_SIZE;
|
|||
|
TAGBYTE(newBkLim) = freeTagVal;
|
|||
|
|
|||
|
/* Adjust zone header to reflect the added free bytes */
|
|||
|
theZone->zcbFree += cbNeeded;
|
|||
|
theZone->bkLim = (Ptr)newBkLim;
|
|||
|
}
|
|||
|
|
|||
|
/* MoveZone24. Move the Process Mgr zone from here to there.
|
|||
|
* Assumes A5 == PROCESSMGRGLOBALS
|
|||
|
*/
|
|||
|
void
|
|||
|
MoveZone24(THz oldZone, THz newZone)
|
|||
|
{
|
|||
|
HeapBlockPtr pBlock, pMaxBlock;
|
|||
|
unsigned long cbDelta, oldDummyBlockSize;
|
|||
|
Boolean zoneWentUp;
|
|||
|
|
|||
|
/* Update appropriate locations to reflect new location */
|
|||
|
if (THEZONE == oldZone)
|
|||
|
THEZONE = newZone;
|
|||
|
if (APPLZONE == oldZone)
|
|||
|
APPLZONE = newZone;
|
|||
|
pNullProcess->p_zone = ProcessMgrZone = newZone;
|
|||
|
|
|||
|
/* remember size of current dummy ptr (big if shrinking Process Mgr zone) */
|
|||
|
pBlock = &oldZone->heapData;
|
|||
|
oldDummyBlockSize = BLOCK_SIZE(pBlock);
|
|||
|
|
|||
|
/* Invalidate the rover and purgeptr */
|
|||
|
oldZone->purgePtr = nil;
|
|||
|
oldZone->allocPtr = nil;
|
|||
|
|
|||
|
/* Move the zone header */
|
|||
|
BlockMove(oldZone, newZone, SIZEOF_ZONE_HEADER);
|
|||
|
|
|||
|
/* Set up new dummy nonrelocatable block */
|
|||
|
pBlock = &newZone->heapData;
|
|||
|
CLEAR_BLOCK_ATTRS(pBlock);
|
|||
|
BLOCK_SIZE(pBlock) = MIN_PHYSICAL_SIZE;
|
|||
|
BLOCK_HANDLE(pBlock) = (Handle) newZone;
|
|||
|
TAGBYTE(pBlock) = nRelTagVal;
|
|||
|
|
|||
|
/* Need to know sign and magnitude of move */
|
|||
|
zoneWentUp = (newZone > oldZone);
|
|||
|
cbDelta = (zoneWentUp) ? (unsigned long)newZone - (unsigned long)oldZone : (unsigned long)oldZone - (unsigned long)newZone;
|
|||
|
|
|||
|
/* If the zone was lowered, there is room to make a free block above
|
|||
|
* the dummy block. Have to add on extra slop if old size > MIN_PHYSICAL_SIZE.
|
|||
|
* Also, keep the zone free count in sync with this addition.
|
|||
|
*/
|
|||
|
if (zoneWentUp == false)
|
|||
|
{
|
|||
|
(Ptr)pBlock += MIN_PHYSICAL_SIZE;
|
|||
|
CLEAR_BLOCK_ATTRS(pBlock);
|
|||
|
BLOCK_SIZE(pBlock) = cbDelta + (oldDummyBlockSize - MIN_PHYSICAL_SIZE);
|
|||
|
BLOCK_HANDLE(pBlock) = (Handle) nil;
|
|||
|
TAGBYTE(pBlock) = freeTagVal;
|
|||
|
newZone->zcbFree += BLOCK_SIZE(pBlock); /* <8> was += cbDelta; */
|
|||
|
}
|
|||
|
|
|||
|
/* Traverse zone to adjust handle field in the block headers */
|
|||
|
(Ptr)pBlock += BLOCK_SIZE(pBlock);
|
|||
|
pMaxBlock = newZone->bkLim;
|
|||
|
while (pBlock < pMaxBlock)
|
|||
|
{
|
|||
|
if (IS_RELOC_BLOCK(pBlock))
|
|||
|
{
|
|||
|
if (zoneWentUp)
|
|||
|
(Ptr)(BLOCK_HANDLE(pBlock)) -= cbDelta;
|
|||
|
else
|
|||
|
(Ptr)(BLOCK_HANDLE(pBlock)) += cbDelta;
|
|||
|
}
|
|||
|
else
|
|||
|
if (IS_NRELOC_BLOCK(pBlock))
|
|||
|
BLOCK_HANDLE(pBlock) = newZone;
|
|||
|
|
|||
|
/* go to next block */
|
|||
|
(Ptr)pBlock += BLOCK_SIZE(pBlock);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* ShrinkProcessMgrZone24. Try to shrink the Process Mgr heap by cbNeeded bytes. Works
|
|||
|
* by growing the dummy block up (with the GZ proc disabled!), then moving the zone
|
|||
|
* header up to the end of it.
|
|||
|
* NOTE: Does not adjust the system zone! When we return to caller, there is a
|
|||
|
* vacuum between the two zones that should caller should fix with ExtendZone.
|
|||
|
*
|
|||
|
* Returns cbActual (where cbActual >= cbNeeded) on success, zero on failure.
|
|||
|
* A5 world needed: PROCESSMGRGLOBALS.
|
|||
|
*/
|
|||
|
unsigned long
|
|||
|
ShrinkProcessMgrZone24(unsigned long cbNeeded)
|
|||
|
{
|
|||
|
register THz origZone;
|
|||
|
HeapBlockPtr dummyHdrPtr;
|
|||
|
Ptr dummyPtr;
|
|||
|
unsigned long sizeToGrow;
|
|||
|
|
|||
|
/* check param */
|
|||
|
assert((cbNeeded != 0) && (WORD_ALIGNED(cbNeeded)));
|
|||
|
|
|||
|
/* Calculate size that dummy block should grow. Allow for overflow. */
|
|||
|
if ((sizeToGrow = cbNeeded + SIZEOF_SMALLEST_PTR_DATUM) < cbNeeded)
|
|||
|
return(0);
|
|||
|
|
|||
|
/* Try to grow the dummy block to desired size, making sure that
|
|||
|
* the ProcessMgrZone GZ proc is temporarily disabled.
|
|||
|
*/
|
|||
|
origZone = ProcessMgrZone;
|
|||
|
dummyHdrPtr = (HeapBlockPtr)(&origZone->heapData);
|
|||
|
dummyPtr = (Ptr)dummyHdrPtr + SIZEOF_BLOCK_HEADER;
|
|||
|
origZone->gzProc = nil;
|
|||
|
SetPtrSize(dummyPtr, sizeToGrow);
|
|||
|
origZone->gzProc = ROUTINE_ADDR(ProcessMgr_GZProc_Glue);
|
|||
|
|
|||
|
/* Not enough memory ... oh well! */
|
|||
|
if (MEMERROR != noErr)
|
|||
|
return(0);
|
|||
|
|
|||
|
/* Find out how much we actually were given (could be more if filling a large
|
|||
|
* free block), then subtract overhead, to determine the true offset of the new
|
|||
|
* zone header. Save result in cbNeeded.
|
|||
|
*/
|
|||
|
cbNeeded = BLOCK_SIZE(dummyHdrPtr) - (SIZEOF_BLOCK_HEADER + SIZEOF_SMALLEST_PTR_DATUM);
|
|||
|
assert((cbNeeded != 0) && (WORD_ALIGNED(cbNeeded)));
|
|||
|
|
|||
|
/* Calculate new start of zone, and move it there */
|
|||
|
MoveZone(origZone, (Ptr) origZone + cbNeeded);
|
|||
|
|
|||
|
/* tell caller how much we got */
|
|||
|
return(cbNeeded);
|
|||
|
}
|
|||
|
|
|||
|
/* GetLockPtr24. Get a non-relocatable block as close to (but below) ceilingPtr
|
|||
|
* as possible, and stamp it with the signature 'LOCK'.
|
|||
|
* A5 world needed: PROCESSMGRGLOBALS
|
|||
|
*/
|
|||
|
Ptr
|
|||
|
GetLockPtr24(Ptr ceilingPtr)
|
|||
|
{
|
|||
|
register THz localProcessMgrZone;
|
|||
|
HeapBlockPtr dummyBlockPtr;
|
|||
|
Ptr dummyPtr,lockPtr;
|
|||
|
u_size requestSize;
|
|||
|
|
|||
|
assert(THEZONE == ProcessMgrZone);
|
|||
|
|
|||
|
/* Get current value of Process Mgr zone, and determine address of the
|
|||
|
* minimal dummy block at the low end of the zone.
|
|||
|
*/
|
|||
|
localProcessMgrZone = ProcessMgrZone;
|
|||
|
dummyBlockPtr = (HeapBlockPtr)&localProcessMgrZone->heapData;
|
|||
|
dummyPtr = BLOCK_DATA(dummyBlockPtr);
|
|||
|
|
|||
|
|
|||
|
/* Try to grow the dummy block big enough so its high end matches
|
|||
|
* ceilingPtr, but without letting the heap move.
|
|||
|
*/
|
|||
|
assert(ceilingPtr > dummyPtr);
|
|||
|
requestSize = ceilingPtr - dummyPtr;
|
|||
|
localProcessMgrZone->gzProc = nil;
|
|||
|
SetPtrSize(dummyPtr, requestSize);
|
|||
|
|
|||
|
/* Request to grow up failed, so try for free block immediately
|
|||
|
* following. Assumption is that memory manager always moves
|
|||
|
* handles up high, coelescing free space low. Failure is fatal.
|
|||
|
*/
|
|||
|
if (MEMERROR != noErr)
|
|||
|
{
|
|||
|
dummyBlockPtr = (Ptr)dummyBlockPtr + BLOCK_SIZE(dummyBlockPtr);
|
|||
|
if ( IS_NOT_FREE_BLOCK(dummyBlockPtr)
|
|||
|
|| (BLOCK_SIZE(dummyBlockPtr) < MIN_PHYSICAL_SIZE) )
|
|||
|
return(nil);
|
|||
|
|
|||
|
requestSize = BLOCK_SIZE(dummyBlockPtr) - MIN_PHYSICAL_SIZE;
|
|||
|
SetPtrSize(dummyPtr, requestSize);
|
|||
|
if (MEMERROR != noErr)
|
|||
|
return(nil);
|
|||
|
}
|
|||
|
|
|||
|
/* Dummy block is now up as close to ceilingPtr as possible. I.e. The
|
|||
|
* low free space was eaten, so a new allocation will be at (we hope)
|
|||
|
* or above ceilingPtr. Allocate the lock block as a minimal sized
|
|||
|
* pointer, then shrink the dummy back to leave room for the real
|
|||
|
* allocation later.
|
|||
|
*/
|
|||
|
if ((lockPtr = NewPtr(sizeof(long))) != nil)
|
|||
|
*((long *)lockPtr) = 'LOCK';
|
|||
|
SetPtrSize(dummyPtr, SIZEOF_SMALLEST_PTR_DATUM);
|
|||
|
assert(MEMERROR == noErr);
|
|||
|
|
|||
|
/* Reallow growth */
|
|||
|
localProcessMgrZone->gzProc = ROUTINE_ADDR(ProcessMgr_GZProc_Glue);
|
|||
|
|
|||
|
return(lockPtr);
|
|||
|
}
|
|||
|
|
|||
|
/* GetProcessMgrHiMaxBlock24. Do like MaxBlock() on the Process Mgr zone, but ignore
|
|||
|
* the straddle area part.
|
|||
|
*/
|
|||
|
u_size
|
|||
|
GetProcessMgrHiMaxBlock24(void)
|
|||
|
{
|
|||
|
HeapBlockPtr heapBlockPtr;
|
|||
|
u_size blockSize, hiMaxBlock, thisRangeFree;
|
|||
|
unsigned int blockTags;
|
|||
|
unsigned int blockFlags;
|
|||
|
Boolean aboveStraddle;
|
|||
|
|
|||
|
aboveStraddle = false;
|
|||
|
thisRangeFree = 0;
|
|||
|
hiMaxBlock = 0;
|
|||
|
|
|||
|
/* Skip dummy block */
|
|||
|
heapBlockPtr = &ProcessMgrZone->heapData;
|
|||
|
(Ptr)heapBlockPtr += BLOCK_SIZE(heapBlockPtr);
|
|||
|
|
|||
|
/* Walk the heap */
|
|||
|
while (heapBlockPtr < ProcessMgrZone->bkLim)
|
|||
|
{
|
|||
|
blockTags = (unsigned int) TAGBYTE(heapBlockPtr);
|
|||
|
blockSize = BLOCK_SIZE(heapBlockPtr);
|
|||
|
|
|||
|
/* Count this block in if it is free or purgeable. Reset the counter if the
|
|||
|
* if the block is non-relocatable, relocatable but locked, or of some unknown
|
|||
|
* new type, since we're looking for memory *between* such blocks.
|
|||
|
*/
|
|||
|
if (blockTags == freeTagVal)
|
|||
|
thisRangeFree += blockSize;
|
|||
|
else if (blockTags == relTagVal)
|
|||
|
{
|
|||
|
blockFlags = (unsigned int) MP_TAGBYTE(heapBlockPtr,ProcessMgrZone);
|
|||
|
if ((blockFlags & lockedMPTagFlag) != 0)
|
|||
|
{
|
|||
|
if ((thisRangeFree > hiMaxBlock) && (aboveStraddle))
|
|||
|
hiMaxBlock = thisRangeFree;
|
|||
|
aboveStraddle = true;
|
|||
|
thisRangeFree = 0;
|
|||
|
}
|
|||
|
else if ((blockFlags & purgeableMPTagFlag) != 0)
|
|||
|
thisRangeFree += blockSize;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if ((thisRangeFree > hiMaxBlock) && (aboveStraddle))
|
|||
|
hiMaxBlock = thisRangeFree;
|
|||
|
aboveStraddle = true;
|
|||
|
thisRangeFree = 0;
|
|||
|
}
|
|||
|
|
|||
|
(Ptr)heapBlockPtr += blockSize;
|
|||
|
}
|
|||
|
|
|||
|
/* Allow for block header we'd need */
|
|||
|
if (hiMaxBlock != 0)
|
|||
|
PhysicalToLogicalSize(hiMaxBlock);
|
|||
|
return(hiMaxBlock);
|
|||
|
}
|
|||
|
|
|||
|
/* GetHighestLargeFreeBlock24. This function returns a pointer to a block that
|
|||
|
* is >= size, or nil if one couldn't be located. It will not pass any
|
|||
|
* non-relocatable blocks during it's search.
|
|||
|
*/
|
|||
|
FreeBlockAddr
|
|||
|
GetHighestLargeFreeBlock24(u_size size, Ptr lockPtr)
|
|||
|
{
|
|||
|
HeapBlockPtr blockPtr, highestLargeFreeBlock, trailerBlockPtr;
|
|||
|
u_size blockSize;
|
|||
|
|
|||
|
assert(lockPtr == nil || *((long *)lockPtr) == 'LOCK');
|
|||
|
|
|||
|
/* Looking for physical blocks now */
|
|||
|
size += SIZEOF_BLOCK_HEADER;
|
|||
|
|
|||
|
/* Start at bottom of heap, and go up to trailerBlock */
|
|||
|
blockPtr = (HeapBlockPtr)&THEZONE->heapData;
|
|||
|
trailerBlockPtr = (HeapBlockPtr)THEZONE->bkLim;
|
|||
|
highestLargeFreeBlock = nil;
|
|||
|
while (blockPtr < trailerBlockPtr)
|
|||
|
{
|
|||
|
blockSize = BLOCK_SIZE(blockPtr);
|
|||
|
|
|||
|
/* Check whether this is a valid block for our purposes */
|
|||
|
if ((IS_FREE_BLOCK(blockPtr) && (blockSize >= size)))
|
|||
|
highestLargeFreeBlock = blockPtr;
|
|||
|
|
|||
|
/* Advance to next block */
|
|||
|
(Ptr)blockPtr += blockSize;
|
|||
|
|
|||
|
/* Don't go past ceiling ptr for Excel. Note that this check is not made
|
|||
|
* against the first block in the zone. This is OK because a) the lock
|
|||
|
* block does no good in that case, and b) the first block is our dummy block.
|
|||
|
*/
|
|||
|
if (BLOCK_DATA(blockPtr) == lockPtr)
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
return((FreeBlockAddr) highestLargeFreeBlock);
|
|||
|
}
|
|||
|
|
|||
|
/* GetTopBlockSize24. Extract the size of the specified block. Return 0 if address
|
|||
|
* is nil or the block is not the absolute highest in the zone.
|
|||
|
*/
|
|||
|
unsigned long
|
|||
|
GetTopBlockSize24(FreeBlockAddr pTopBlock)
|
|||
|
{
|
|||
|
u_size blockSize;
|
|||
|
|
|||
|
if ((pTopBlock == nil)
|
|||
|
|| ((Ptr)pTopBlock + (blockSize = BLOCK_SIZE((HeapBlockPtr) pTopBlock)) != THEZONE->bkLim) )
|
|||
|
return(0);
|
|||
|
|
|||
|
return(blockSize);
|
|||
|
}
|
|||
|
|
|||
|
/* FreeTop24. Shrink the size of the given free block to the specified value, and
|
|||
|
* create a zone trailer block after the result. Returns address of trailer block.
|
|||
|
*/
|
|||
|
FreeBlockAddr
|
|||
|
FreeTop24(FreeBlockAddr pBlockHdr, u_size newSize)
|
|||
|
{
|
|||
|
/* Resize the free block: only the size field needs to change */
|
|||
|
BLOCK_SIZE((HeapBlockPtr)pBlockHdr) = newSize;
|
|||
|
|
|||
|
/* Advance pBlockHdr to header of block to follow, and init the header */
|
|||
|
*(Ptr*)&pBlockHdr += newSize;
|
|||
|
CLEAR_BLOCK_ATTRS(pBlockHdr);
|
|||
|
TAGBYTE((HeapBlockPtr)pBlockHdr) = freeTagVal;
|
|||
|
BLOCK_SIZE((HeapBlockPtr)pBlockHdr) = MIN_PHYSICAL_SIZE;
|
|||
|
return(pBlockHdr);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* ChipOffRelocFromFree24. Allocate a relocatable block at the high end of the
|
|||
|
* given free block.
|
|||
|
* Assumes that the free block length is at least sizeNeeded.
|
|||
|
* NOTE: The size correction will be incorrect if the free block is bigger
|
|||
|
* than sizeNeeded, but not big enough to be cleaved. The resulting logical
|
|||
|
* size will be slightly larger than requested.
|
|||
|
*/
|
|||
|
void
|
|||
|
ChipOffRelocFromFree24(FreeBlockAddr pBlock, Handle theHandle, u_size sizeNeeded, short sizeCorrection)
|
|||
|
{
|
|||
|
HeapBlockPtr hbPtr = (HeapBlockPtr) pBlock;
|
|||
|
u_size unusedBytes;
|
|||
|
|
|||
|
sizeNeeded += SIZEOF_BLOCK_HEADER;
|
|||
|
|
|||
|
if ((unusedBytes = BLOCK_SIZE(hbPtr) - sizeNeeded) >= MIN_PHYSICAL_SIZE)
|
|||
|
{
|
|||
|
SIZE_CORR(hbPtr) = 0;
|
|||
|
BLOCK_SIZE(hbPtr) = unusedBytes;
|
|||
|
(Ptr)hbPtr += unusedBytes;
|
|||
|
BLOCK_SIZE(hbPtr) = sizeNeeded;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
sizeNeeded = BLOCK_SIZE(hbPtr);
|
|||
|
sizeCorrection += unusedBytes;
|
|||
|
assert(sizeCorrection <= 15);
|
|||
|
}
|
|||
|
|
|||
|
/* Convert block to relocatable, and set master pointer and size correction */
|
|||
|
CLEAR_BLOCK_ATTRS(hbPtr);
|
|||
|
TAGBYTE(hbPtr) = relTagVal;
|
|||
|
BLOCK_HANDLE(hbPtr) = (Ptr)(theHandle) - (long)THEZONE;
|
|||
|
SIZE_CORR(hbPtr) = sizeCorrection;
|
|||
|
*theHandle = BLOCK_DATA(hbPtr);
|
|||
|
|
|||
|
/* Adjust heap for the loss */
|
|||
|
HEAP_FREE_SPACE(THEZONE) -= sizeNeeded;
|
|||
|
}
|
|||
|
|
|||
|
/* InitVectorTable24. Stuff the function vectors with our values. */
|
|||
|
void
|
|||
|
InitVectorTable24(void)
|
|||
|
{
|
|||
|
vrGetProcessMgrLoFreeBytes = (Ptr) ROUTINE_ADDR(GetProcessMgrLoFreeBytes24);
|
|||
|
vrExtendZone = (Ptr) ROUTINE_ADDR(ExtendZone24);
|
|||
|
vrMoveZone = (Ptr) ROUTINE_ADDR(MoveZone24);
|
|||
|
vrShrinkProcessMgrZone = (Ptr) ROUTINE_ADDR(ShrinkProcessMgrZone24);
|
|||
|
vrGetLockPtr = (Ptr) ROUTINE_ADDR(GetLockPtr24);
|
|||
|
vrGetHighestLargeFreeBlock = (Ptr) ROUTINE_ADDR(GetHighestLargeFreeBlock24);
|
|||
|
vrGetTopBlockSize = (Ptr) ROUTINE_ADDR(GetTopBlockSize24);
|
|||
|
vrFreeTop = (Ptr) ROUTINE_ADDR(FreeTop24);
|
|||
|
vrChipOffRelocFromFree = (Ptr) ROUTINE_ADDR(ChipOffRelocFromFree24);
|
|||
|
vrZoneMPBlockPtr = (Ptr) ROUTINE_ADDR(ZoneMPBlockPtr24);
|
|||
|
vrGetSystemHiFreeBytes = (Ptr) ROUTINE_ADDR(GetSystemHiFreeBytes24);
|
|||
|
vrGetProcessMgrHiMaxBlock = (Ptr) ROUTINE_ADDR(GetProcessMgrHiMaxBlock24);
|
|||
|
}
|