mirror of
https://github.com/elliotnunn/supermario.git
synced 2025-02-18 12:30:31 +00:00
3887 lines
112 KiB
C
3887 lines
112 KiB
C
/*
|
|
File: MemMgr.c
|
|
|
|
Contains: Memory Manager External Routines
|
|
|
|
Written by: Jeff Crawford, Brian Topping, Mike Wiese
|
|
|
|
Copyright: © 1992-1994 by Apple Computer, Inc., all rights reserved.
|
|
|
|
Change History (most recent first):
|
|
|
|
<180> 1/20/94 BT #1137209 <BT, jrc> Fix PurgeMem to actually do the purge via
|
|
PurgeAndMakeSpace. It never used to be called for this, so we
|
|
need special consideration for PurgeMem.
|
|
<179> 1/19/94 BT #1135848 <BT, JRG> Weaken tag checks some to accept handles with
|
|
the ptr bit set. There is a conflict that the ptr bit is used to
|
|
mark a busy block in a purge cycle, but this stops the ResMgr
|
|
from getting access to the type since it uses HGetState.
|
|
HGetState bails when the tag check fails. This fixes all cases
|
|
of a handle tag check.
|
|
<178> 1/6/94 BT <BT, jrc> #1134929 PurgeMem is changed to not do a compaction if
|
|
the normal purge cannot get the space it needs. Old IM documents
|
|
this as not moving memory.
|
|
<177> 10/15/93 BT Duh, one of those nights.
|
|
<176> 10/14/93 BT Looks like a new bug from the ashes, a type was wrong now that
|
|
prototypes are enforced.
|
|
<175> 10/14/93 BT <BT, ewa> Radar 1117552; Change interfaces around. Radar
|
|
1114117; fix MoveHHi.
|
|
<174> 9/28/93 BT <BT, ewa> #1114712, MaxApplZone needs to operate on ApplZone,
|
|
not TheZone.
|
|
<173> 9/9/93 BT <ewa, BT> #1110965 Added a fix to SetApplLimit to clear
|
|
curHeap->fHeapIsFullyExtended. This field is an optimization so
|
|
the growzone doesn't get called if it won't help, but the field
|
|
wasn't getting cleared when the limit was extended.
|
|
<172> 9/2/93 BT <BT, ewa> #1110427, add tag checking for heaps. This is a
|
|
precautionary measure, as bus error handlers are proven most
|
|
effective with a quick tag check.
|
|
<171> 8/23/93 BT <BT, DRF> #ifndef'd tag checks to exercise the bus error
|
|
handlers. This is a benign check in.
|
|
<170> 8/19/93 BT <BT, cam> Add "#ifdef hasFirstLevelFakeHandleTests" around
|
|
remaining range checks. This defined in MemMgr.h unless
|
|
"cancelFigmentRangeChecks" is set true.
|
|
<169> 8/19/93 JC <mlw> #1106373, Fix problem when nil is returned by FindHeap.
|
|
<168> 8/17/93 BT <BT, bps> Changed a typecast on LMGetFakeHandleRange().
|
|
<167> 8/17/93 JC <mlw> #1104797, #1106652, Removed odd free MP lists from the
|
|
internal_debug and shipping builds.
|
|
<166> 8/12/93 JC <DRF> #1106070, Fixed HSetState to mask the correct bits to
|
|
protect against unruly clients.
|
|
<165> 8/6/93 BT <BT, BKJ> Radar 1011917: DISKLOCK v2.1.2: Crashes after locking
|
|
disk when idle with Figment on. DiskLock was doing a SetZone
|
|
with a bad value, then doing a MaxBlock. Adding heap checks to
|
|
MaxBlock fixed this instance, although we may want these in
|
|
other places.
|
|
<164> 8/5/93 BT <BT, JC> We came, we saw, we initialed...
|
|
<163> 8/4/93 JC Backed out change <152>, this problem currently breaks, Claris
|
|
CAD, MacDraw II, and MacDraw Pro. #1101865 fixed PurgeMem to
|
|
check to see if the ptr it got back is nil. This fixes the
|
|
MacDraw II problem seen in A3. Made some minor mods to support
|
|
the linked in ThinkC test application.
|
|
<162> 8/2/93 JC #1095953 replaced LMGet/SetRealMemTop with LMGet/
|
|
SetFakeHandleRange to permit heaps above RealMemTop. Modified
|
|
InitZone to raise FakeHandleRange for this situation.
|
|
<161> 7/30/93 JC <mlw> Move ClientDebug routines to be after validity checking in
|
|
DisposePtr. This is attributed to the tag block fix.
|
|
<160> 7/29/93 JC #1102189, #11022190, Fixed MoveHHi to slide blocks up in certain
|
|
situations.
|
|
<159> 7/29/93 JC #1103403, #1103608. Fixed c_PurgeMem to purge all blocks if
|
|
PurgeAndSlideBlocksDown comes up empty.
|
|
<158> 7/29/93 JC Change interface to RemoveHeap to fix OCE bug.
|
|
<157> 7/28/93 BT <BT, JRG> Emergency fix an ugly bug that causes native Figment
|
|
to crash your machine after using Component aware apps. Can't
|
|
use the same interfaces for the "≈Q" calls as the non-dispatched
|
|
until MM is stripping selectors. Added glue for these calls
|
|
here.
|
|
<156> 7/27/93 JC #1100227, Fixed Claris XTND and others who read the first
|
|
longword out of a disposed block. We now move the prevFree link
|
|
of a free block to be 12 bytes lower. Fixed size delta problem
|
|
and removed kWorstCaseBlockOverhead to facilitate this change.
|
|
<155> 7/26/93 JC Commented out ChainedGZProc support code since its never called.
|
|
<154> 7/26/93 JC #1100714 and others. Added fake handle and fake ptr checking by
|
|
comparing tag fields to many common routines. This fixes Digital
|
|
Darkroom and others that pass the range check. Also changed
|
|
SetPtrSize to behave like the old MM when passed a nil ptr
|
|
(crash).
|
|
<153> 7/23/93 JC #1101604 fixed default MP block allocation to be more like the
|
|
old MM.
|
|
<152> 7/23/93 JC Fix bug where we are not creating an MP block during InitZone.
|
|
Unfortunately, I had to special case out the ROZ because it
|
|
already has a corrupted heap that won't work with this change.
|
|
<151> 7/21/93 JC <mw> Fixed bug with A-Train where they disposing a Ptr block
|
|
twice and the block was being backwards coelesced. Also added
|
|
commented out code to call AllocateMoreMasters at the end of
|
|
InitZone. Could not add this code due to a corruption with the
|
|
ROZ.
|
|
<150> 7/20/93 JC Spiffed up the client debug routines for Developer's CD version
|
|
of Figment.
|
|
<149> 7/19/93 BT Even more Radar #1095398. Add fake parameter temporarily to
|
|
strip off the selector that is being passed in from broken
|
|
MixedMode.
|
|
<148> 7/16/93 JC Made changes to support the linked Think C build.
|
|
<147> 7/12/93 BMC StarTrek - adding support for lowmem accessor functions.
|
|
<146> 7/7/93 JC #1096767,1096744,1096911: Fixed FreeMem to not return negative
|
|
values when the heap is full. Fixed PurgeSpace to calculate a
|
|
more accurate value of contiguous purgable space.
|
|
<145> 7/7/93 BT <JRG> Added a trapWord param to PurgeSpaceSystemContiguous when
|
|
I shouldn't have. Put this back to "void" like it was
|
|
originally.
|
|
<144> 7/7/93 BT BTW - <EPT> initialed the last change.
|
|
<143> 7/7/93 BT Continuation of Radar #1095398. I Forgot to put in D1 trap
|
|
parameter for native glue calling conventions some time back,
|
|
now that it is used it needs to be there.
|
|
<142> 7/3/93 BT This change must not have stayed put. Need to change
|
|
rdDisposeProcProcInfo to uppDisposeProcInfo. Eric did this
|
|
already before change control, I am going to do it again here.
|
|
<141> 7/2/93 BT (With EPT) Radar #1095398. Fix internal Memory Manager calls to
|
|
go thru the trap table interface.
|
|
<140> 6/30/93 JC #1089109: Removed fHeapIsDirty bit.
|
|
<139> 6/30/93 JC Added kREALMEMTOP, so we can test from ThinkC and StartTrek.
|
|
Removed Get/SetPhysMemTop since its not used. Cleaned up
|
|
SecondAndThirdLevelFakeHandleTests by localizing testBlock.
|
|
<138> 6/25/93 BT (with JRG) Change LMGetPhysMemTop to LMGetRealMemTop. This
|
|
works with VM. Also verify that the return values from all the
|
|
routines are getting propageted up properly.
|
|
<137> 6/25/93 BT (with EPT) Backed out last change in favor of changing all
|
|
occurences of MemError() to LMGetMemErr().
|
|
<136> 6/25/93 BT (with EPT) Add LowMem.h to includes for power.
|
|
<135> 6/25/93 BT Fix some typecasting for anal IBM compilers.
|
|
<134> 6/25/93 BT (with JC) Added range checking to handle calls so that the
|
|
relative master pointer is checked to be within the bounds of
|
|
available RAM. More elaborate code is in here, but commented
|
|
out because we don't want to use it.
|
|
<133> 6/17/93 JC Fixed DisposeHandle, ReallocHandle, EmptyHandle and HGetState to
|
|
echo the old MM when passed a nil or empty (MP=nil) handle.
|
|
<132> 6/16/93 JC Added universal low memory getters and setters.
|
|
<131> 6/16/93 BMC StarTrek - delete SystemZone & ApplicZone since we resolve them
|
|
elsewhere. Also spunging off of linked_thinkc_app low mem
|
|
global (statics) till low mem access is "macrotized".
|
|
<130> 6/15/93 JC <JRG, JC> Fix __NewHandleHI to conform to new c_NewHandleHI
|
|
calling conventions. Also added NewHandleHi to StarTrek
|
|
interface.
|
|
<129> 6/10/93 JC Added support again for the heap is dirty bit. Removed extra
|
|
parameter to CreateNewHeap.
|
|
<128> 6/8/93 JC Fixed LLInsert to mark block as private.
|
|
<127> 6/8/93 JC Erased some comments.
|
|
<126> 6/4/93 JC Cleaned up internal API for ReallocHandle.
|
|
<125> 6/4/93 JC Changed HeapID's to be a debug feature only.
|
|
<124> 6/4/93 JC Removed use of HeapIsDirty bit for now.
|
|
<123> 6/3/93 JC Fixed routines that call CompactHeap to respect that it can
|
|
return the dummyFree instead of nil.
|
|
<122> 5/28/93 BMC StarTrek glue fixes
|
|
<121> 5/28/93 BMC Failed to enter change history comment (hacked in by hand after
|
|
the fact.
|
|
<120> 5/26/93 BT Added native glue for StraddleBlockSize.
|
|
<119> 5/26/93 BT Finish PowerPC glue and native HeapDispatch.
|
|
<118> 5/25/93 BT Added PowerPC glue for NewHandleHi.
|
|
<117> 5/24/93 JC Changed XXX to DbgXXX for all debug routines.
|
|
<116> 5/24/93 JC Fixed DisposePtr to check to see if the block is already freed.
|
|
<115> 5/21/93 BT Change native glue names to conform to new conventions
|
|
<114> 5/20/93 JC Cleaned up call back procs. Removed c_MoreMastersHi. Added
|
|
c_RegisterDisposeProc API for ProcessMgr.
|
|
<113> 5/19/93 JC Began changes as requested by the code review. Removed options
|
|
parameter from AllocateMoreMasters.
|
|
<112> 5/14/93 JC Modified ReallocHandle to save pass GZRootHnd on to the grow
|
|
zone proc. Considered an alternate version of ReallocHandle that
|
|
would not empty a the handle before allocating a new one.
|
|
However, removed this this version before checking it in to
|
|
mimic the old MM.
|
|
<111> 5/14/93 JC Cleaned up implementation of GZRootPtr, GZRootHnd and GZMoveHnd.
|
|
<110> 5/7/93 JC Added support for GZRootHnd. Fixed obscure bug where
|
|
JumpRelocateRange we would fail when we could still slide blocks
|
|
up. Also fixed a bug in MakeSpaceLow to check against backLimit.
|
|
Fixed similar bug in MakeSpaceHigh to check against
|
|
lowestRemoveableBlock. Otimized AlignUp to be 4 assembly
|
|
instructions.
|
|
<109> 5/5/93 BT Whoops, forgot to compile on 68K first, changed a variable name
|
|
in ReallocHandle that follows different naming conventions.
|
|
Something needs to be done about the references to handles as
|
|
master pointers, this is very confusing...
|
|
<108> 5/5/93 BT Some entry points that take handles were not checking for the
|
|
odd master pointer still. The comments implied that they should,
|
|
so I added them. This fixed another quitting problem in Canvas
|
|
on PDM.
|
|
<107> 5/2/93 JC Put odd free master pointer list back in for any app that does
|
|
not have its compatibility flags set. This odd list is used to
|
|
catch clients who dispose of a block twice, or dispose a block
|
|
then lock it (etc.). When this situation occurs, the call
|
|
returns with memWZErr. I also think I fixed a prob with
|
|
ReallocHandle in debug mode only, but I can't remember.
|
|
<106> 4/23/93 JC Fixed Jeff's heap tree prob when quitting apps that have a
|
|
scrap.
|
|
<105> 4/21/93 JC Fixed AfterDark problem where they dispose first Ptr in the
|
|
heap. Also fixed ProcessMgr problem where it calls SetHandleSize
|
|
when nuking a heap.
|
|
<104> 4/21/93 JC Disabled c_DisposeZone since we now remove the heap from the
|
|
heap tree in DisposeHandle and DisposePtr.
|
|
<103> 4/20/93 JC Added ability to remove heaps from the heap tree when thier
|
|
memory is being disposed.
|
|
<102> 4/18/93 JC Changed #defines to more acurate descriptions. Changed
|
|
small_block_headers to small_freeBlock_headers and linkedIn to
|
|
linked_thinkc_app. •• Brian & Sam take note.••
|
|
<1> 6/10/92 JC New Today
|
|
|
|
*/
|
|
|
|
#ifndef THINK_C
|
|
#ifdef StarTrek
|
|
#include <MacTypes.h>
|
|
#include <MacMem.h>
|
|
#include <Resource.h>
|
|
#include <SysEqu.h>
|
|
#include <Errors.h>
|
|
#include <OSUtils.h>
|
|
#else
|
|
#include <Types.h>
|
|
#include <Memory.h>
|
|
#include <Resources.h>
|
|
#include <SysEqu.h>
|
|
#include <Errors.h>
|
|
#include <OSUtils.h>
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef StarTrek
|
|
#include "MemDebug.h"
|
|
#include "MemMgr.h"
|
|
#include "MemRout.h"
|
|
#include "MemPriv.h"
|
|
#else
|
|
#include "MemMgrDebug.h"
|
|
#include "MemMgr.h"
|
|
#include "MemoryRoutines.h"
|
|
#endif
|
|
|
|
|
|
#ifdef patchedIn
|
|
/* This will overcome the 32k limit */
|
|
#pragma segment Figment
|
|
#endif
|
|
|
|
#ifdef THINK_C
|
|
/* This will overcome the 32k limit */
|
|
#pragma segment Figment
|
|
#endif
|
|
|
|
#ifdef powerc
|
|
#include "QTMemory.h"
|
|
#endif
|
|
|
|
/*
|
|
* if we are linking in as a Think C project, then declare the global variables here.
|
|
* Otherwise we define them as Macintosh low mem globals in MemMgr.h.
|
|
*/
|
|
#if defined(linked_thinkc_app)
|
|
stdHeap* THEZONE;
|
|
Ptr APPLLIMIT;
|
|
stdHeap* SYSZONE;
|
|
stdHeap* APPLZONE;
|
|
Ptr HEAPEND;
|
|
Ptr HIHEAPMARK;
|
|
Handle gGZROOTHND; /* put a "g" in front so we don't clash with interface.o */
|
|
Ptr gGZROOTPTR; /* put a "g" in front so we don't clash with interface.o */
|
|
Handle gGZMOVEHND; /* put a "g" in front so we don't clash with interface.o */
|
|
OSErr gMEMERROR; /* put a "g" in front so we don't clash with interface.o */
|
|
void* gFAKEHANDLERANGE;
|
|
#endif /* linked_thinkc_app */
|
|
|
|
|
|
/* Used by StackSpace & Core_IAZ */
|
|
#if !defined(powerc) && !defined(StarTrek)
|
|
static pascal ulong GetSP(void) = {0x2E8F}; /* Move.l A7,(Sp) */
|
|
#else
|
|
/* 2/16/93 1:44:33 PM (BET): don't have anything for power yet. */
|
|
ulong GetSP()
|
|
{
|
|
long foobar;
|
|
|
|
return ((ulong)&foobar);
|
|
}
|
|
#endif
|
|
|
|
|
|
#if ForROM
|
|
/* this is for the hack used by the Font Manager */
|
|
extern pascal void DiskCachePurgeProcedure(Handle purgeableHandle);
|
|
#endif
|
|
|
|
|
|
/****************************************************************/
|
|
/* Inline routines */
|
|
/****************************************************************/
|
|
|
|
#define MarkBlockPurgable(block, heap) \
|
|
{ \
|
|
IfIntDebugMsg(IsFreeBlock(block), "blockHeader is free", block); \
|
|
IfIntDebugMsg(block == nil, "blockHeader is nil", block); \
|
|
\
|
|
/* If we are marking the block as purable and its not locked, then add it to \
|
|
purable space */ \
|
|
if (IsNonPurgableHandle(block) && IsUnlockedHandle(block)) \
|
|
heap->totalPurgableSpace += block->size; \
|
|
\
|
|
block->purgeBit = 1; /* set purge bit */ \
|
|
}
|
|
|
|
|
|
#define MarkBlockNonPurgable(block, heap) \
|
|
{ \
|
|
IfIntDebugMsg(IsFreeBlock(block), "blockHeader is free", block); \
|
|
IfIntDebugMsg(block == nil, "blockHeader is nil", block); \
|
|
\
|
|
/* If we are marking the block as not purgable and it is unlocked, then subtract \
|
|
it from purable space */ \
|
|
if (IsPurgableHandle(block) && IsUnlockedHandle(block)) \
|
|
heap->totalPurgableSpace -= block->size; \
|
|
\
|
|
block->purgeBit = 0; /* clear purge bit */ \
|
|
}
|
|
|
|
|
|
/****************************************************************/
|
|
/* Non-inline routines */
|
|
/****************************************************************/
|
|
|
|
|
|
/*
|
|
* Note: SetApplBase and InitApplZone are part of the system bootup process. They are not
|
|
* implemented in C as part of Figment. However, some small changes to the assembly language
|
|
* routines have been made to load Figment.
|
|
*/
|
|
|
|
void c_InitZone(GrowZoneProcPtr pGrowZone, short numMasters, void* limitPtr, void* startPtr)
|
|
{
|
|
stdHeap* newZone;
|
|
|
|
#ifdef hasFirstLevelFakeHandleTests
|
|
/* <162 JC>
|
|
* If we are initializing a heap high in ram (ie.- NuBus space), then the fake handle
|
|
* range check would fail for that heap. We therefore check the limit, and if it's higher,
|
|
* we move the fake handle range check higher so clients can still do normal operations
|
|
* on the new heap.
|
|
*/
|
|
if (limitPtr > (void *)LMGetFakeHandleRange()) /* are we creating a heap above the range? */
|
|
LMSetFakeHandleRange(limitPtr); /* yes, set new range. */
|
|
#endif
|
|
|
|
/* initializ the new zone and set TheZone to it */
|
|
LMSetTheZone(newZone = CreateNewHeap(pGrowZone, numMasters, limitPtr, startPtr));
|
|
|
|
#ifndef patchedIn
|
|
{
|
|
stdHeap* curHeap;
|
|
|
|
if (!IsHeap(curHeap = LMGetTheZone())) {
|
|
ClientDebugMsg("Bad heap from LowMem", curHeap);
|
|
LMSetMemErr(memAZErr);
|
|
return;
|
|
}
|
|
|
|
if (IsAppHeap(curHeap))
|
|
{
|
|
Ptr limit;
|
|
/* is the new heap limit above HiHeapMark? */
|
|
if (LMGetHiHeapMark() < (limit = (char*)curHeap->backLimit + curHeap->backLimit->size))
|
|
LMSetHiHeapMark(limit);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* <152 JC>
|
|
* Allocate the master pointer block as per Inside Mac.
|
|
*
|
|
* Special note: The Rom Read Only Zone is really messed up. All memory blocks
|
|
* in ROM have hard coded relative handles. The means that the offset of the
|
|
* MP with respect the the heap header cannont change. Adding the MP block
|
|
* at the start of the heap disrupts the heap enough that MP pointing to ROM
|
|
* are written over important block headers. To avoid this problem, we don't
|
|
* create an MP in the ROZ untill a handle is created. When the ROZ if fixed,
|
|
* remove this code.
|
|
*/
|
|
if (ReadOnlyZone != newZone)
|
|
{
|
|
/* this is not the ROZ, create a MP block */
|
|
AllocateMoreMasters((stdHeap*) startPtr);
|
|
}
|
|
|
|
/*
|
|
* This is for the stupid font manager patch that rolled into SuperMario
|
|
* so the Font Manager can set the purge proc.
|
|
*/
|
|
#ifndef patchedIn
|
|
#ifndef linked_thinkc_app
|
|
#if ForROM
|
|
((stdHeap*) startPtr)->purgeProc = DiskCachePurgeProcedure;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
LMSetMemErr(noErr);
|
|
}
|
|
|
|
|
|
#if defined(linked_thinkc_app)
|
|
/* Not in ROM */
|
|
Ptr c_GetApplLimit(void)
|
|
{
|
|
return LMGetApplLimit();
|
|
}
|
|
#endif
|
|
|
|
|
|
OSErr c_SetApplLimit(Ptr zoneLimit)
|
|
{
|
|
#ifdef linked_thinkc_app
|
|
ulong justAValue = 0x400; /* some value */
|
|
ulong* DefltStack = &justAValue;
|
|
#elif StarTrek
|
|
ulong justAValue = 0x6000; /* some value */
|
|
ulong* DefltStack = &justAValue;
|
|
#endif
|
|
Ptr defaultLimit = (Ptr) ((GetSP() - (*(ulong*)DefltStack)));
|
|
|
|
zoneLimit = (Ptr) AlignDown(MIN(zoneLimit, defaultLimit));
|
|
|
|
if ((Ptr)(LMGetApplZone())->backLimit > zoneLimit)
|
|
{
|
|
/* note: in the ProcessMgr comments, it complains that there is a bug in the old
|
|
SetApplLimit where it sets ApplLimit if an error is returned. This code
|
|
fixes that bug by exiting before an error is returned. */
|
|
return LMSetMemErr(memFullErr);
|
|
}
|
|
|
|
/* if we are extending ApplLimit, clear fHeapFullyExtended */
|
|
if (LMGetApplLimit() < zoneLimit)
|
|
{
|
|
stdHeap* curHeap;
|
|
if (!IsHeap(curHeap = LMGetTheZone()))
|
|
{
|
|
ClientDebugMsg("Bad heap from LowMem", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
curHeap->fHeapFullyExtended = 0;
|
|
}
|
|
|
|
LMSetHiHeapMark(LMSetApplLimit(zoneLimit));
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
|
|
|
|
OSErr c_MaxApplZone(void)
|
|
{
|
|
stdHeap* curHeap;
|
|
|
|
if (!IsHeap(curHeap = LMGetApplZone())) {
|
|
ClientDebugMsg("Bad heap from LowMem", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
if (!(curHeap->fHeapFullyExtended))
|
|
{
|
|
LMSetHiHeapMark(LMGetApplLimit());
|
|
|
|
ExtendApplLimit(kMaxSize,curHeap); /* sets HEAPEND */
|
|
|
|
/* Set flag in tell allocation algorithm not to extend the heap zone */
|
|
curHeap->fHeapFullyExtended = 1;
|
|
}
|
|
return (LMSetMemErr(noErr));
|
|
}
|
|
|
|
|
|
OSErr c_MoreMasters(void)
|
|
{
|
|
stdHeap* curHeap;
|
|
OSErr theErr;
|
|
|
|
if (!IsHeap(curHeap = LMGetTheZone())) {
|
|
ClientDebugMsg("Bad heap from LowMem", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
theErr = AllocateMoreMasters(curHeap);
|
|
|
|
FlushCacheIfNeeded(curHeap);
|
|
DbgClientCheckHeap(curHeap);
|
|
return LMSetMemErr(theErr);
|
|
}
|
|
|
|
|
|
THz c_GetZone(void)
|
|
{
|
|
LMSetMemErr(noErr);
|
|
return (THz) LMGetTheZone();
|
|
}
|
|
|
|
|
|
OSErr c_SetZone(THz theZone)
|
|
{
|
|
LMSetTheZone((stdHeap*)theZone);
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
|
|
|
|
#ifdef linked_thinkc_app
|
|
/* Not in ROM */
|
|
THz c_SystemZone(void)
|
|
{
|
|
return (THz) LMGetSysZone();
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef linked_thinkc_app
|
|
/* Not in ROM */
|
|
THz c_ApplicZone(void)
|
|
{
|
|
return (THz) LMGetApplZone();
|
|
}
|
|
#endif
|
|
|
|
|
|
OSErr c_NewHandle(Handle* theHandle, ushort trapWord, Size requestedSize)
|
|
{
|
|
stdHeap* curHeap;
|
|
handleBlock* newBlock;
|
|
Handle newMasterPtr;
|
|
blockSize_t reqBlockSize;
|
|
|
|
DbgValidateTrapWord(trapWord);
|
|
if (!IsHeap(curHeap = OperateOnSysHeap(trapWord) ? LMGetSysZone() : LMGetTheZone())) {
|
|
ClientDebugMsg("Bad heap from LowMem", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
/* allocate more masters if we need too, bail if we failed */
|
|
if (curHeap->firstFreeMP == 0)
|
|
{
|
|
OSErr theErr;
|
|
|
|
/* allocate a master pointer block, if we are in the ProcessMgrHeap, allocate them
|
|
high. Did we get an error? */
|
|
if (noErr != (theErr = AllocateMoreMasters(curHeap)))
|
|
{
|
|
FlushCacheIfNeeded(curHeap);
|
|
DbgCheckHeap(curHeap);
|
|
*theHandle = nil;
|
|
return LMSetMemErr(theErr);
|
|
}
|
|
}
|
|
|
|
/* Align the requested size up to a nice multiple */
|
|
reqBlockSize = AlignUp(requestedSize + kBlockOverhead);
|
|
|
|
/* make sure size is large enough block so we can dispose it */
|
|
if (reqBlockSize < kMinFreeBlockSize)
|
|
reqBlockSize = kMinFreeBlockSize;
|
|
|
|
/* allocate new block, bail if we failed */
|
|
if (nil == (newBlock = (handleBlock *) NewBlockFast(reqBlockSize, curHeap)))
|
|
{
|
|
FlushCacheIfNeeded(curHeap);
|
|
DbgCheckHeap(curHeap);
|
|
*theHandle = nil;
|
|
return LMSetMemErr(memFullErr);
|
|
}
|
|
else
|
|
{
|
|
/* we got the mem, assign the fields */
|
|
newMasterPtr = curHeap->firstFreeMP;
|
|
|
|
/* advance firstFreeMP to next unused mp, mask off odd bit if desired */
|
|
#ifdef client_debugging
|
|
curHeap->firstFreeMP = UnmaskMPBit(*newMasterPtr);
|
|
#else
|
|
curHeap->firstFreeMP = (Ptr*)*newMasterPtr;
|
|
#endif
|
|
*newMasterPtr = (Ptr)newBlock->data;
|
|
|
|
/* set up the blocks relative handle */
|
|
newBlock->relHandle = (long)newMasterPtr - (long)curHeap;
|
|
|
|
/* set tags=relocatableType, mpFlags=0, heapID=heapID, sizeDelta=sizeDelta */
|
|
JamTagsFlagsAndSizeDelta(newBlock,
|
|
((ulong)relocatableType << 24) +
|
|
newBlock->size - requestedSize - kPsuedoBlockSize);
|
|
|
|
DbgSetBlockHeapID(newBlock, curHeap);
|
|
|
|
/* Clear the block if client desires, otherwise, fill it with garbage (debugging) */
|
|
if (ClearTheBlock(trapWord))
|
|
ClearBytes(newBlock->data, reqBlockSize - kBlockHeaderSize);
|
|
else
|
|
DbgGarbageFill(curHeap, newBlock->data, requestedSize);
|
|
|
|
/* debug stuff */
|
|
IfDbgMsg(curHeap->handleBlocks++ < 0,"corrupt header", curHeap);
|
|
DbgSetMagic(newBlock->data, requestedSize);
|
|
DbgCode(curHeap->totalDelta += newBlock->sizeDelta);
|
|
|
|
FlushCacheIfNeeded(curHeap);
|
|
DbgCheckHeap(curHeap);
|
|
*theHandle = newMasterPtr;
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
}
|
|
|
|
|
|
OSErr c_NewEmptyHandle(Handle* theHandle, ushort trapWord)
|
|
{
|
|
stdHeap* curHeap;
|
|
Handle newMasterPtr;
|
|
|
|
DbgValidateTrapWord(trapWord);
|
|
if (!IsHeap(curHeap = OperateOnSysHeap(trapWord) ? LMGetSysZone() : LMGetTheZone())) {
|
|
ClientDebugMsg("Bad heap from LowMem", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
/* allocate more masters if we need too, bail if we failed */
|
|
if (curHeap->firstFreeMP == 0)
|
|
{
|
|
OSErr theErr;
|
|
|
|
if (noErr != (theErr = AllocateMoreMasters(curHeap)))
|
|
{
|
|
FlushCacheIfNeeded(curHeap);
|
|
DbgCheckHeap(curHeap);
|
|
*theHandle = nil;
|
|
return LMSetMemErr(theErr);
|
|
}
|
|
}
|
|
|
|
/* Set up master pointer */
|
|
newMasterPtr = curHeap->firstFreeMP;
|
|
|
|
/* advance firstFreeMP to next unused mp, mask off odd bit if desired */
|
|
#ifdef client_debugging
|
|
curHeap->firstFreeMP = UnmaskMPBit(*newMasterPtr);
|
|
#else
|
|
curHeap->firstFreeMP = (Ptr*)*newMasterPtr;
|
|
#endif
|
|
*newMasterPtr = nil;
|
|
|
|
FlushCacheIfNeeded(curHeap);
|
|
DbgCheckHeap(curHeap);
|
|
*theHandle = newMasterPtr;
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
|
|
|
|
OSErr c_NewHandleHi(Handle* theHandle, ushort trapWord, Size requestedSize)
|
|
{
|
|
stdHeap* curHeap;
|
|
handleBlock* newBlock;
|
|
Handle newMasterPtr;
|
|
blockSize_t reqBlockSize;
|
|
|
|
DbgValidateTrapWord(trapWord);
|
|
if (!IsHeap(curHeap = OperateOnSysHeap(trapWord) ? LMGetSysZone() : LMGetTheZone())) {
|
|
ClientDebugMsg("Bad heap from LowMem", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
/* allocate more masters if we need too, bail if we failed */
|
|
if (curHeap->firstFreeMP == 0)
|
|
{
|
|
/* need a new master pointer block */
|
|
/* If the heap is the ProcessMgr heap, then we want to allocate master
|
|
pointer blocks high in the heap otherwise allocate low. Sorry if this is not
|
|
readable, but I save 2 local variables. Hey its C in it's purist form. */
|
|
if (noErr != AllocateMoreMasters(curHeap))
|
|
{
|
|
FlushCacheIfNeeded(curHeap);
|
|
DbgCheckHeap(curHeap);
|
|
*theHandle = nil;
|
|
return LMSetMemErr(memFullErr);
|
|
}
|
|
}
|
|
|
|
/* Align the requested size up to a nice multiple */
|
|
reqBlockSize = AlignUp(requestedSize + kBlockOverhead);
|
|
|
|
/* make sure size is large enough block so we can dispose it */
|
|
if (reqBlockSize < kMinFreeBlockSize)
|
|
reqBlockSize = kMinFreeBlockSize;
|
|
|
|
/* allocate new block, bail if we failed */
|
|
if (nil == (newBlock = (handleBlock *) NewBlock(reqBlockSize, kAllocateHigh, curHeap)))
|
|
{
|
|
FlushCacheIfNeeded(curHeap);
|
|
DbgCheckHeap(curHeap);
|
|
*theHandle = (Handle) newBlock; /* return nil for the handle */
|
|
return LMSetMemErr(memFullErr);
|
|
}
|
|
else
|
|
{
|
|
/* we got the mem, assign the fields */
|
|
newMasterPtr = curHeap->firstFreeMP;
|
|
|
|
/* advance firstFreeMP to next unused mp, mask off odd bit */
|
|
#ifdef client_debugging
|
|
curHeap->firstFreeMP = UnmaskMPBit(*newMasterPtr);
|
|
#else
|
|
curHeap->firstFreeMP = (Ptr*)*newMasterPtr;
|
|
#endif
|
|
*newMasterPtr = (Ptr)newBlock->data;
|
|
|
|
/* set up the blocks relative handle */
|
|
newBlock->relHandle = (long)newMasterPtr - (long)curHeap;
|
|
|
|
/* set tags=relocatableType, mpFlags=0, heapID=heapID, sizeDelta=sizeDelta */
|
|
JamTagsFlagsAndSizeDelta(newBlock,
|
|
((ulong)relocatableType << 24) +
|
|
newBlock->size - requestedSize - kPsuedoBlockSize);
|
|
DbgSetBlockHeapID(newBlock, curHeap);
|
|
|
|
/* Clear the block if client desires, otherwise, fill it with garbage (debugging) */
|
|
if (ClearTheBlock(trapWord))
|
|
ClearBytes(newBlock->data, reqBlockSize - kBlockHeaderSize);
|
|
else
|
|
DbgGarbageFill(curHeap, newBlock->data, requestedSize);
|
|
|
|
/* debug stuff */
|
|
IfDbgMsg(curHeap->handleBlocks++ < 0,"corrupt header", curHeap);
|
|
DbgSetMagic(newBlock->data, requestedSize);
|
|
DbgCode(curHeap->totalDelta += newBlock->sizeDelta);
|
|
|
|
FlushCacheIfNeeded(curHeap);
|
|
DbgCheckHeap(curHeap);
|
|
*theHandle = newMasterPtr;
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
}
|
|
|
|
|
|
OSErr c_DisposeHandle(Handle handle)
|
|
{
|
|
stdHeap* curHeap;
|
|
handleBlock* blockHeader; /* client's text pointer, or blockHeader */
|
|
|
|
if (handle == nil)
|
|
{
|
|
return LMSetMemErr(noErr); /* bail right away */
|
|
}
|
|
|
|
/* get pointer to client's text, is it nil? */
|
|
if (nil == (blockHeader = (void*)(*handle)))
|
|
{
|
|
/* Since the block header does not exist, can't get heap header the easy way */
|
|
if (!IsHeap(curHeap = GetZoneFromNilMP(handle))) {
|
|
ClientDebugMsg("Bad heap from Nil MP", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
if (IsReadOnlyZone(curHeap))
|
|
{
|
|
return LMSetMemErr(memROZWarn);
|
|
}
|
|
|
|
/* add the mp to the front of the free mp list */
|
|
if (curHeap->firstFreeMP != nil)
|
|
{
|
|
#ifdef client_debugging
|
|
*handle = MaskMPBitOdd(curHeap->firstFreeMP); /* to catch double disposing clients */
|
|
#else
|
|
*handle = (Ptr)(curHeap->firstFreeMP);
|
|
#endif
|
|
}
|
|
else
|
|
*handle = nil;
|
|
curHeap->firstFreeMP = handle;
|
|
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
else
|
|
{
|
|
#ifdef client_debugging
|
|
if (IsOddMP(blockHeader)) /* at this point, blockheader is the handle */
|
|
{
|
|
/*
|
|
* the client has most likely disposed of a handle twice. We return
|
|
* right away with an error. This makes apps like PixelPaint work.
|
|
* This mechanism will hopefully replace the bus error hander mechanism
|
|
* of the old MM (I hope). Note: now we rely on tag & range checking.
|
|
*/
|
|
DbgClientCheckForDisposedHandle(handle,"MP is odd, are you diposing twice?");
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
/* get the blockheader from the clients text pointer */
|
|
blockHeader = (handleBlock*) GetBlockHeaderFromPtr(blockHeader);
|
|
if (!IsHeap(curHeap = GetHeapFromHandleBlock(handle, blockHeader))) {
|
|
ClientDebugMsg("Bad heap from handle block", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
#ifndef debugNoTagChecking
|
|
/* tag field check for fake handle */
|
|
if ((((stdBlock2*)blockHeader)->tags & kPtrMask) != (uchar)relocatableType)
|
|
{
|
|
if (curHeap != ReadOnlyZone)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you disposing a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasFirstLevelFakeHandleTests
|
|
/* range check for fake handle */
|
|
if (curHeap > (stdHeap*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you disposing a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasSecondAndThirdLevelFakeHandleTests
|
|
{
|
|
stdBlock* testBlock;
|
|
|
|
/* double check to see that backLimit points back to this heap */
|
|
if ((testBlock = curHeap->backLimit) > (stdBlock*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you disposing a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
if (testBlock->parent != curHeap)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you disposing a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (IsReadOnlyZone(curHeap))
|
|
{
|
|
/*
|
|
* note: we could set the MP to nil here but we choose not to. This is part
|
|
* of our mechanism to keep the ROZ a static data structure. Nothing in the
|
|
* heap will change.
|
|
*/
|
|
return LMSetMemErr(memROZWarn);
|
|
}
|
|
|
|
DbgClientCheckHeap(curHeap);
|
|
DbgMasterPtrCheck(handle, curHeap);
|
|
|
|
/* call the dispose procedure. ProcessMgr will use it to track temp mem. Other
|
|
clients will want to use it also. */
|
|
if (curHeap->disposeProc)
|
|
{
|
|
FlushCacheIfNeeded(curHeap);
|
|
DbgCheckHeap(curHeap);
|
|
CALL_FNC_PTR_2(DisposeProcPtr,curHeap->disposeProc,uppDisposeProcInfo,handle,(THz)curHeap);
|
|
|
|
#if 0
|
|
{
|
|
callBackNodePtr listItem = curHeap->disposeProc;
|
|
/*
|
|
* This code will be turned on when the ProcessMgr is revved to call RegisterDisposeProc
|
|
* to track temporary memory instead of jamming it itself. Also have to fix
|
|
* c_RegisterDisposeProc before making this change.
|
|
*/
|
|
|
|
do
|
|
{
|
|
CALL_FNC_PTR_2(DisposeProcPtr,curHeap->disposeProc,uppDisposeProcInfo,handle,(THz)curHeap);
|
|
if (listItem = LLGetNextItem(listItem))
|
|
continue; /* there is another dispose proc to call */
|
|
else
|
|
break; /* no more dispose procs to call */
|
|
}
|
|
while(true);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* add the mp to the front of the free mp list */
|
|
if (curHeap->firstFreeMP != nil)
|
|
{
|
|
#ifdef client_debugging
|
|
*handle = MaskMPBitOdd(curHeap->firstFreeMP); /* to catch double disposing clients */
|
|
#else
|
|
*handle = (Ptr)(curHeap->firstFreeMP);
|
|
#endif
|
|
}
|
|
else
|
|
*handle = nil;
|
|
|
|
curHeap->firstFreeMP = handle;
|
|
|
|
DbgCode(curHeap->totalDelta -= (long) blockHeader->sizeDelta);
|
|
|
|
/* reset lowestRemovableBlock if needed */
|
|
if (((void*)blockHeader < curHeap->lowestRemovableBlock) &&
|
|
(IsLockedHandle(blockHeader)) &&
|
|
((void*)blockHeader > (void*)(curHeap->heapStart)))
|
|
{
|
|
curHeap->lowestRemovableBlock = blockHeader;
|
|
}
|
|
|
|
if (IsPurgableHandle(blockHeader) && IsUnlockedBlock(blockHeader))
|
|
{
|
|
curHeap->totalPurgableSpace -= blockHeader->size;
|
|
}
|
|
|
|
/* are we are disposing of a subHeap? */
|
|
if (blockHeader->subHeapBit)
|
|
{
|
|
/*
|
|
* note: This does not happen when disposing app partitions. ProcessMgr
|
|
* makes an explicit call to c_DisposeZone since it may not dispose of the
|
|
* memory but SetHandleSize on it instead.
|
|
*/
|
|
/* Remove the subheap from the heap tree */
|
|
//RemoveHeap((stdHeap*)(blockHeader->data));
|
|
RemoveHeap((Ptr)blockHeader->data, (Ptr)blockHeader + blockHeader->size);
|
|
}
|
|
|
|
KillBlock((stdBlock*)blockHeader, curHeap);
|
|
IfDbgMsg(curHeap->handleBlocks-- < 0,"corrupt header", curHeap);
|
|
|
|
DbgCheckHeap(curHeap);
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* note: since this call returns positive results (a size if the trap worked)
|
|
* and negative results (and error code if the trap failed), this trap is only
|
|
* 31 bit clean.
|
|
*/
|
|
Size c_GetHandleSize(const Handle handle)
|
|
{
|
|
handleBlock* blockHeader; /* client's text pointer, or blockHeader */
|
|
|
|
if (handle == nil)
|
|
{
|
|
return LMSetMemErr(nilHandleErr); /* bail right away */
|
|
}
|
|
|
|
/* get client's text pointer, is it nil? */
|
|
if (nil == (blockHeader = (void*)(*handle)))
|
|
{
|
|
/* we return the sign extended result code here, the MPW glue code will
|
|
force the size to be zero if the result code is negative. It does this
|
|
to make Inside Mac correct. This also applies to the memWZErr check. */
|
|
return LMSetMemErr(nilHandleErr);
|
|
}
|
|
else
|
|
{
|
|
stdHeap* curHeap;
|
|
blockSize_t theSize;
|
|
|
|
#ifdef client_debugging
|
|
if (IsOddMP(blockHeader)) /* at this point, blockheader is the handle */
|
|
{
|
|
/*
|
|
* the client has most likely disposed of this handle already. If we are debugging
|
|
* the client, we alert them of their foolishness. Otherwise, we return with
|
|
* a "block is free" error. This mechanism should replace the bus error handler
|
|
* mechism in the old MM (I hope). Note: now we rely on tag & range checking.
|
|
*/
|
|
DbgClientCheckForDisposedHandle(handle,"MP is odd, are getting size of a disposed handle?");
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
/* get block header from client's text pointer */
|
|
blockHeader = (handleBlock*) GetBlockHeaderFromPtr(blockHeader);
|
|
if (!IsHeap(curHeap = GetHeapFromHandleBlock(handle, blockHeader))) {
|
|
ClientDebugMsg("Bad heap from handle block", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
#ifndef debugNoTagChecking
|
|
/* tag field check for fake handle */
|
|
if ((((stdBlock2*)blockHeader)->tags & kPtrMask) != (uchar)relocatableType)
|
|
{
|
|
if (curHeap != ReadOnlyZone)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you getting size of a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasFirstLevelFakeHandleTests
|
|
/* range check for fake handle */
|
|
if (curHeap > (stdHeap*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you getting size of a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasSecondAndThirdLevelFakeHandleTests
|
|
{
|
|
stdBlock* testBlock;
|
|
|
|
/* double check to see that backLimit points back to this heap */
|
|
if ((testBlock = curHeap->backLimit) > (stdBlock*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you getting size of a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
if (testBlock->parent != curHeap)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you getting size of a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
DbgMasterPtrCheck(handle, curHeap);
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
theSize = blockHeader->size - blockHeader->sizeDelta - kPsuedoBlockSize;
|
|
|
|
LMSetMemErr(noErr);
|
|
return theSize;
|
|
}
|
|
}
|
|
|
|
|
|
OSErr c_SetHandleSize(Handle handle, Size requestedSize)
|
|
{
|
|
handleBlock* blockHeader; /* client's text pointer, or blockHeader */
|
|
|
|
if (handle == nil)
|
|
{
|
|
return LMSetMemErr(nilHandleErr); /* bail right away */
|
|
}
|
|
|
|
/* get clients text pointer, is it nil? */
|
|
if ((blockHeader = (void*)(*handle)) == nil)
|
|
{
|
|
return LMSetMemErr(nilHandleErr);
|
|
}
|
|
else
|
|
{
|
|
stdHeap* curHeap;
|
|
blockSize_t reqBlockSize;
|
|
Boolean blockIsPurgable;
|
|
DbgCode(short sizeDelta);
|
|
|
|
#ifdef client_debugging
|
|
if (IsOddMP(blockHeader)) /* at this point, blockheader is the handle */
|
|
{
|
|
/*
|
|
* the client has most likely disposed of a handle twice. We return
|
|
* right away with an error. This makes apps like PixelPaint work.
|
|
* This mechanism will hopefully replace the bus error hander mechanism
|
|
* of the old MM (I hope). Note: now we rely on tag & range checking.
|
|
*/
|
|
DbgClientCheckForDisposedHandle(handle,"MP is odd, are you setting size twice?");
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
/* get block header from client's text pointer */
|
|
blockHeader = (handleBlock*) GetBlockHeaderFromPtr(blockHeader);
|
|
if (!IsHeap(curHeap = GetHeapFromHandleBlock(handle, blockHeader))) {
|
|
ClientDebugMsg("Bad heap from handle block", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
DbgCode(sizeDelta = blockHeader->sizeDelta);
|
|
|
|
#ifndef debugNoTagChecking
|
|
/* tag field check for fake handle */
|
|
if ((((stdBlock2*)blockHeader)->tags & kPtrMask) != (uchar)relocatableType)
|
|
{
|
|
if (curHeap != ReadOnlyZone)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you setting size of a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasFirstLevelFakeHandleTests
|
|
/* range check for fake handle */
|
|
if (curHeap > (stdHeap*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you setting size of a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasSecondAndThirdLevelFakeHandleTests
|
|
{
|
|
stdBlock* testBlock;
|
|
|
|
/* double check to see that backLimit points back to this heap */
|
|
if ((testBlock = curHeap->backLimit) > (stdBlock*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you setting size of a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
if (testBlock->parent != curHeap)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you setting size of a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
DbgMasterPtrCheck(handle, curHeap);
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
/* Align the requested size up to a nice multiple */
|
|
reqBlockSize = AlignUp(requestedSize + kBlockOverhead);
|
|
|
|
/* make sure size is large enough block so we can dispose it */
|
|
if (reqBlockSize < kMinFreeBlockSize)
|
|
reqBlockSize = kMinFreeBlockSize;
|
|
|
|
/* can the change in size be absorbed in the delta alone? */
|
|
if (reqBlockSize == blockHeader->size)
|
|
{
|
|
/* we take the cheap way out */
|
|
blockHeader->sizeDelta = blockHeader->size - requestedSize - kPsuedoBlockSize;
|
|
DbgCode(curHeap->totalDelta += blockHeader->sizeDelta - sizeDelta);
|
|
DbgSetMagic(blockHeader->data, requestedSize);
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
|
|
/* jeff, just check for roz */
|
|
/* are we shrinking a block in the ROZ? */
|
|
if (IsReadOnlyZone(curHeap) && reqBlockSize < blockHeader->size)
|
|
{
|
|
return LMSetMemErr(memROZWarn);
|
|
}
|
|
|
|
/* If the block is purgable, mark it as non-purgable so it wont be
|
|
purged during the move. Later, we will restore the block. */
|
|
if (blockIsPurgable = IsUnlockedPurgableHandle(blockHeader))
|
|
MarkBlockNonPurgable(blockHeader, curHeap)
|
|
|
|
/* call SetBlockSize to change the size of the block */
|
|
LMSetGZRootHnd(handle); /* incase growzone proc gets called */
|
|
LMSetGZRootPtr(*handle); /* because the ptr exists (as opposed to reallocating it */
|
|
blockHeader = (handleBlock*) SetBlockSize((stdBlock*)blockHeader, reqBlockSize, curHeap);
|
|
LMSetGZRootHnd(nil);
|
|
LMSetGZRootPtr(nil);
|
|
|
|
if (blockHeader)
|
|
{
|
|
blockHeader->sizeDelta = blockHeader->size - requestedSize - kPsuedoBlockSize;
|
|
|
|
DbgCode(curHeap->totalDelta += blockHeader->sizeDelta - sizeDelta);
|
|
DbgSetMagic(blockHeader->data, requestedSize);
|
|
if (blockIsPurgable)
|
|
MarkBlockPurgable(blockHeader, curHeap);
|
|
FlushCacheIfNeeded(curHeap);
|
|
DbgCheckHeap(curHeap);
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
else
|
|
{
|
|
if (blockIsPurgable)
|
|
{
|
|
blockHeader = (handleBlock*) GetBlockHeaderFromPtr(*handle); /* re-aquire blockHeader */
|
|
MarkBlockPurgable(blockHeader, curHeap);
|
|
}
|
|
FlushCacheIfNeeded(curHeap);
|
|
DbgCheckHeap(curHeap);
|
|
return LMSetMemErr(memFullErr);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
OSErr c_HandleZone(THz* theZone, Handle handle)
|
|
{
|
|
stdHeap* curHeap;
|
|
handleBlock* blockHeader; /* client's text pointer, or blockHeader */
|
|
|
|
if (handle == nil)
|
|
{
|
|
*theZone = (THz) LMGetTheZone();
|
|
return LMSetMemErr(noErr); /* bail right away */
|
|
}
|
|
|
|
/* get clients text pointer, is it not nil? */
|
|
if (blockHeader = (void*)(*handle))
|
|
{
|
|
#ifdef client_debugging
|
|
if (IsOddMP(blockHeader)) /* at this point, blockheader is the handle */
|
|
{
|
|
/*
|
|
* the client has most likely disposed of a handle twice. We return
|
|
* right away with an error. This makes apps like PixelPaint work.
|
|
* This mechanism will hopefully replace the bus error hander mechanism
|
|
* of the old MM (I hope). Note: now we rely on tag & range checking.
|
|
*/
|
|
DbgClientCheckForDisposedHandle(handle,"MP is odd, are you working on a disposed handle?");
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
/* note: no special case code needed for the 32 bit read only zone */
|
|
blockHeader = (handleBlock*) GetBlockHeaderFromPtr(blockHeader);
|
|
if (!IsHeap(curHeap = GetHeapFromHandleBlock(handle, blockHeader))) {
|
|
ClientDebugMsg("Bad heap from handle block", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
#ifndef debugNoTagChecking
|
|
/* tag field check for fake handle */
|
|
if ((((stdBlock2*)blockHeader)->tags & kPtrMask) != (uchar)relocatableType)
|
|
{
|
|
if (curHeap != ReadOnlyZone)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you calling HandleZone on a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasFirstLevelFakeHandleTests
|
|
/* range check for fake handle */
|
|
if (curHeap > (stdHeap*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you calling HandleZone on a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasSecondAndThirdLevelFakeHandleTests
|
|
{
|
|
stdBlock* testBlock;
|
|
|
|
/* double check to see that backLimit points back to this heap */
|
|
if ((testBlock = curHeap->backLimit) > (stdBlock*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you calling HandleZone on a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
if (testBlock->parent != curHeap)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you calling HandleZone on a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
*theZone = (THz)curHeap;
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
else
|
|
{
|
|
/* Since the block header does not exist, can't get heap header the easy way */
|
|
/* *warning*, this deviates from the old MM which would return TheZone */
|
|
if (!IsHeap((stdHeap*)(*theZone = (THz)GetZoneFromNilMP(handle)))) {
|
|
ClientDebugMsg("Bad heap from nil MP", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* RecoverHandle notes....
|
|
*
|
|
* note: recover handle needs special case code to handle the ROZ
|
|
*
|
|
* Another note: Since the heap tree is real reliable, we ignor the SYS bit in
|
|
* the trap word and call FindHeap instead.
|
|
*
|
|
* The author of this code wishes to expres his opinions here. This code would be
|
|
* much easier if handle blocks had direct pointers to the zone instead of
|
|
* relative handles. Thankyou. Now back to your regularly scheduled program...
|
|
*/
|
|
Handle c_RecoverHandle(ushort trapWord, const Ptr textPtr)
|
|
{
|
|
#pragma unused(trapWord) /* this is no longer used, should remove it */
|
|
stdHeap* curHeap;
|
|
handleBlock* blockHeader;
|
|
|
|
DbgValidateTrapWord(trapWord);
|
|
IfClientDebugMsg(textPtr == nil, "textPtr is nil", textPtr);
|
|
|
|
blockHeader = (handleBlock*) GetBlockHeaderFromPtr(textPtr);
|
|
|
|
/* are we recovering a handle in ROM? */
|
|
if (IsBlockInROM(blockHeader))
|
|
{
|
|
/* set up for ReadOnlyZone */
|
|
if (!IsHeap(curHeap = ReadOnlyZone)) {
|
|
ClientDebugMsg("Bad heap from ROZ", curHeap);
|
|
LMSetMemErr(memAZErr);
|
|
return nil;
|
|
}
|
|
LMSetMemErr(memROZWarn);
|
|
}
|
|
else
|
|
{
|
|
if (nil == (curHeap = FindHeap(textPtr)))
|
|
{
|
|
/*
|
|
* We could not find a heap in the heap tree, this is real bad. Since
|
|
* we have nothing better to return, we wimp out and just return theZone.
|
|
*/
|
|
curHeap = LMGetTheZone();
|
|
}
|
|
|
|
if (!IsHeap(curHeap)) {
|
|
ClientDebugMsg("Bad heap from FindHeap or LowMem", curHeap);
|
|
LMSetMemErr(memAZErr);
|
|
return nil;
|
|
}
|
|
|
|
/* debug stuff */
|
|
DbgClientCheckHeap(curHeap);
|
|
IfClientDebugMsg(blockHeader->relHandle > ((long)curHeap->backLimit - (long)curHeap->heapStart),
|
|
"Warning: relative handle offset too big", blockHeader->relHandle);
|
|
DbgHandleBlockCheck(textPtr, curHeap);
|
|
|
|
LMSetMemErr(noErr);
|
|
}
|
|
|
|
return (Handle)(blockHeader->relHandle + (long)curHeap);
|
|
}
|
|
|
|
|
|
/*
|
|
* API notes on ReallocHandle:
|
|
*
|
|
* 1. Inside Mac states that "In case of an error, no new block is allocated and the
|
|
* handle h is left unchanged." Be very careful when reading this statement. When
|
|
* they say the handle h is left unchanged, they mean that: "the 32 bit quantity h
|
|
* remains unchanged."
|
|
*
|
|
* 2. If ReallocHandle fails with memFullErr, then h remains the same, but the block
|
|
* header and all it contents are disposed and the master pointer is set to nil.
|
|
* But hey, h is still unchanged.
|
|
*/
|
|
OSErr c_ReallocHandle(Handle theHandle, Size requestedSize)
|
|
{
|
|
stdHeap* curHeap;
|
|
handleBlock* blockHeader;
|
|
blockSize_t reqBlockSize;
|
|
Handle pMP; /* pointer to the master pointer */
|
|
|
|
if (theHandle == nil)
|
|
{
|
|
return LMSetMemErr(noErr); /* bail right away */
|
|
}
|
|
|
|
/* Align the requested size up to a nice multiple */
|
|
reqBlockSize = AlignUp(requestedSize + kBlockOverhead);
|
|
|
|
/* make sure size is large enough block so we can dispose it */
|
|
if (reqBlockSize < kMinFreeBlockSize)
|
|
reqBlockSize = kMinFreeBlockSize;
|
|
|
|
/* if the handle is not empty we must empty it first */
|
|
if (*(pMP = theHandle))
|
|
{
|
|
#ifdef client_debugging
|
|
if (IsOddMP(*pMP))
|
|
{
|
|
/*
|
|
* the client has most likely disposed of a handle twice. We return
|
|
* right away with an error. This makes apps like PixelPaint work.
|
|
* This mechanism will hopefully replace the bus error hander mechanism
|
|
* of the old MM (I hope). Note: now we rely on tag & range checking.
|
|
*/
|
|
DbgClientCheckForDisposedHandle(pMP,"MP is odd, are you reallocating a disposed handle?");
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
blockHeader = (handleBlock*) GetBlockHeaderFromPtr(*pMP);
|
|
if (!IsHeap(curHeap = GetHeapFromHandleBlock(pMP, blockHeader))) {
|
|
ClientDebugMsg("Bad heap from handle block", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
#ifndef debugNoTagChecking
|
|
/* tag field check for fake handle */
|
|
if ((((stdBlock2*)blockHeader)->tags & kPtrMask) != (uchar)relocatableType)
|
|
{
|
|
if (curHeap != ReadOnlyZone)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you reallocating a fake handle?", pMP);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasFirstLevelFakeHandleTests
|
|
/* range check for fake handle */
|
|
if (curHeap > (stdHeap*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you reallocating a fake handle?", pMP);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasSecondAndThirdLevelFakeHandleTests
|
|
{
|
|
stdBlock* testBlock;
|
|
|
|
/* double check to see that backLimit points back to this heap */
|
|
if ((testBlock = curHeap->backLimit) > (stdBlock*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you reallocating a fake handle?", pMP);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
if (testBlock->parent != curHeap)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you reallocating a fake handle?", pMP);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (IsReadOnlyZone(curHeap))
|
|
{
|
|
/* note: the old MM used to check for (reqBlockSize > blockHeader->size)
|
|
but returned the same error code (memROZError = memROZWarn). We dont
|
|
do the check at all. */
|
|
return LMSetMemErr(memROZWarn);
|
|
}
|
|
|
|
DbgMasterPtrCheck(pMP, curHeap);
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
if (IsLockedHandle(blockHeader))
|
|
{
|
|
return LMSetMemErr(memPurErr); /* purr like a cat */
|
|
}
|
|
|
|
*pMP = nil; /* set the mp to nil */
|
|
DoEmpty(blockHeader, curHeap);
|
|
}
|
|
else
|
|
{
|
|
/* Since the block header does not exist, can't get heap header the easy way */
|
|
if (!IsHeap(curHeap = GetZoneFromNilMP(pMP))) {
|
|
ClientDebugMsg("Bad heap from nil MP", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
DbgClientCheckHeap(curHeap);
|
|
}
|
|
|
|
/* incase growzone proc gets called so we dont lose the allocated MP */
|
|
/* don't set the root ptr because we are reallocating here */
|
|
LMSetGZRootHnd(pMP);
|
|
blockHeader = (handleBlock *) NewBlockFast(reqBlockSize, curHeap);
|
|
LMSetGZRootHnd(nil);
|
|
|
|
/* allocate new block, bail if we failed */
|
|
if (nil == blockHeader)
|
|
{
|
|
//*theHandle = nil; /* return nil for the handle */
|
|
FlushCacheIfNeeded(curHeap);
|
|
DbgCheckHeap(curHeap);
|
|
return LMSetMemErr(memFullErr);
|
|
}
|
|
else
|
|
{
|
|
/* we got the mem, assign the fields */
|
|
|
|
/* set up the blocks relative handle */
|
|
blockHeader->relHandle = (long)pMP - (long)curHeap;
|
|
|
|
*pMP = (Ptr) blockHeader->data; /* point the MP to the clients text */
|
|
|
|
/* set tags=relocatableType, mpFlags=0, heapID=0, sizeDelta=sizeDelta */
|
|
JamTagsFlagsAndSizeDelta(blockHeader,
|
|
((ulong)relocatableType << 24) +
|
|
blockHeader->size - requestedSize - kPsuedoBlockSize);
|
|
DbgSetBlockHeapID(blockHeader, curHeap);
|
|
|
|
IfDbgMsg(curHeap->handleBlocks++ < 0,"corrupt header", curHeap);
|
|
DbgGarbageFill(curHeap, blockHeader->data, requestedSize);
|
|
DbgSetMagic(blockHeader->data, requestedSize);
|
|
DbgCode(curHeap->totalDelta += blockHeader->sizeDelta);
|
|
|
|
FlushCacheIfNeeded(curHeap);
|
|
DbgCheckHeap(curHeap);
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
}
|
|
|
|
|
|
OSErr c_NewPtr(Ptr* thePtr, ushort trapWord, Size requestedSize)
|
|
{
|
|
stdHeap* curHeap;
|
|
ptrBlock* newBlock;
|
|
blockSize_t reqBlockSize;
|
|
|
|
/* Align the requested size up to a nice multiple */
|
|
reqBlockSize = AlignUp(requestedSize + kBlockOverhead);
|
|
|
|
/* make sure size is large enough block so we can dispose it */
|
|
if (reqBlockSize < kMinFreeBlockSize)
|
|
reqBlockSize = kMinFreeBlockSize;
|
|
|
|
DbgValidateTrapWord(trapWord);
|
|
if (!IsHeap(curHeap = OperateOnSysHeap(trapWord) ? LMGetSysZone() : LMGetTheZone())) {
|
|
ClientDebugMsg("Bad heap from LowMem", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
DbgCheckForProcessMgrHeap(curHeap);
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
/* allocate the block, if we are in the process mgr heap, allocate the block high */
|
|
if (nil == (newBlock = NewBlock(reqBlockSize, kAllocateLow, curHeap)))
|
|
{
|
|
/* allocation failed */
|
|
|
|
FlushCacheIfNeeded(curHeap);
|
|
DbgCheckHeap(curHeap);
|
|
*thePtr = nil;
|
|
return LMSetMemErr(memFullErr);
|
|
}
|
|
else
|
|
{
|
|
/* allocation worked */
|
|
newBlock->parent = curHeap;
|
|
|
|
/* set tags=ptrType, mpFlags=0, heapID=0, sizeDelta=sizeDelta */
|
|
JamTagsFlagsAndSizeDelta(newBlock,
|
|
((ulong)ptrType << 24) +
|
|
newBlock->size - requestedSize - kPsuedoBlockSize);
|
|
DbgSetBlockHeapID(newBlock, curHeap);
|
|
|
|
/* reset lowestRemovableBlock */
|
|
if (curHeap->lowestRemovableBlock == newBlock)
|
|
curHeap->lowestRemovableBlock = WalkUpFindNewLowRemoveable(newBlock, curHeap);
|
|
|
|
/* Clear the block if client desires, otherwise, fill it with garbage (debugging) */
|
|
if (ClearTheBlock(trapWord))
|
|
ClearBytes(newBlock->data, reqBlockSize - kBlockHeaderSize);
|
|
else
|
|
DbgGarbageFill(curHeap, newBlock->data, requestedSize);
|
|
|
|
DbgSetMagic(newBlock->data, requestedSize);
|
|
DbgCode(curHeap->totalDelta += newBlock->sizeDelta);
|
|
IfDbgMsg(curHeap->ptrBlocks++ < 0,"corrupt header", curHeap);
|
|
|
|
FlushCacheIfNeeded(curHeap);
|
|
DbgCheckHeap(curHeap);
|
|
*thePtr = (Ptr)newBlock->data;
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
}
|
|
|
|
|
|
OSErr c_DisposePtr(Ptr block)
|
|
{
|
|
if (block)
|
|
{
|
|
ptrBlock* blockHeader = (ptrBlock*)GetBlockHeaderFromPtr(block);
|
|
stdHeap* curHeap;
|
|
freeBlock* lowBlockFreed;
|
|
|
|
if (!IsHeap(curHeap = blockHeader->parent)) {
|
|
ClientDebugMsg("Bad heap from block header", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
/* is this block already free */
|
|
if (IsFreeBlock(blockHeader))
|
|
{
|
|
/*
|
|
* PageMaker has a translator (for MS Word) that calls DisposePtr
|
|
* twice on the same block of memory.
|
|
*/
|
|
ClientDebugMsg("Bad ptr block, are you disposing a free block?", block);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
|
|
#ifndef debugNoTagChecking
|
|
/* tag field check for fake ptr */
|
|
if (((stdBlock2*)blockHeader)->tags != (uchar)ptrType)
|
|
{
|
|
ClientDebugMsg("Bad ptr block, are you disposing a fake pointer?", block);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
if (IsReadOnlyZone(curHeap))
|
|
{
|
|
return LMSetMemErr(memROZWarn);
|
|
}
|
|
|
|
DbgCheckForProcessMgrHeap(curHeap);
|
|
DbgClientCheckHeap(curHeap);
|
|
DbgPtrBlockCheck(block, curHeap);
|
|
DbgCode(curHeap->totalDelta -= (long) blockHeader->sizeDelta);
|
|
|
|
/* are we are disposing of a subHeap? */
|
|
if (blockHeader->subHeapBit)
|
|
{
|
|
/* Remove the subheap from the heap tree */
|
|
//RemoveHeap((stdHeap*)block);
|
|
RemoveHeap((Ptr)blockHeader->data, (Ptr)blockHeader + blockHeader->size);
|
|
}
|
|
|
|
lowBlockFreed = KillBlock(blockHeader, curHeap);
|
|
|
|
/*
|
|
* This is a fix for the wierd case where clients are disposing a ptr
|
|
* twice AND the the block is backwards coelesced. We saw this with the
|
|
* ever popular app, A-Train.
|
|
*/
|
|
((stdBlock2*)blockHeader)->tags = 0; /* old blockheader is now a free block */
|
|
|
|
/* are we disposing a block lower than the lowestRemovableBlock in the main fragment? */
|
|
#ifndef implemented_discontiguous_heaps
|
|
if ((void*)lowBlockFreed < curHeap->lowestRemovableBlock)
|
|
curHeap->lowestRemovableBlock = lowBlockFreed;
|
|
#else
|
|
if (((void*)lowBlockFreed < curHeap->lowestRemovableBlock) && ((void*)lowBlockFreed >= (void*)(curHeap->heapStart)))
|
|
curHeap->lowestRemovableBlock = lowBlockFreed;
|
|
#endif
|
|
|
|
IfDbgMsg(--curHeap->ptrBlocks < 0,"corrupt header", curHeap);
|
|
DbgCheckHeap(curHeap);
|
|
}
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
|
|
|
|
/*
|
|
* Note: since the original call returns positive results through D0 and negative
|
|
* results through D0, this trap is only 31 bit clean.
|
|
*
|
|
* Note2: if this routine returns and error, the glue in Interface.o will force
|
|
* D0 to be zero. So we don't need to do it here lest we mess things up for
|
|
* assembly language programmers who are depending on the error code being in D0.
|
|
*
|
|
* Note3: no special case code needed for the 32 bit read only zone.
|
|
*/
|
|
Size c_GetPtrSize(const Ptr block)
|
|
{
|
|
ptrBlock* blockHeader = (ptrBlock*)GetBlockHeaderFromPtr(block);
|
|
#ifdef debugging
|
|
stdHeap* curHeap = blockHeader->parent;
|
|
#endif
|
|
|
|
IfClientDebugMsg(block == nil, "GetPtrSize on a nil ptr", 0);
|
|
|
|
/* is this block already free */
|
|
if (IsFreeBlock(blockHeader))
|
|
{
|
|
ClientDebugMsg("Bad ptr block, are you getting size of a free block?", block);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
|
|
#ifndef debugNoTagChecking
|
|
/* tag field check for fake ptr */
|
|
if (((stdBlock2*)blockHeader)->tags != (uchar)ptrType)
|
|
{
|
|
ClientDebugMsg("Bad ptr block, are you getting size of a fake pointer?", block);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
#endif
|
|
|
|
DbgCheckForProcessMgrHeap(curHeap);
|
|
DbgClientCheckHeap(curHeap);
|
|
DbgPtrBlockCheck(block, curHeap);
|
|
|
|
LMSetMemErr(noErr);
|
|
return blockHeader->size - kPsuedoBlockSize - blockHeader->sizeDelta;
|
|
}
|
|
|
|
|
|
OSErr c_SetPtrSize(Ptr block, Size requestedSize)
|
|
{
|
|
ptrBlock* blockHeader = (ptrBlock*) GetBlockHeaderFromPtr(block);
|
|
stdHeap* curHeap;
|
|
blockSize_t reqBlockSize;
|
|
OSErr theErr;
|
|
Boolean setLRB; /* true => must set lowestRemovableBlock */
|
|
#ifdef debugging
|
|
short sizeDelta = blockHeader->sizeDelta;
|
|
#endif
|
|
|
|
if (!IsHeap(curHeap = blockHeader->parent)) {
|
|
ClientDebugMsg("Bad heap from block header", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
IfClientDebugMsg(block == nil, "SetPtrSize on a nil ptr", 0);
|
|
|
|
/* is this block already free */
|
|
if (IsFreeBlock(blockHeader))
|
|
{
|
|
ClientDebugMsg("Bad ptr block, are you setting size of a free block?", block);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
|
|
#ifndef debugNoTagChecking
|
|
/* tag field check for fake ptr */
|
|
if (((stdBlock2*)blockHeader)->tags != (uchar)ptrType)
|
|
{
|
|
ClientDebugMsg("Bad ptr block, are you setting size of a fake pointer?", block);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
#endif
|
|
|
|
DbgCheckForProcessMgrHeap(curHeap);
|
|
DbgClientCheckHeap(curHeap);
|
|
DbgPtrBlockCheck(block, curHeap);
|
|
|
|
/* Align the requested size up to a nice multiple */
|
|
reqBlockSize = AlignUp(requestedSize + kBlockOverhead);
|
|
|
|
/* make sure size is large enough block so we can dispose it */
|
|
if (reqBlockSize < kMinFreeBlockSize)
|
|
reqBlockSize = kMinFreeBlockSize;
|
|
|
|
/* can the change in size be absorbed in the delta alone? */
|
|
if (reqBlockSize == blockHeader->size)
|
|
{
|
|
/* we take the cheap way out */
|
|
blockHeader->sizeDelta = blockHeader->size - requestedSize - kPsuedoBlockSize;
|
|
|
|
DbgCode(curHeap->totalDelta += blockHeader->sizeDelta - sizeDelta);
|
|
DbgSetMagic(blockHeader->data, requestedSize);
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
|
|
/* are we shrinking a block in the ROZ? */
|
|
if (IsReadOnlyZone(curHeap) && reqBlockSize < blockHeader->size)
|
|
{
|
|
return LMSetMemErr(memROZWarn);
|
|
}
|
|
|
|
setLRB = (curHeap->lowestRemovableBlock == GetNextBlock(blockHeader));
|
|
|
|
/* call SetBlockSize to change the size of the block */
|
|
LMSetGZRootPtr(block); /* incase growzone proc gets called */
|
|
blockHeader = SetBlockSize(blockHeader, reqBlockSize, curHeap);
|
|
LMSetGZRootPtr(nil);
|
|
|
|
if (blockHeader)
|
|
{
|
|
blockHeader->sizeDelta = blockHeader->size - requestedSize - kPsuedoBlockSize;
|
|
if (setLRB)
|
|
curHeap->lowestRemovableBlock = WalkUpFindNewLowRemoveable(blockHeader, curHeap);
|
|
|
|
DbgCode(curHeap->totalDelta += blockHeader->sizeDelta - sizeDelta);
|
|
DbgSetMagic(blockHeader->data, requestedSize);
|
|
theErr = noErr;
|
|
}
|
|
else
|
|
{
|
|
theErr = memFullErr;
|
|
}
|
|
|
|
FlushCacheIfNeeded(curHeap);
|
|
DbgCheckHeap(curHeap);
|
|
return LMSetMemErr(theErr);
|
|
}
|
|
|
|
|
|
OSErr c_PtrZone(THz* theZone, Ptr thePtr)
|
|
{
|
|
ptrBlock* blockHeader = (ptrBlock*) GetBlockHeaderFromPtr(thePtr);
|
|
stdHeap* curHeap;
|
|
|
|
if (!IsHeap(curHeap = blockHeader->parent)) {
|
|
ClientDebugMsg("Bad heap from block header", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
IfClientDebugMsg(thePtr == nil,"PtrZone on a nil ptr",0);
|
|
|
|
/* is this block already free */
|
|
if (IsFreeBlock(blockHeader))
|
|
{
|
|
ClientDebugMsg("Bad ptr block, are you calling PtrZone on a free block?", thePtr);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
|
|
#ifndef debugNoTagChecking
|
|
/* tag field check for fake ptr */
|
|
if (((stdBlock2*)blockHeader)->tags != (uchar)ptrType)
|
|
{
|
|
ClientDebugMsg("Bad ptr block, are you calling PtrZone on a fake pointer?", thePtr);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
#endif
|
|
|
|
DbgCheckForProcessMgrHeap(curHeap);
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
*theZone = (THz)curHeap;
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
|
|
|
|
long c_FreeMem(ushort trapWord)
|
|
{
|
|
stdHeap* curHeap;
|
|
|
|
/*
|
|
* This returns the physical block size (clientSize + header + sizeDelta) instead of
|
|
* logical size. As stupid as this sounds, that is exactly what the old MM returns.
|
|
* Although the new blockHeader sizes are now 16 bytes as opposed to 12, I don't think
|
|
* this will break anyone. An alternative way to fix this is to walk all the free blocks
|
|
* and accumulate the logical free size. I choose not to do this. Yet anthother way to
|
|
* get the right size is to convert physical to logical size inside all the internal
|
|
* routines that set curHeap->totalFree. I choose not to this since it takes to much
|
|
* time. So the best thing to do is to return the not quite correct physical free size
|
|
* of the heap instead of the logical size.
|
|
|
|
* Just for more safety, I subtract off the block header size to make the figure
|
|
* a little more closer to reality.
|
|
*/
|
|
|
|
DbgValidateTrapWord(trapWord);
|
|
curHeap = OperateOnSysHeap(trapWord) ? LMGetSysZone() : LMGetTheZone();
|
|
DbgClientCheckHeap(curHeap);
|
|
LMSetMemErr(noErr);
|
|
return curHeap->totalFree ? (curHeap->totalFree - kBlockOverhead) : 0;
|
|
}
|
|
|
|
|
|
Size c_MaxMem(ushort trapWord, Size *growSize)
|
|
{
|
|
stdHeap* curHeap;
|
|
freeBlock* free;
|
|
|
|
DbgValidateTrapWord(trapWord);
|
|
curHeap = OperateOnSysHeap(trapWord) ? LMGetSysZone() : LMGetTheZone();
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
free = PurgeAndCompactHeap(curHeap);
|
|
|
|
if (IsAppHeap(curHeap))
|
|
{
|
|
/* jeff, warning, the old MM returns the MIN(ApplLimit,(SP-MinStack))
|
|
might want to consider this feature. */
|
|
*growSize = LMGetApplLimit() - (Ptr) curHeap->backLimit - curHeap->backLimit->size;
|
|
}
|
|
else
|
|
*growSize = 0;
|
|
|
|
FlushCacheIfNeeded(curHeap);
|
|
DbgCheckHeap(curHeap);
|
|
LMSetMemErr(noErr);
|
|
|
|
return free->size ? (free->size - kBlockOverhead) : 0;
|
|
}
|
|
|
|
|
|
Size c_CompactMem(ushort trapWord, Size sizeNeeded)
|
|
{
|
|
stdHeap* curHeap;
|
|
blockSize_t reqBlockSize;
|
|
freeBlock* largestBlock;
|
|
|
|
/* Align the sizeNeeded size up to a nice multiple */
|
|
reqBlockSize = AlignUp(sizeNeeded + kBlockOverhead);
|
|
|
|
/* make sure size is large enough block so we can dispose it */
|
|
if (reqBlockSize < kMinFreeBlockSize)
|
|
reqBlockSize = kMinFreeBlockSize;
|
|
|
|
DbgValidateTrapWord(trapWord);
|
|
curHeap = OperateOnSysHeap(trapWord) ? LMGetSysZone() : LMGetTheZone();
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
LMSetMemErr(noErr);
|
|
|
|
largestBlock = CompactHeap(reqBlockSize, curHeap);
|
|
|
|
FlushCacheIfNeeded(curHeap);
|
|
DbgCheckHeap(curHeap);
|
|
|
|
return largestBlock->size ? (largestBlock->size - kBlockOverhead) : 0;
|
|
}
|
|
|
|
|
|
OSErr c_ReserveMem(ushort trapWord, Size sizeNeeded)
|
|
{
|
|
stdHeap* curHeap;
|
|
blockSize_t reqBlockSize ;
|
|
freeBlock* free;
|
|
OSErr theErr;
|
|
|
|
/* Align the sizeNeeded size up to a nice multiple */
|
|
reqBlockSize = AlignUp(sizeNeeded + kBlockOverhead);
|
|
|
|
/* make sure size is large enough block so we can dispose it */
|
|
if (reqBlockSize < kMinFreeBlockSize)
|
|
reqBlockSize = kMinFreeBlockSize;
|
|
|
|
DbgValidateTrapWord(trapWord);
|
|
curHeap = OperateOnSysHeap(trapWord) ? LMGetSysZone() : LMGetTheZone();
|
|
DbgCheckForProcessMgrHeap(curHeap);
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
/* allocate more masters if we need too, bail if we failed */
|
|
if (curHeap->firstFreeMP == 0)
|
|
{
|
|
/* allocate a master pointer block, if we are in the ProcessMgrHeap, allocate them
|
|
high. Did we get an error? */
|
|
if (noErr != (theErr = AllocateMoreMasters(curHeap)))
|
|
{
|
|
FlushCacheIfNeeded(curHeap);
|
|
DbgCheckHeap(curHeap);
|
|
return LMSetMemErr(theErr);
|
|
}
|
|
}
|
|
|
|
if (nil == (free = MakeSpaceLow(reqBlockSize, kAllocateLow, curHeap)))
|
|
{
|
|
theErr = LMSetMemErr(memFullErr);
|
|
}
|
|
else
|
|
{
|
|
curHeap->favoredFree = free;
|
|
theErr = LMSetMemErr(noErr);
|
|
}
|
|
|
|
FlushCacheIfNeeded(curHeap);
|
|
DbgCheckHeap(curHeap);
|
|
return theErr;
|
|
}
|
|
|
|
|
|
OSErr c_PurgeMem(ushort trapWord, Size sizeNeeded)
|
|
{
|
|
stdHeap* curHeap;
|
|
freeBlock* free;
|
|
OSErr theErr;
|
|
|
|
DbgValidateTrapWord(trapWord);
|
|
curHeap = OperateOnSysHeap(trapWord) ? LMGetSysZone() : LMGetTheZone();
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
/* Align the sizeNeeded size up to a nice multiple */
|
|
sizeNeeded = AlignUp(sizeNeeded + kBlockOverhead);
|
|
|
|
/* make sure size is large enough block so we can dispose it */
|
|
if (sizeNeeded < kMinFreeBlockSize)
|
|
sizeNeeded = kMinFreeBlockSize;
|
|
|
|
free = PurgeAndMakeSpace(sizeNeeded, curHeap, true);
|
|
if (free->size >= sizeNeeded)
|
|
theErr = LMSetMemErr(noErr);
|
|
else
|
|
theErr = LMSetMemErr(memFullErr);
|
|
|
|
FlushCacheIfNeeded(curHeap);
|
|
DbgCheckHeap(curHeap);
|
|
|
|
return theErr;
|
|
}
|
|
|
|
|
|
OSErr c_EmptyHandle(Handle handle)
|
|
{
|
|
stdHeap* curHeap;
|
|
handleBlock* blockHeader; /* client's text pointer, or blockHeader */
|
|
|
|
if (handle == nil)
|
|
{
|
|
return LMSetMemErr(noErr); /* bail right away */
|
|
}
|
|
|
|
/* get client's text pointer, is it not nil? */
|
|
if (blockHeader = (void*)(*handle))
|
|
{
|
|
#ifdef client_debugging
|
|
if (IsOddMP(blockHeader)) /* at this point, blockheader is the handle */
|
|
{
|
|
/*
|
|
* the client has most likely disposed of a handle twice. We return
|
|
* right away with an error. This makes apps like PixelPaint work.
|
|
* This mechanism will hopefully replace the bus error hander mechanism
|
|
* of the old MM (I hope). Note: now we rely on tag & range checking.
|
|
*/
|
|
DbgClientCheckForDisposedHandle(handle,"MP is odd, are you emptying a disposed handle?");
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
/* get block header from clients text pointer */
|
|
blockHeader = (handleBlock*) GetBlockHeaderFromPtr(blockHeader);
|
|
if (!IsHeap(curHeap = GetHeapFromHandleBlock(handle, blockHeader))) {
|
|
ClientDebugMsg("Bad heap from block header", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
#ifndef debugNoTagChecking
|
|
/* tag field check for fake handle */
|
|
if ((((stdBlock2*)blockHeader)->tags & kPtrMask) != (uchar)relocatableType)
|
|
{
|
|
if (curHeap != ReadOnlyZone)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you emptying a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasFirstLevelFakeHandleTests
|
|
/* range check for fake handle */
|
|
if (curHeap > (stdHeap*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you emptying a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasSecondAndThirdLevelFakeHandleTests
|
|
{
|
|
stdBlock* testBlock;
|
|
|
|
/* double check to see that backLimit points back to this heap */
|
|
if ((testBlock = curHeap->backLimit) > (stdBlock*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you emptying a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
if (testBlock->parent != curHeap)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you emptying a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
DbgMasterPtrCheck(handle, curHeap);
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
if (IsLockedHandle(blockHeader))
|
|
{
|
|
return LMSetMemErr(memPurErr);
|
|
}
|
|
|
|
if (IsReadOnlyZone(curHeap))
|
|
{
|
|
*handle = nil; /* zero the master pointer */
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
|
|
*handle = nil; /* set the mp to nil */
|
|
DoEmpty(blockHeader, curHeap);
|
|
|
|
DbgCheckHeap(curHeap);
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
else
|
|
{
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
}
|
|
|
|
|
|
OSErr c_HLock(Handle handle)
|
|
{
|
|
stdHeap* curHeap;
|
|
handleBlock* blockHeader; /* client's text pointer, or blockHeader */
|
|
|
|
if (handle == nil)
|
|
{
|
|
return LMSetMemErr(nilHandleErr); /* bail right away */
|
|
}
|
|
|
|
/* get client's text pointer, is it not nil? */
|
|
if (blockHeader = (void*)(*handle))
|
|
{
|
|
#ifdef client_debugging
|
|
if (IsOddMP(blockHeader)) /* at this point, blockheader is the handle */
|
|
{
|
|
/*
|
|
* the client has most likely disposed of this handle already. If we are debugging
|
|
* the client, we alert them of their foolishness. Otherwise, we return with
|
|
* a "block is free" error. This mechanism should replace the bus error handler
|
|
* mechism in the old MM (I hope). Note: now we rely on tag & range checking.
|
|
*/
|
|
DbgClientCheckForDisposedHandle(handle,"MP is odd, are you locking a disposed handle?");
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
/* get block header from client's text pointer */
|
|
blockHeader = (handleBlock*) GetBlockHeaderFromPtr(blockHeader);
|
|
if (!IsHeap(curHeap = GetHeapFromHandleBlock(handle, blockHeader))) {
|
|
ClientDebugMsg("Bad heap from block header", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
#ifndef debugNoTagChecking
|
|
/* tag field check for fake handle */
|
|
if ((((stdBlock2*)blockHeader)->tags & kPtrMask) != (uchar)relocatableType)
|
|
{
|
|
if (curHeap != ReadOnlyZone)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you locking a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasFirstLevelFakeHandleTests
|
|
/* range check for fake handle */
|
|
if (curHeap > (stdHeap*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you locking a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasSecondAndThirdLevelFakeHandleTests
|
|
{
|
|
stdBlock* testBlock;
|
|
|
|
/* double check to see that backLimit points back to this heap */
|
|
if ((testBlock = curHeap->backLimit) > (stdBlock*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you locking a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
if (testBlock->parent != curHeap)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you locking a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (IsReadOnlyZone(curHeap))
|
|
{
|
|
/* ResourceMgr likes to lock the resource map in the Read Only Zone */
|
|
if (IsBlockInROM(blockHeader))
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
|
|
IfClientDebugMsg(IsPtrBlock(blockHeader),"not a valid handle", handle);
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
/* if client is locking a purgable block, adjust totalPurgableSpace */
|
|
if (IsPurgableHandle(blockHeader) && IsUnlockedHandle(blockHeader))
|
|
curHeap->totalPurgableSpace -= blockHeader->size;
|
|
|
|
blockHeader->lockBit = 1; /* set locked bit */
|
|
|
|
/* reset lowestRemovableBlock */
|
|
if (curHeap->lowestRemovableBlock == blockHeader)
|
|
curHeap->lowestRemovableBlock = WalkUpFindNewLowRemoveable((stdBlock*)blockHeader, curHeap);
|
|
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
else
|
|
{
|
|
return LMSetMemErr(nilHandleErr);
|
|
}
|
|
}
|
|
|
|
|
|
OSErr c_HUnlock(Handle handle)
|
|
{
|
|
stdHeap* curHeap;
|
|
handleBlock* blockHeader; /* client's text pointer, or blockHeader */
|
|
|
|
if (handle == nil)
|
|
{
|
|
return LMSetMemErr(nilHandleErr); /* bail right away */
|
|
}
|
|
|
|
/* get client's text pointer, is it not nil? */
|
|
if (blockHeader = (void*)(*handle))
|
|
{
|
|
#ifdef client_debugging
|
|
if (IsOddMP(blockHeader)) /* at this point, blockheader is the handle */
|
|
{
|
|
/*
|
|
* the client has most likely disposed of this handle already. If we are debugging
|
|
* the client, we alert them of their foolishness. Otherwise, we return with
|
|
* a "block is free" error. This mechanism should replace the bus error handler
|
|
* mechism in the old MM (I hope). Note: now we rely on tag & range checking.
|
|
*/
|
|
DbgClientCheckForDisposedHandle(handle,"MP is odd, are you unlocking a disposed handle?");
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
/* get block header from client's text pointer */
|
|
blockHeader = (handleBlock*) GetBlockHeaderFromPtr(blockHeader);
|
|
if (!IsHeap(curHeap = GetHeapFromHandleBlock(handle, blockHeader))) {
|
|
ClientDebugMsg("Bad heap from block header", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
#ifndef debugNoTagChecking
|
|
/* tag field check for fake handle */
|
|
if ((((stdBlock2*)blockHeader)->tags & kPtrMask) != (uchar)relocatableType)
|
|
{
|
|
if (curHeap != ReadOnlyZone)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you unlocking a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasFirstLevelFakeHandleTests
|
|
/* range check for fake handle */
|
|
if (curHeap > (stdHeap*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you unlocking a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasSecondAndThirdLevelFakeHandleTests
|
|
{
|
|
stdBlock* testBlock;
|
|
|
|
/* double check to see that backLimit points back to this heap */
|
|
if ((testBlock = curHeap->backLimit) > (stdBlock*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you unlocking a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
if (testBlock->parent != curHeap)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you unlocking a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (IsReadOnlyZone(curHeap))
|
|
{
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
|
|
IfClientDebugMsg(IsPtrBlock(blockHeader),"not a valid handle", handle);
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
/* if client is unlocking a purgable block, adjust totalPurgableSpace */
|
|
if (IsPurgableHandle(blockHeader) && IsLockedHandle(blockHeader))
|
|
curHeap->totalPurgableSpace += blockHeader->size;
|
|
|
|
blockHeader->lockBit = 0; /* clear locked bit */
|
|
|
|
/* resest lowestRemoveableBlock */
|
|
if (((void*)blockHeader < curHeap->lowestRemovableBlock) && ((void*)blockHeader > (void*)(curHeap->heapStart)))
|
|
curHeap->lowestRemovableBlock = blockHeader;
|
|
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
else
|
|
{
|
|
return LMSetMemErr(nilHandleErr);
|
|
}
|
|
}
|
|
|
|
|
|
OSErr c_HPurge(Handle handle)
|
|
{
|
|
stdHeap* curHeap;
|
|
handleBlock* blockHeader; /* client's text pointer, or blockHeader */
|
|
|
|
if (handle == nil)
|
|
{
|
|
return LMSetMemErr(nilHandleErr); /* bail right away */
|
|
}
|
|
|
|
/* get client's text pointer, is it not nil? */
|
|
if (blockHeader = (void*)(*handle))
|
|
{
|
|
#ifdef client_debugging
|
|
if (IsOddMP(blockHeader)) /* at this point, blockheader is the handle */
|
|
{
|
|
/*
|
|
* the client has most likely disposed of this handle already. If we are debugging
|
|
* the client, we alert them of their foolishness. Otherwise, we return with
|
|
* a "block is free" error. This mechanism should replace the bus error handler
|
|
* mechism in the old MM (I hope). Note: now we rely on tag & range checking.
|
|
*/
|
|
DbgClientCheckForDisposedHandle(handle,"MP is odd, are you HPurging a disposed handle?");
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
/* get block header from client's text pointer */
|
|
blockHeader = (handleBlock*) GetBlockHeaderFromPtr(blockHeader);
|
|
if (!IsHeap(curHeap = GetHeapFromHandleBlock(handle, blockHeader))) {
|
|
ClientDebugMsg("Bad heap from block header", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
#ifndef debugNoTagChecking
|
|
/* tag field check for fake handle */
|
|
if ((((stdBlock2*)blockHeader)->tags & kPtrMask) != (uchar)relocatableType)
|
|
{
|
|
if (curHeap != ReadOnlyZone)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you HPurging a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasFirstLevelFakeHandleTests
|
|
/* range check for fake handle */
|
|
if (curHeap > (stdHeap*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you HPurging a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasSecondAndThirdLevelFakeHandleTests
|
|
{
|
|
stdBlock* testBlock;
|
|
|
|
/* double check to see that backLimit points back to this heap */
|
|
if ((testBlock = curHeap->backLimit) > (stdBlock*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you HPurging a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
if (testBlock->parent != curHeap)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you HPurging a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (IsReadOnlyZone(curHeap))
|
|
{
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
|
|
IfClientDebugMsg(IsPtrBlock(blockHeader),"not a valid handle", handle);
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
MarkBlockPurgable(blockHeader,curHeap);
|
|
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
else
|
|
{
|
|
return LMSetMemErr(nilHandleErr);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
OSErr c_HNoPurge(Handle handle)
|
|
{
|
|
stdHeap* curHeap;
|
|
handleBlock* blockHeader; /* client's text pointer, or blockHeader */
|
|
|
|
if (handle == nil)
|
|
{
|
|
return LMSetMemErr(nilHandleErr); /* bail right away */
|
|
}
|
|
|
|
/* get client's text pointer, is it not nil? */
|
|
if (blockHeader = (void*)(*handle))
|
|
{
|
|
#ifdef client_debugging
|
|
if (IsOddMP(blockHeader)) /* at this point, blockheader is the handle */
|
|
{
|
|
/*
|
|
* the client has most likely disposed of this handle already. If we are debugging
|
|
* the client, we alert them of their foolishness. Otherwise, we return with
|
|
* a "block is free" error. This mechanism should replace the bus error handler
|
|
* mechism in the old MM (I hope). Note: now we rely on tag & range checking.
|
|
*/
|
|
DbgClientCheckForDisposedHandle(handle,"MP is odd, are you HNopurging a disposed handle?");
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
/* get block header from client's text pointer */
|
|
blockHeader = (handleBlock*) GetBlockHeaderFromPtr(blockHeader);
|
|
if (!IsHeap(curHeap = GetHeapFromHandleBlock(handle, blockHeader))) {
|
|
ClientDebugMsg("Bad heap from block header", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
#ifndef debugNoTagChecking
|
|
/* tag field check for fake handle */
|
|
if ((((stdBlock2*)blockHeader)->tags & kPtrMask) != (uchar)relocatableType)
|
|
{
|
|
if (curHeap != ReadOnlyZone)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you HNopurging a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasFirstLevelFakeHandleTests
|
|
/* range check for fake handle */
|
|
if (curHeap > (stdHeap*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you HNopurging a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasSecondAndThirdLevelFakeHandleTests
|
|
{
|
|
stdBlock* testBlock;
|
|
|
|
/* double check to see that backLimit points back to this heap */
|
|
if ((testBlock = curHeap->backLimit) > (stdBlock*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you HNopurging a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
if (testBlock->parent != curHeap)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you HNopurging a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (IsReadOnlyZone(curHeap))
|
|
{
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
|
|
IfClientDebugMsg(IsPtrBlock(blockHeader),"not a valid handle", handle);
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
MarkBlockNonPurgable(blockHeader,curHeap);
|
|
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
else
|
|
{
|
|
return LMSetMemErr(nilHandleErr);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* ProcessMgr patches the old SetGrowZone routine so 1) It can save the gzProc as
|
|
* part of the app's pcb chain it to its own gzProc. 2) so apps can not change the
|
|
* gzProc for the system heap or the processMgr heap and 3) to prevent apps from
|
|
* restoring the ProcessMgr gzProc.
|
|
*/
|
|
OSErr c_SetGrowZone(GrowZoneProcPtr theGrowZoneProc)
|
|
{
|
|
stdHeap* curHeap;
|
|
|
|
/* ProcessMgr prevents apps from setting the grow zone of the system heap. This is to
|
|
stop skanky apps that want to hang off the system grow zone proc. */
|
|
if ( (curHeap = LMGetTheZone()) != LMGetSysZone())
|
|
curHeap->gzProc = theGrowZoneProc;
|
|
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
|
|
|
|
#if defined(linked_thinkc_app)
|
|
/* Not in ROM */
|
|
Handle c_GZSaveHnd(void)
|
|
{
|
|
return gGZROOTHND;
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
Figment does not implement BlockMove()
|
|
*/
|
|
|
|
|
|
#if defined(linked_thinkc_app)
|
|
/* not in ROM */
|
|
Ptr c_TopMem(void)
|
|
{
|
|
return nil; /* jeff, figure what to return here */
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
* Moves a handle high. Currently, the new implementation of MoveHHi differs from the old
|
|
* one in that moves that handle to the top of the heap instead of the top of the current
|
|
* region. This implementation is much slower. I'm still investigating it.
|
|
*/
|
|
OSErr c_MoveHHi(Handle handle)
|
|
{
|
|
stdHeap* curHeap;
|
|
handleBlock* blockHeader; /* client's text pointer, or blockHeader */
|
|
|
|
if (handle == nil)
|
|
{
|
|
return LMSetMemErr(nilHandleErr); /* bail right away */
|
|
}
|
|
|
|
/* get client's text pointer, is it nil? */
|
|
if ((blockHeader = (void*)(*handle)) == nil)
|
|
{
|
|
return LMSetMemErr(nilHandleErr);
|
|
}
|
|
|
|
#ifdef client_debugging
|
|
if (IsOddMP(blockHeader)) /* at this point, blockheader is the handle */
|
|
{
|
|
/*
|
|
* the client has most likely disposed of a handle twice. We return
|
|
* right away with an error. This makes apps like PixelPaint work.
|
|
* This mechanism will hopefully replace the bus error hander mechanism
|
|
* of the old MM (I hope). Note: now we rely on tag & range checking.
|
|
*/
|
|
DbgClientCheckForDisposedHandle(handle,"MP is odd, are you moving high a disposed handle?");
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
/* get block header from client's text pointer */
|
|
blockHeader = (handleBlock*) GetBlockHeaderFromPtr(blockHeader);
|
|
if (!IsHeap(curHeap = GetHeapFromHandleBlock(handle, blockHeader))) {
|
|
ClientDebugMsg("Bad heap from block header", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
#ifndef debugNoTagChecking
|
|
/* tag field check for fake handle */
|
|
if ((((stdBlock2*)blockHeader)->tags & kPtrMask) != (uchar)relocatableType)
|
|
{
|
|
if (curHeap != ReadOnlyZone)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you moving high a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasFirstLevelFakeHandleTests
|
|
/* range check for fake handle */
|
|
if (curHeap > (stdHeap*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you moving high a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasSecondAndThirdLevelFakeHandleTests
|
|
{
|
|
stdBlock* testBlock;
|
|
|
|
/* double check to see that backLimit points back to this heap */
|
|
if ((testBlock = curHeap->backLimit) > (stdBlock*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you moving high a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
if (testBlock->parent != curHeap)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you moving high a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
/* Blocks are never moved in the ROZ, no need to check for it. */
|
|
|
|
if (IsLockedHandle(blockHeader))
|
|
{
|
|
return LMSetMemErr(memLockedErr);
|
|
}
|
|
else
|
|
{
|
|
Boolean blockIsPurgable;
|
|
|
|
/* If the block is purgable, mark it as non-purgable so it wont be
|
|
purged during the move. Later, we will restore the block. */
|
|
if (blockIsPurgable = IsUnlockedPurgableHandle(blockHeader))
|
|
MarkBlockNonPurgable(blockHeader, curHeap);
|
|
|
|
/* 10/13/93 11:55:08 AM (BET): it was previously thought that the MoveHnd was the one
|
|
being moved high; MoveHnd is really the currently modified handle _while we are
|
|
compacting_. This means we should be setting RootHnd and RootPtr to this block
|
|
and setting MoveHnd to each block we shuffle to comply with this request. */
|
|
LMSetGZRootHnd(handle);
|
|
LMSetGZRootPtr(*handle);
|
|
|
|
/* is the block in the system heap or has the zone been fully extended (MaxApplZone)? */
|
|
if (IsSystemHeap(curHeap))
|
|
{
|
|
/* moving the block high makes the worse, so we move it low */
|
|
MoveBlockLow(blockHeader, curHeap);
|
|
}
|
|
else
|
|
{
|
|
MoveBlockHigh(blockHeader, curHeap);
|
|
}
|
|
LMSetGZRootHnd(nil);
|
|
LMSetGZRootPtr(nil);
|
|
|
|
/* note: at this point blockHeader has moved, so we can not use it */
|
|
|
|
/* do we need to restore purgability to the block */
|
|
if (blockIsPurgable)
|
|
{
|
|
/* reclaim block header */
|
|
blockHeader = (handleBlock*) GetBlockHeaderFromPtr(*handle);
|
|
MarkBlockPurgable(blockHeader, curHeap);
|
|
}
|
|
|
|
FlushCacheIfNeeded(curHeap);
|
|
DbgCheckHeap(curHeap);
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
}
|
|
|
|
|
|
OSErr c_MoveHLow(Handle handle)
|
|
{
|
|
stdHeap* curHeap;
|
|
handleBlock* blockHeader; /* client's text pointer, or blockHeader */
|
|
|
|
if (handle == nil)
|
|
{
|
|
return LMSetMemErr(nilHandleErr); /* bail right away */
|
|
}
|
|
|
|
/* get client's text pointer, is it not nil? */
|
|
if (blockHeader = (void*)(*handle))
|
|
{
|
|
#ifdef client_debugging
|
|
if (IsOddMP(blockHeader)) /* at this point, blockheader is the handle */
|
|
{
|
|
/*
|
|
* the client has most likely disposed of a handle twice. We return
|
|
* right away with an error. This makes apps like PixelPaint work.
|
|
* This mechanism will hopefully replace the bus error hander mechanism
|
|
* of the old MM (I hope). Note: now we rely on tag & range checking.
|
|
*/
|
|
DbgClientCheckForDisposedHandle(handle,"MP is odd, are you moving a disposed handle?");
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
/* get block header from client's text pointer */
|
|
blockHeader = (handleBlock*) GetBlockHeaderFromPtr(blockHeader);
|
|
if (!IsHeap(curHeap = GetHeapFromHandleBlock(handle, blockHeader))) {
|
|
ClientDebugMsg("Bad heap from block header", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
#ifndef debugNoTagChecking
|
|
/* tag field check for fake handle */
|
|
if ((((stdBlock2*)blockHeader)->tags & kPtrMask) != (uchar)relocatableType)
|
|
{
|
|
if (curHeap != ReadOnlyZone)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you moving a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasFirstLevelFakeHandleTests
|
|
/* range check for fake handle */
|
|
if (curHeap > (stdHeap*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you moving a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasSecondAndThirdLevelFakeHandleTests
|
|
{
|
|
stdBlock* testBlock;
|
|
|
|
/* double check to see that backLimit points back to this heap */
|
|
if ((testBlock = curHeap->backLimit) > (stdBlock*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you moving a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
if (testBlock->parent != curHeap)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you moving a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
/* Blocks are never moved in the Read Only Zone */
|
|
|
|
if (IsLockedHandle(blockHeader))
|
|
{
|
|
return LMSetMemErr(memLockedErr);
|
|
}
|
|
else
|
|
{
|
|
Boolean blockIsPurgable;
|
|
|
|
/* If the block is purgable, mark it as non-purgable so it wont be
|
|
purged during the move. Later, we will restore the block. */
|
|
if (blockIsPurgable = IsUnlockedPurgableHandle(blockHeader))
|
|
MarkBlockNonPurgable(blockHeader, curHeap);
|
|
|
|
/* 10/13/93 11:55:08 AM (BET): it was previously thought that the MoveHnd was the one
|
|
being moved high; MoveHnd is really the currently modified handle _while we are
|
|
compacting_. This means we should be setting RootHnd and RootPtr to this block
|
|
and setting MoveHnd to each block we shuffle to comply with this request. */
|
|
LMSetGZRootHnd(handle);
|
|
LMSetGZRootPtr(*handle);
|
|
|
|
MoveBlockLow(blockHeader, curHeap);
|
|
|
|
LMSetGZRootHnd(handle);
|
|
LMSetGZRootPtr(*handle);
|
|
|
|
/* note: at this point blockHeader has moved, so we can't use it */
|
|
/* do we need to restore purgability to the block */
|
|
if (blockIsPurgable)
|
|
{
|
|
/* reclaim block header */
|
|
blockHeader = (handleBlock*) GetBlockHeaderFromPtr(*handle);
|
|
MarkBlockPurgable(blockHeader, curHeap);
|
|
}
|
|
|
|
FlushCacheIfNeeded(curHeap);
|
|
DbgCheckHeap(curHeap);
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return LMSetMemErr(nilHandleErr);
|
|
}
|
|
}
|
|
|
|
|
|
#if defined(linked_thinkc_app)
|
|
OSErr c_MemError(void)
|
|
{
|
|
return LMGetMemErr();
|
|
}
|
|
#endif
|
|
|
|
|
|
Size c_MaxBlock(ushort trapWord)
|
|
{
|
|
stdHeap* curHeap;
|
|
blockSize_t sizeWeGot;
|
|
|
|
DbgValidateTrapWord(trapWord);
|
|
curHeap = OperateOnSysHeap(trapWord) ? LMGetSysZone() : LMGetTheZone();
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
#ifdef hasFirstLevelFakeHandleTests
|
|
{
|
|
stdBlock* testBlock;
|
|
/*
|
|
* This is for DiskLock v. 2.12, which tries to set the zone to a heap it finds pointed to by
|
|
* SysZone->oldBackLimit->parent. This fails on the old memory manager too, but the bus error
|
|
* handlers grab it and return an error. I can only assume that Shayer is doing this to see if
|
|
* is in some kind of boot time heap so as to do the right thing.
|
|
*
|
|
* Since the heap pointer is in real memory space but simply off by 4 bytes, we are going to have
|
|
* to follow a circular path back to this point to check that this is indeed a heap.
|
|
*/
|
|
/* range check for bad heap */
|
|
if (curHeap > (stdHeap*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad current heap", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
/* now range check the backLimit */
|
|
if ((testBlock = curHeap->backLimit) > (stdBlock*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad backLimit in poseur heap", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
if (testBlock->parent != curHeap)
|
|
{
|
|
ClientDebugMsg("Bad heap consistency via backLimit block check", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
/* End DiskLock hack
|
|
*********************************/
|
|
}
|
|
#endif
|
|
|
|
LMSetMemErr(noErr);
|
|
|
|
sizeWeGot = CalcMaxBlockSize(curHeap);
|
|
|
|
/* calculate the maximum block size, subtract off for the header */
|
|
return sizeWeGot ? sizeWeGot - kBlockOverhead: 0;
|
|
}
|
|
|
|
|
|
Size c_PurgeSpace(ushort trapWord, Size* contig)
|
|
{
|
|
stdHeap* curHeap;
|
|
blockSize_t total;
|
|
|
|
DbgValidateTrapWord(trapWord);
|
|
curHeap = OperateOnSysHeap(trapWord) ? LMGetSysZone() : LMGetTheZone();
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
if (*contig = CalcLargestPurgeRegion(curHeap))
|
|
{
|
|
/* subtract block overhead if we got something back */
|
|
*contig -= kBlockOverhead;
|
|
}
|
|
|
|
/* calculate total now */
|
|
if (total = curHeap->totalFree + curHeap->totalPurgableSpace)
|
|
{
|
|
/* subtract block overhead if we got something back */
|
|
total -= kBlockOverhead;
|
|
}
|
|
|
|
LMSetMemErr(noErr);
|
|
return total;
|
|
}
|
|
|
|
|
|
long c_StackSpace(void)
|
|
{
|
|
ulong theSize;
|
|
|
|
/* note: since heapEnd really points to the zone trailer block and
|
|
kBlockHeaderSize <= zoneTrailerSize <= kBlockHeaderSize*2 then we
|
|
have to consider that value in the fudge factor. The actual value
|
|
may be more since we will pop a stack frame off before returning
|
|
to the caller. */;
|
|
|
|
theSize = GetSP() + 2*kBlockHeaderSize; /* get Stack pointer + fudge factor */
|
|
theSize = AlignDown(theSize);
|
|
LMSetMemErr(noErr);
|
|
return theSize - (ulong)LMGetHiHeapMark();
|
|
}
|
|
|
|
|
|
/* Although not documented, the old HSetRBit code calls the handle prologue routine
|
|
which checks for memWZErr. So we do too. */
|
|
OSErr c_HSetRBit(Handle handle)
|
|
{
|
|
stdHeap* curHeap;
|
|
handleBlock* blockHeader; /* client's text pointer, or blockHeader */
|
|
|
|
if (handle == nil)
|
|
{
|
|
return LMSetMemErr(nilHandleErr); /* bail right away */
|
|
}
|
|
|
|
/* get client's text pointer, is it not nil? */
|
|
if (blockHeader = (void*)(*handle))
|
|
{
|
|
#ifdef client_debugging
|
|
if (IsOddMP(blockHeader)) /* at this point, blockheader is the handle */
|
|
{
|
|
/*
|
|
* the client has most likely disposed of a handle twice. We return
|
|
* right away with an error. This makes apps like PixelPaint work.
|
|
* This mechanism will hopefully replace the bus error hander mechanism
|
|
* of the old MM (I hope). Note: now we rely on tag & range checking.
|
|
*/
|
|
DbgClientCheckForDisposedHandle(handle,"MP is odd, are you setting the resource bit on a disposed handle?");
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
/* get block header from client's text pointer */
|
|
blockHeader = (handleBlock*) GetBlockHeaderFromPtr(blockHeader);
|
|
if (!IsHeap(curHeap = GetHeapFromHandleBlock(handle, blockHeader))) {
|
|
ClientDebugMsg("Bad heap from block header", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
#ifndef debugNoTagChecking
|
|
/* tag field check for fake handle */
|
|
if ((((stdBlock2*)blockHeader)->tags & kPtrMask) != (uchar)relocatableType)
|
|
{
|
|
if (curHeap != ReadOnlyZone)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you setting the resource bit on a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasFirstLevelFakeHandleTests
|
|
/* range check for fake handle */
|
|
if (curHeap > (stdHeap*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you setting the resource bit on a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasSecondAndThirdLevelFakeHandleTests
|
|
{
|
|
stdBlock* testBlock;
|
|
|
|
/* double check to see that backLimit points back to this heap */
|
|
if ((testBlock = curHeap->backLimit) > (stdBlock*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you setting the resource bit on a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
if (testBlock->parent != curHeap)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you setting the resource bit on a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* Note: this operation never occurs in the Read Only Zone */
|
|
|
|
IfClientDebugMsg(IsPtrBlock(blockHeader),"not a valid handle", handle);
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
blockHeader->resourceBit = 1; /* set resource bit */
|
|
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
else
|
|
{
|
|
return LMSetMemErr(nilHandleErr);
|
|
}
|
|
}
|
|
|
|
|
|
/* Although not documented, the old HSetRBit code calls the handle prologue routine
|
|
which checks for memWZErr. So we do too. */
|
|
OSErr c_HClrRBit(Handle handle)
|
|
{
|
|
stdHeap* curHeap;
|
|
handleBlock* blockHeader; /* client's text pointer, or blockHeader */
|
|
|
|
if (handle == nil)
|
|
{
|
|
return LMSetMemErr(nilHandleErr); /* bail right away */
|
|
}
|
|
|
|
/* get client's text pointer, is it not nil? */
|
|
if (blockHeader = (void*)(*handle))
|
|
{
|
|
#ifdef client_debugging
|
|
if (IsOddMP(blockHeader)) /* at this point, blockheader is the handle */
|
|
{
|
|
/*
|
|
* the client has most likely disposed of a handle twice. We return
|
|
* right away with an error. This makes apps like PixelPaint work.
|
|
* This mechanism will hopefully replace the bus error hander mechanism
|
|
* of the old MM (I hope). Note: now we rely on tag & range checking.
|
|
*/
|
|
DbgClientCheckForDisposedHandle(handle,"MP is odd, are you clearing the resource bit a disposed handle?");
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
/* get block header from client's text pointer */
|
|
blockHeader = (handleBlock*) GetBlockHeaderFromPtr(blockHeader);
|
|
if (!IsHeap(curHeap = GetHeapFromHandleBlock(handle, blockHeader))) {
|
|
ClientDebugMsg("Bad heap from block header", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
#ifndef debugNoTagChecking
|
|
/* tag field check for fake handle */
|
|
if ((((stdBlock2*)blockHeader)->tags & kPtrMask) != (uchar)relocatableType)
|
|
{
|
|
if (curHeap != ReadOnlyZone)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you clearing the resource bit on a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasFirstLevelFakeHandleTests
|
|
/* range check for fake handle */
|
|
if (curHeap > (stdHeap*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you clearing the resource bit on a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasSecondAndThirdLevelFakeHandleTests
|
|
{
|
|
stdBlock* testBlock;
|
|
|
|
/* double check to see that backLimit points back to this heap */
|
|
if ((testBlock = curHeap->backLimit) > (stdBlock*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you clearing the resource bit on a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
if (testBlock->parent != curHeap)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you clearing the resource bit on a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
if (IsReadOnlyZone(curHeap))
|
|
{
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
|
|
IfClientDebugMsg(IsPtrBlock(blockHeader),"not a valid handle", handle);
|
|
|
|
blockHeader->resourceBit = 0; /* clear resource bit */
|
|
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
else
|
|
{
|
|
return LMSetMemErr(nilHandleErr);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* note: No special case code needed for the 32 bit read only zone.
|
|
*
|
|
* note2: Since this routine can return an error, we might want to consider
|
|
* having this routine return a 2 byte value rather than 1 byte value.
|
|
*/
|
|
unsigned char c_HGetState(Handle handle)
|
|
{
|
|
stdHeap* curHeap;
|
|
handleBlock* blockHeader; /* client's text pointer, or blockHeader */
|
|
|
|
if (handle == nil)
|
|
{
|
|
/*
|
|
* warning: in this code path, the old MM returns nilHandleErr (2 bytes) back
|
|
* to the client instead of the state (1 byte). However, it is sign extended.
|
|
*/
|
|
return LMSetMemErr(nilHandleErr);
|
|
}
|
|
|
|
/* get client's text pointer, is it not nil? */
|
|
if (blockHeader = (void*)(*handle))
|
|
{
|
|
#ifdef client_debugging
|
|
if (IsOddMP(blockHeader)) /* at this point, blockheader is the handle */
|
|
{
|
|
/*
|
|
* the client has most likely disposed of a handle twice. We return
|
|
* right away with an error. This makes apps like PixelPaint work.
|
|
* This mechanism will hopefully replace the bus error hander mechanism
|
|
* of the old MM (I hope). Note: now we rely on tag & range checking.
|
|
*/
|
|
DbgClientCheckForDisposedHandle(handle,"MP is odd, are you getting state on a disposed handle?");
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
/* get block header from client's text pointer */
|
|
blockHeader = (handleBlock*) GetBlockHeaderFromPtr(blockHeader);
|
|
if (!IsHeap(curHeap = GetHeapFromHandleBlock(handle, blockHeader))) {
|
|
ClientDebugMsg("Bad heap from block header", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
#ifndef debugNoTagChecking
|
|
/* tag field check for fake handle */
|
|
if ((((stdBlock2*)blockHeader)->tags & kPtrMask) != (uchar)relocatableType)
|
|
{
|
|
if (curHeap != ReadOnlyZone)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you getting state on a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasFirstLevelFakeHandleTests
|
|
/* range check for fake handle */
|
|
if (curHeap > (stdHeap*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you getting state on a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasSecondAndThirdLevelFakeHandleTests
|
|
{
|
|
stdBlock* testBlock;
|
|
|
|
/* double check to see that backLimit points back to this heap */
|
|
if ((testBlock = curHeap->backLimit) > (stdBlock*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you getting state on a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
if (testBlock->parent != curHeap)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you getting state on a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
LMSetMemErr(noErr);
|
|
return ((stdBlock2*)blockHeader)->mpFlags & kMPFlagsMask; /* mask off private bits */
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* warning: in this code path, the old MM returns nilHandleErr (2 bytes) back
|
|
* to the client instead of the state (1 byte). However, it is sign extended.
|
|
*/
|
|
return LMSetMemErr(nilHandleErr);
|
|
}
|
|
}
|
|
|
|
|
|
/* This routine becomes a pain because clients can use this routine to in place of:
|
|
HPurge, HNoPurge, HLock, HUnlock, HSetResource, HClrResource. This routine is
|
|
sufficiently complicated that a state table is needed.
|
|
HSetState Notes:
|
|
|
|
Lock bit Purge bit Purge bit Total Purgable LowestRemovableBlock
|
|
Start/End State Start State End State Space Change Action
|
|
|
|
Unlocked => Unlocked
|
|
NonPurgable -> NonPurgable No change No change
|
|
NonPurgable -> Purgable + No change
|
|
Purgable -> NonPurgable - No change
|
|
Purgable -> Purgable No change No change
|
|
|
|
Unlocked => Locked
|
|
NonPurgable -> NonPurgable No change WalkUp
|
|
NonPurgable -> Purgable No change WalkUp
|
|
Purgable -> NonPurgable - WalkUp
|
|
Purgable -> Purgable - WalkUp
|
|
|
|
Locked => Unlocked
|
|
NonPurgable -> NonPurgable No change Set to blockHeader
|
|
NonPurgable -> Purgable + Set to blockHeader
|
|
Purgable -> NonPurgable No change Set to blockHeader
|
|
Purgable -> Purgable + Set to blockHeader
|
|
|
|
Locked => Locked
|
|
NonPurgable -> NonPurgable No change No change
|
|
NonPurgable -> Purgable No change No change
|
|
Purgable -> NonPurgable No change No change
|
|
Purgable -> Purgable No change No change
|
|
*/
|
|
OSErr c_HSetState(Handle handle, unsigned char newFlags)
|
|
{
|
|
stdHeap* curHeap;
|
|
handleBlock* blockHeader; /* client's text pointer, or blockHeader */
|
|
unsigned char oldFlags;
|
|
|
|
if (handle == nil)
|
|
{
|
|
return LMSetMemErr(nilHandleErr); /* bail right away */
|
|
}
|
|
|
|
/* get client's text pointer, is it not nil? */
|
|
if (blockHeader = (void*)(*handle))
|
|
{
|
|
#ifdef client_debugging
|
|
if (IsOddMP(blockHeader)) /* at this point, blockheader is the handle */
|
|
{
|
|
/*
|
|
* the client has most likely disposed of a handle twice. We return
|
|
* right away with an error. This makes apps like PixelPaint work.
|
|
* This mechanism will hopefully replace the bus error hander mechanism
|
|
* of the old MM (I hope). Note: now we rely on tag & range checking.
|
|
*/
|
|
DbgClientCheckForDisposedHandle(handle,"MP is odd, are you setting state on a disposed handle?");
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
/* get block header from client's text pointer */
|
|
blockHeader = (handleBlock*) GetBlockHeaderFromPtr(blockHeader);
|
|
if (!IsHeap(curHeap = GetHeapFromHandleBlock(handle, blockHeader))) {
|
|
ClientDebugMsg("Bad heap from block header", curHeap);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
#ifndef debugNoTagChecking
|
|
/* tag field check for fake handle */
|
|
if ((((stdBlock2*)blockHeader)->tags & kPtrMask) != (uchar)relocatableType)
|
|
{
|
|
if (curHeap != ReadOnlyZone)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you setting state on a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasFirstLevelFakeHandleTests
|
|
/* range check for fake handle */
|
|
if (curHeap > (stdHeap*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you setting state on a fake handle?", handle);
|
|
return LMSetMemErr(memWZErr);
|
|
}
|
|
#endif
|
|
|
|
#ifdef hasSecondAndThirdLevelFakeHandleTests
|
|
{
|
|
stdBlock* testBlock;
|
|
|
|
/* double check to see that backLimit points back to this heap */
|
|
if ((testBlock = curHeap->backLimit) > (stdBlock*)LMGetFakeHandleRange())
|
|
{
|
|
ClientDebugMsg("Bad handle, are you setting state on a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
|
|
if (testBlock->parent != curHeap)
|
|
{
|
|
ClientDebugMsg("Bad handle, are you setting state on a fake handle?", handle);
|
|
return LMSetMemErr(memAZErr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (IsReadOnlyZone(curHeap))
|
|
{
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
|
|
DbgClientCheckHeap(curHeap);
|
|
|
|
oldFlags = ((stdBlock2*)blockHeader)->mpFlags;
|
|
|
|
IfClientDebugMsg(IsPtrBlock(blockHeader),"not a valid handle", handle);
|
|
|
|
if (newFlags & lockedBlockType)
|
|
{
|
|
if (oldFlags & lockedBlockType)
|
|
{
|
|
/* locked => locked, nothing changes here */
|
|
}
|
|
else
|
|
{
|
|
/* unlocked => locked */
|
|
|
|
/* set LRB if needed */
|
|
if (curHeap->lowestRemovableBlock == blockHeader)
|
|
curHeap->lowestRemovableBlock = WalkUpFindNewLowRemoveable((stdBlock*)blockHeader, curHeap);
|
|
|
|
/* was the orginal block purgable? */
|
|
if (oldFlags & purgableType)
|
|
{
|
|
curHeap->totalPurgableSpace -= blockHeader->size;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (oldFlags & lockedBlockType)
|
|
{
|
|
/* locked => unlocked */
|
|
|
|
/* reset LRB if needed */
|
|
if (((void*)blockHeader < curHeap->lowestRemovableBlock) && ((void*)blockHeader > (void*)(curHeap->heapStart)))
|
|
curHeap->lowestRemovableBlock = blockHeader;
|
|
|
|
/* increment total purgable space if the new block is purgable */
|
|
if (newFlags & purgableType)
|
|
curHeap->totalPurgableSpace += blockHeader->size;
|
|
}
|
|
else
|
|
{
|
|
/* unlocked => unlocked */
|
|
|
|
if (oldFlags & purgableType)
|
|
{
|
|
if (!(newFlags & purgableType))
|
|
{
|
|
/* purgable -> nonPurgable */
|
|
curHeap->totalPurgableSpace -= blockHeader->size;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (newFlags & purgableType)
|
|
{
|
|
/* nonPurgable -> purgable */
|
|
curHeap->totalPurgableSpace += blockHeader->size;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* warning: next line also clears other MP flags (subHeapBlockType, privBlockType, etc) */
|
|
((stdBlock2*)blockHeader)->mpFlags = newFlags & kMPFlagsMask;
|
|
DbgCheckHeap(curHeap);
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
else
|
|
{
|
|
return LMSetMemErr(nilHandleErr);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Returns the next block in the heap, skips over private blocks including master
|
|
* pointer blocks and the dead block. If the end of the heap is reached, then it
|
|
* returns nil. Warning, don't make other calls that move memory while iterating
|
|
* the heap.
|
|
*/
|
|
Ptr c_GetNextBlockInHeap(Ptr theBlock, THz theHeap)
|
|
{
|
|
stdHeap* curHeap = (stdHeap*)theHeap;
|
|
stdBlock* workBlock;
|
|
|
|
if (theBlock)
|
|
workBlock = (stdBlock*) GetBlockHeaderFromPtr(theBlock);
|
|
else
|
|
workBlock = curHeap->heapStart;
|
|
|
|
do
|
|
{
|
|
workBlock = GetNextBlock(workBlock);
|
|
|
|
if (workBlock == curHeap->backLimit)
|
|
return nil;
|
|
}
|
|
while (IsPrivateBlock(workBlock));
|
|
|
|
LMSetMemErr(noErr);
|
|
return (Ptr) workBlock + kBlockHeaderSize;
|
|
}
|
|
|
|
/* This get called by the Process Manager can presumable any new Figment aware
|
|
clients that might want to dispose of thier zone. */
|
|
OSErr c_DisposeZone(THz theZone)
|
|
{
|
|
stdBlock* blockHeader;
|
|
stdHeap* parentHeap;
|
|
|
|
/* first we need to see if the heap is contained by a heap in the client header */
|
|
blockHeader = (stdBlock*) GetBlockHeaderFromPtr(theZone);
|
|
|
|
/* does this potential block have a parent heap? */
|
|
if (parentHeap = FindHeap(blockHeader))
|
|
{
|
|
if (IsValidBlockInHeap(blockHeader, parentHeap))
|
|
blockHeader->subHeapBit = 0; /* mark the block as no longer containing a heap */
|
|
}
|
|
|
|
//RemoveHeap((stdHeap*) theZone);
|
|
RemoveHeap(((stdHeap*)theZone)->heapStart, (Ptr)((stdHeap*)theZone)->backLimit);
|
|
|
|
return LMSetMemErr(noErr);
|
|
}
|
|
|
|
|
|
/* this is a way for ProcessMgr inform the heap manager of special compatibility hacks */
|
|
OSErr c_SetZoneCompatibilityFlags(THz theZone, ushort theFlags)
|
|
{
|
|
((stdHeap2*)theZone)->compatibilityFlags = theFlags;
|
|
return noErr;
|
|
}
|
|
|
|
|
|
/* this is a way for ProcessMgr inform the heap manager of special compatibility hacks */
|
|
ushort c_GetZoneCompatibilityFlags(THz theZone)
|
|
{
|
|
return ((stdHeap2*)theZone)->compatibilityFlags;
|
|
}
|
|
|
|
|
|
#if 0
|
|
/*
|
|
* Below is code to implement chained GZ procs and code to implement chained
|
|
* dispose procs. These features are not implemented and are commented out.
|
|
* There is also support code in MemMgrInternal.c that is commented out as well.
|
|
*/
|
|
|
|
/* Used to register call back procs */
|
|
static OSErr LLInsert(ProcPtr theProc, callBackNodePtr* listHead);
|
|
static OSErr LLInsert(ProcPtr theProc, callBackNodePtr* listHead)
|
|
{
|
|
callBackNodePtr trail;
|
|
callBackNodePtr curr;
|
|
callBackNodePtr newItem;
|
|
|
|
/* create new list node */
|
|
c_NewPtr((Ptr*)&newItem, 0xA11E, sizeof(callBackNodeItem)); /* call newptr through internal API */
|
|
if (!newItem)
|
|
return LMGetMemErr();
|
|
|
|
/* Mark the block as "private" */
|
|
((stdBlock*)GetBlockHeaderFromPtr(newItem))->privBlockBit = 1;
|
|
|
|
/* Since its private, the MM does not consider it a ptrBlock */
|
|
DbgCode(LMGetTheZone()->ptrBlocks--);
|
|
|
|
curr = *listHead;
|
|
trail = nil;
|
|
|
|
/* walk down the list to add entry at the end */
|
|
while (curr)
|
|
{
|
|
trail = curr;
|
|
curr = curr->next;
|
|
}
|
|
|
|
/* fill in items */
|
|
newItem->next = nil;
|
|
newItem->proc = theProc;
|
|
|
|
if (trail)
|
|
{
|
|
/* add it to the list */
|
|
trail->next = newItem;
|
|
}
|
|
else
|
|
{
|
|
/* add to the head of the list */
|
|
*listHead = newItem;
|
|
}
|
|
return noErr;
|
|
}
|
|
|
|
|
|
/* Used to unregister call back procs */
|
|
/* returns true if item was found */
|
|
static Boolean LLDelete(ProcPtr theProc, callBackNodePtr* listHead);
|
|
static Boolean LLDelete(ProcPtr theProc, callBackNodePtr* listHead)
|
|
{
|
|
callBackNodePtr curr;
|
|
callBackNodePtr trail = nil;
|
|
|
|
/* scan the list looking for the right item */
|
|
curr = *listHead;
|
|
while (curr->proc != theProc)
|
|
{
|
|
trail = curr;
|
|
curr = curr->next;
|
|
|
|
/* did we reach the end of the list? */
|
|
if (curr == nil)
|
|
return false; /* we didn't find anything */
|
|
}
|
|
|
|
/* we have found the proc to remove, do it */
|
|
if (trail)
|
|
{
|
|
trail->next = curr->next;
|
|
}
|
|
else
|
|
{
|
|
/* removing first item */
|
|
*listHead = curr->next;
|
|
}
|
|
|
|
DisposePtr((Ptr)curr);
|
|
return true;
|
|
}
|
|
|
|
|
|
OSErr c_RegisterChainedGrowZoneProc(GrowZoneProcPtr theProc, Boolean beforeUsersProc)
|
|
{
|
|
stdHeap* curHeap = LMGetTheZone();
|
|
|
|
return LLInsert((ProcPtr) theProc,
|
|
(beforeUsersProc) ? &curHeap->earlyChainedGZProc : &curHeap->lateChainedGZProc
|
|
);
|
|
}
|
|
|
|
|
|
OSErr c_UnregisterChainedGrowZoneProc(GrowZoneProcPtr theProc)
|
|
{
|
|
stdHeap* curHeap = LMGetTheZone();
|
|
|
|
/* can we delete it from the early chain?, then do so */
|
|
if (!LLDelete((ProcPtr) theProc, &curHeap->earlyChainedGZProc))
|
|
{
|
|
/* delete it from the late chain */
|
|
LLDelete((ProcPtr) theProc, &curHeap->lateChainedGZProc);
|
|
}
|
|
|
|
return noErr;
|
|
}
|
|
#endif /* commented out code */
|
|
|
|
|
|
#if USESROUTINEDESCRIPTORS
|
|
OSErr c_RegisterDisposeProc(DisposeUPP theProc, THz theZone)
|
|
#else
|
|
OSErr c_RegisterDisposeProc(DisposeProcPtr theProc, THz theZone)
|
|
#endif
|
|
{
|
|
stdHeap* curHeap = (stdHeap*)theZone;
|
|
|
|
// we use this code after the Process Manager starts calling this
|
|
// trap instead of jamming the heap field directly
|
|
//return LLInsert((ProcPtr) theProc, &curHeap->disposeProc);
|
|
|
|
// this code will be removed after ProcessMgr revs
|
|
curHeap->disposeProc = (DisposeProcPtr)theProc;
|
|
return noErr;
|
|
}
|
|
|
|
|
|
|
|
#ifdef StarTrek
|
|
|
|
/*
|
|
* This is "high level glue" to so the Figment API can be called from high level code
|
|
* but still use the same API as the existing MM.
|
|
*/
|
|
|
|
pascal void InitZone(GrowZoneProcPtr pgrowZone, short cmoreMasters, void* limitPtr, void* startPtr)
|
|
{
|
|
c_InitZone(pgrowZone, cmoreMasters, limitPtr, startPtr);
|
|
}
|
|
|
|
pascal void SetApplLimit(Ptr zoneLimit)
|
|
{
|
|
c_SetApplLimit(zoneLimit);
|
|
}
|
|
|
|
pascal void MaxApplZone(void)
|
|
{
|
|
c_MaxApplZone();
|
|
}
|
|
|
|
pascal void MoreMasters(void)
|
|
{
|
|
c_MoreMasters();
|
|
}
|
|
|
|
pascal THz GetZone(void)
|
|
{
|
|
return c_GetZone();
|
|
}
|
|
|
|
pascal void SetZone(THz hz)
|
|
{
|
|
c_SetZone(hz);
|
|
}
|
|
|
|
pascal Handle NewHandle(Size requestedSize)
|
|
{
|
|
Handle theHandle;
|
|
|
|
c_NewHandle(&theHandle, kWorkOnCurHeap, requestedSize);
|
|
return theHandle;
|
|
}
|
|
|
|
pascal Handle NewHandleSys(Size requestedSize)
|
|
{
|
|
Handle theHandle;
|
|
|
|
c_NewHandle(&theHandle, kSysTrapWordBit, requestedSize);
|
|
return theHandle;
|
|
}
|
|
|
|
pascal Handle NewHandleClear(Size requestedSize)
|
|
{
|
|
Handle theHandle;
|
|
|
|
c_NewHandle(&theHandle, kClearTrapWordBit, requestedSize);
|
|
return theHandle;
|
|
}
|
|
|
|
pascal Handle NewHandleSysClear(Size requestedSize)
|
|
{
|
|
Handle theHandle;
|
|
|
|
c_NewHandle(&theHandle, kClearTrapWordBit+kClearTrapWordBit, requestedSize);
|
|
return theHandle;
|
|
}
|
|
|
|
pascal Handle NewEmptyHandle(void)
|
|
{
|
|
Handle theHandle;
|
|
|
|
c_NewEmptyHandle(&theHandle, kWorkOnCurHeap);
|
|
return theHandle;
|
|
}
|
|
|
|
pascal Handle NewEmptyHandleSys(void)
|
|
{
|
|
Handle theHandle;
|
|
|
|
c_NewEmptyHandle(&theHandle, kSysTrapWordBit);
|
|
return theHandle;
|
|
}
|
|
|
|
pascal void DisposeHandle(Handle theHandle)
|
|
{
|
|
c_DisposeHandle(theHandle);
|
|
}
|
|
|
|
pascal Size GetHandleSize(Handle theHandle)
|
|
{
|
|
return c_GetHandleSize(theHandle);
|
|
}
|
|
|
|
pascal void SetHandleSize(Handle theHandle, Size requestedSize)
|
|
{
|
|
c_SetHandleSize(theHandle, requestedSize);
|
|
}
|
|
|
|
pascal THz HandleZone(Handle theHandle)
|
|
{
|
|
THz theZone;
|
|
|
|
c_HandleZone(&theZone, theHandle);
|
|
return theZone;
|
|
}
|
|
|
|
pascal Handle RecoverHandle(Ptr masterPointer)
|
|
{
|
|
return c_RecoverHandle(kWorkOnCurHeap, masterPointer);
|
|
}
|
|
|
|
pascal Handle RecoverHandleSys(Ptr masterPointer)
|
|
{
|
|
return c_RecoverHandle(kSysTrapWordBit, masterPointer);
|
|
}
|
|
|
|
pascal void ReallocHandle(Handle handle, Size requestedSize)
|
|
{
|
|
c_ReallocHandle(handle, requestedSize);
|
|
}
|
|
|
|
pascal Ptr NewPtr(Size requestedSize)
|
|
{
|
|
Ptr thePtr;
|
|
|
|
c_NewPtr(&thePtr, kWorkOnCurHeap, requestedSize);
|
|
return thePtr;
|
|
}
|
|
|
|
pascal Ptr NewPtrSys(Size requestedSize)
|
|
{
|
|
Ptr thePtr;
|
|
|
|
c_NewPtr(&thePtr, kSysTrapWordBit, requestedSize);
|
|
return thePtr;
|
|
}
|
|
|
|
pascal Ptr NewPtrClear(Size requestedSize)
|
|
{
|
|
Ptr thePtr;
|
|
|
|
c_NewPtr(&thePtr, kClearTrapWordBit, requestedSize);
|
|
return thePtr;
|
|
}
|
|
|
|
pascal Ptr NewPtrSysClear(Size requestedSize)
|
|
{
|
|
Ptr thePtr;
|
|
|
|
c_NewPtr(&thePtr, kClearTrapWordBit+kClearTrapWordBit, requestedSize);
|
|
return thePtr;
|
|
}
|
|
|
|
pascal void DisposePtr(Ptr thePtr)
|
|
{
|
|
c_DisposePtr(thePtr);
|
|
}
|
|
|
|
pascal Size GetPtrSize(Ptr thePtr)
|
|
{
|
|
return c_GetPtrSize(thePtr);
|
|
}
|
|
|
|
pascal void SetPtrSize(Ptr thePtr, Size requestedSize)
|
|
{
|
|
c_SetPtrSize(thePtr, requestedSize);
|
|
}
|
|
|
|
pascal THz PtrZone(Ptr thePtr)
|
|
{
|
|
THz theZone;
|
|
|
|
c_PtrZone(&theZone, thePtr);
|
|
return theZone;
|
|
}
|
|
|
|
pascal long FreeMem(void)
|
|
{
|
|
return c_FreeMem(kWorkOnCurHeap);
|
|
}
|
|
|
|
pascal long FreeMemSys(void)
|
|
{
|
|
return c_FreeMem(kSysTrapWordBit);
|
|
}
|
|
|
|
pascal Size MaxMem(Size *growSize)
|
|
{
|
|
return c_MaxMem(kWorkOnCurHeap, growSize);
|
|
}
|
|
|
|
pascal Size MaxMemSys(Size *growSize)
|
|
{
|
|
return c_MaxMem(kSysTrapWordBit, growSize);
|
|
}
|
|
|
|
pascal Size CompactMem(Size sizeNeeded)
|
|
{
|
|
return c_MaxMem(kWorkOnCurHeap, &sizeNeeded);
|
|
}
|
|
|
|
pascal Size CompactMemSys(Size sizeNeeded)
|
|
{
|
|
return c_CompactMem(kSysTrapWordBit, sizeNeeded);
|
|
}
|
|
|
|
#define ResrvMem(s) ReserveMem(s)
|
|
pascal void ReserveMem(Size sizeNeeded)
|
|
{
|
|
c_ReserveMem(kWorkOnCurHeap, sizeNeeded);
|
|
}
|
|
|
|
pascal void ReserveMemSys(Size sizeNeeded)
|
|
{
|
|
c_ReserveMem(kSysTrapWordBit, sizeNeeded);
|
|
}
|
|
|
|
pascal void PurgeMem(Size sizeNeeded)
|
|
{
|
|
c_PurgeMem(kWorkOnCurHeap, sizeNeeded);
|
|
}
|
|
|
|
pascal void PurgeMemSys(Size sizeNeeded)
|
|
{
|
|
c_PurgeMem(kSysTrapWordBit, sizeNeeded);
|
|
}
|
|
|
|
pascal void EmptyHandle(Handle handle)
|
|
{
|
|
c_EmptyHandle(handle);
|
|
}
|
|
|
|
pascal void HLock(Handle handle)
|
|
{
|
|
c_HLock(handle);
|
|
}
|
|
|
|
pascal void HUnlock(Handle handle)
|
|
{
|
|
c_HUnlock(handle);
|
|
}
|
|
|
|
pascal void HPurge(Handle handle)
|
|
{
|
|
c_HPurge(handle);
|
|
}
|
|
|
|
pascal void HNoPurge(Handle handle)
|
|
{
|
|
c_HNoPurge(handle);
|
|
}
|
|
|
|
pascal void SetGrowZone(GrowZoneProcPtr theGrowZoneProc)
|
|
{
|
|
c_SetGrowZone(theGrowZoneProc);
|
|
}
|
|
|
|
pascal void MoveHHi(Handle theHandle)
|
|
{
|
|
c_MoveHHi(theHandle);
|
|
}
|
|
|
|
pascal void MoveHLow(Handle theHandle)
|
|
{
|
|
c_MoveHLow(theHandle);
|
|
}
|
|
|
|
pascal Size MaxBlock(void)
|
|
{
|
|
return c_MaxBlock(kWorkOnCurHeap);
|
|
}
|
|
|
|
pascal Size MaxBlockSys(void)
|
|
{
|
|
return c_MaxBlock(kSysTrapWordBit);
|
|
}
|
|
|
|
pascal void PurgeSpace(Size *total,Size *contig)
|
|
{
|
|
*total = c_PurgeSpace(kWorkOnCurHeap, contig);
|
|
}
|
|
|
|
pascal void PurgeSpaceSys(Size *total,Size *contig)
|
|
{
|
|
*total = c_PurgeSpace(kSysTrapWordBit, contig);
|
|
}
|
|
|
|
pascal long StackSpace(void)
|
|
{
|
|
return c_StackSpace();
|
|
}
|
|
|
|
pascal void HSetRBit(Handle handle)
|
|
{
|
|
c_HSetRBit(handle);
|
|
}
|
|
|
|
pascal void HClrRBit(Handle handle)
|
|
{
|
|
c_HClrRBit(handle);
|
|
}
|
|
|
|
pascal char HGetState(Handle handle)
|
|
{
|
|
return c_HGetState(handle);
|
|
}
|
|
|
|
pascal void HSetState(Handle handle, char flags)
|
|
{
|
|
c_HSetState(handle, flags);
|
|
}
|
|
|
|
pascal Handle NewHandleHi(Size requestedSize)
|
|
{
|
|
Handle theHandle;
|
|
|
|
c_NewHandleHi(&theHandle, kWorkOnCurHeap, requestedSize);
|
|
return theHandle;
|
|
}
|
|
|
|
#endif /* StarTrek */
|
|
|
|
|