mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-29 20:49:19 +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: © 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’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);
|
||
}
|