executor/src/mman.c

2179 lines
44 KiB
C

/* Copyright 1990 - 1996 by Abacus Research and
* Development, Inc. All rights reserved.
*/
#if !defined (OMIT_RCSID_STRINGS)
char ROMlib_rcsid_mman[] =
"$Id: mman.c 88 2005-05-25 03:59:37Z ctm $";
#endif
/* Implementation of MAC memory manager routines */
/* Forward declarations in MemoryMgr.h (DO NOT DELETE THIS LINE) */
#include "rsys/common.h"
#include "MemoryMgr.h"
#include "SegmentLdr.h"
#include "QuickDraw.h"
#include "SysErr.h"
#include "TextEdit.h"
#include "OSEvent.h"
#include "rsys/mman_private.h"
#include "rsys/file.h"
#include "rsys/smash.h"
#include "rsys/memory_layout.h"
#include "rsys/hook.h"
#include "rsys/memsize.h"
#include "rsys/executor.h"
#include "rsys/options.h"
#include "rsys/toolutil.h"
#include "rsys/gestalt.h"
#if defined (MSDOS)
#include "dpmilock.h"
#endif
#if defined (LINUX) || defined (MACOSX)
#include <sys/mman.h>
#if !defined (MAP_ANONYMOUS)
# define MAP_ANONYMOUS MAP_ANON
#endif
#endif /* LINUX */
#if defined(NEXT) && !defined (STRICT_OPENSTEP)
#include <mach/mach_error.h>
#endif
int ROMlib_applzone_size = DEFAULT_APPLZONE_SIZE;
int ROMlib_syszone_size = DEFAULT_SYSZONE_SIZE;
int ROMlib_stack_size = DEFAULT_STACK_SIZE;
/* these two variables define, in ROMlib space, the beginning of mac-memory
and the end of mac memory. They're purpose is to try to prevent routines
like DisposHandle () from crashing when passed a bogus pointer.
Specifically, I know an application that picks up 4 bytes from low-memory
global 0x100 and then calls DisposHandle () on it. That location contains
0xFFFF0048 both here and on a Mac. On a Mac, this doesn't cause a crash.
*/
PUBLIC unsigned long ROMlib_syszone;
PUBLIC unsigned long ROMlib_memtop;
#if defined (MM_MANY_APPLZONES)
/* for debugging, we can have multiple applzones which are used
roundrobin */
int mm_n_applzones = 1;
static int mm_current_applzone;
#endif
/* for routines that simply set MemErr */
#define SET_MEM_ERR(err) \
do { \
GEN_MEM_ERR (err); \
MemErr = CWV (err); \
} while (FALSE)
SignedByte
hlock_return_orig_state (Handle h)
{
block_header_t *block;
SignedByte state;
MM_SLAM ("entry");
block = HANDLE_TO_BLOCK (h);
if (block == NULL)
{
SET_MEM_ERR (nilHandleErr);
return 0;
}
if (USE (block) == FREE)
{
SET_MEM_ERR (memWZErr);
return 0;
}
state = HANDLE_STATE (h, block);
SET_HANDLE_STATE (h, block, state | LOCKBIT);
MM_SLAM ("exit");
SET_MEM_ERR (noErr);
return state;
}
Size
zone_size (THz zone)
{
return (char *) ZONE_BK_LIM (zone) - (char *) zone;
}
SignedByte
HGetState (Handle h)
{
block_header_t *block;
MM_SLAM ("entry");
/* there used to be a spewy check here that returned noErr (zero
state) if the incoming handle address was `spewy' (less than
0x2000 or between the end of the applzone and the current stack
frame. it got axed */
block = HANDLE_TO_BLOCK (h);
if (block == NULL)
{
SET_MEM_ERR (nilHandleErr);
return nilHandleErr;
}
if (USE (block) == FREE)
{
SET_MEM_ERR (memWZErr);
return memWZErr;
}
SET_MEM_ERR (noErr);
return HANDLE_STATE (h, block);
}
void
HSetState (Handle h, SignedByte flags)
{
block_header_t *block;
MM_SLAM ("entry");
block = HANDLE_TO_BLOCK (h);
if (block == NULL)
{
SET_MEM_ERR (nilHandleErr);
return;
}
if (USE (block) == FREE)
{
SET_MEM_ERR (memWZErr);
return;
}
SET_HANDLE_STATE (h, block, flags);
MM_SLAM ("exit");
SET_MEM_ERR (noErr);
}
void
HLock (Handle h)
{
block_header_t *block;
MM_SLAM ("entry");
block = HANDLE_TO_BLOCK (h);
if (block == NULL)
{
SET_MEM_ERR (nilHandleErr);
return;
}
if (USE (block) == FREE)
{
SET_MEM_ERR (memWZErr);
return;
}
SET_HANDLE_STATE (h, block, HANDLE_STATE (h, block) | LOCKBIT);
MM_SLAM ("exit");
SET_MEM_ERR (noErr);
}
void
HUnlock (Handle h)
{
block_header_t *block;
MM_SLAM ("entry");
block = HANDLE_TO_BLOCK (h);
if (block == NULL)
{
SET_MEM_ERR (nilHandleErr);
return;
}
if (USE (block) == FREE)
{
SET_MEM_ERR (memWZErr);
return;
}
SET_HANDLE_STATE (h, block, HANDLE_STATE (h, block) & ~LOCKBIT);
MM_SLAM ("exit");
SET_MEM_ERR (noErr);
}
void
HPurge (Handle h)
{
block_header_t *block;
MM_SLAM ("entry");
block = HANDLE_TO_BLOCK (h);
if (block == NULL)
{
SET_MEM_ERR (nilHandleErr);
return;
}
if (USE (block) == FREE)
{
SET_MEM_ERR (memWZErr);
return;
}
SET_HANDLE_STATE (h, block, HANDLE_STATE (h, block) | PURGEBIT);
MM_SLAM ("exit");
SET_MEM_ERR (noErr);
}
void
HNoPurge (Handle h)
{
block_header_t *block;
MM_SLAM ("entry");
block = HANDLE_TO_BLOCK (h);
if (block == NULL)
{
SET_MEM_ERR (nilHandleErr);
return;
}
if (USE (block) == FREE)
{
SET_MEM_ERR (memWZErr);
return;
}
SET_HANDLE_STATE (h, block, HANDLE_STATE (h, block) & ~PURGEBIT);
MM_SLAM ("exit");
SET_MEM_ERR (noErr);
}
void
HSetRBit (Handle h)
{
block_header_t *block;
MM_SLAM ("entry");
block = HANDLE_TO_BLOCK (h);
if (block == NULL)
{
SET_MEM_ERR (nilHandleErr);
return;
}
if (USE (block) == FREE)
{
SET_MEM_ERR (memWZErr);
return;
}
SET_HANDLE_STATE (h, block, HANDLE_STATE (h, block) | RSRCBIT);
MM_SLAM ("exit");
SET_MEM_ERR (noErr);
}
void
HClrRBit (Handle h)
{
block_header_t *block;
MM_SLAM ("entry");
block = HANDLE_TO_BLOCK (h);
if (block == NULL)
{
SET_MEM_ERR (nilHandleErr);
return;
}
if (USE (block) == FREE)
{
SET_MEM_ERR (memWZErr);
return;
}
SET_HANDLE_STATE (h, block, HANDLE_STATE (h, block) & ~RSRCBIT);
MM_SLAM ("exit");
SET_MEM_ERR (noErr);
}
/* Zone sizes will be zero modulo this number (which must be a power of 2). */
#define ZONE_ALIGN_SIZE 8192
static void
pin_and_align (int *vp, int min, int max)
{
int v = *vp;
v = (v + ZONE_ALIGN_SIZE - 1) & ~(ZONE_ALIGN_SIZE - 1);
if (v < min)
v = min;
else if (v > max)
v = max;
*vp = v;
}
static void
canonicalize_memory_sizes (void)
{
pin_and_align (&ROMlib_applzone_size, MIN_APPLZONE_SIZE, MAX_APPLZONE_SIZE);
pin_and_align (&ROMlib_syszone_size, MIN_SYSZONE_SIZE, MAX_SYSZONE_SIZE);
pin_and_align (&ROMlib_stack_size, MIN_STACK_SIZE, MAX_STACK_SIZE);
}
void
InitApplZone (void)
{
/* ApplZone must already be set before getting here */
/* nisus writer demands that `ApplLimit - ZONE_BK_LIM (ApplZone)' be
greater than (or equal to?) 16384 */
#define APPLZONE_SLOP 16384
canonicalize_memory_sizes ();
#define INIT_APPLZONE_SIZE \
(ROMlib_applzone_size + APPLZONE_SLOP)
HeapEnd = (Ptr) RM ((char *) MR (ApplZone)
+ INIT_APPLZONE_SIZE
- (MIN_BLOCK_SIZE + APPLZONE_SLOP));
InitZone (0, 64, (Ptr) HEAPEND, (Zone *) MR (ApplZone));
MM_SLAM ("exit");
SET_MEM_ERR (noErr);
}
#define MANDELSLOP (32L * 1024)
void
print_mem_full_message (void)
{
fprintf (stderr,
"Executor has run out of memory. Try specifying "
"a smaller -memory size.\n");
#if defined (MSDOS)
fprintf (stderr,
"Under Windows and Warp, try increasing the DPMI memory "
"available to Executor.\n");
#endif
}
void
ROMlib_InitZones (offset_enum which)
{
static boolean_t beenhere = FALSE;
static Ptr stack_begin, stack_end;
static unsigned long applzone_memory_segment_size;
int init_syszone_size;
#if ERROR_SUPPORTED_P (ERROR_MEMORY_MANAGER_SLAM)
/* Temporarily turn off heap slamming while the heap is being set up. */
boolean_t old_debug_enabled_p;
old_debug_enabled_p = error_set_enabled (ERROR_MEMORY_MANAGER_SLAM, FALSE);
#endif
#define INIT_SYSZONE_SIZE \
(ROMlib_syszone_size)
if (!beenhere)
{
char *memory;
unsigned long total_allocated_memory, total_mac_visible_memory;
Ptr mem_top;
canonicalize_memory_sizes ();
#define STACK_SIZE ROMlib_stack_size
#if defined (MM_MANY_APPLZONES)
applzone_memory_segment_size = (mm_n_applzones * INIT_APPLZONE_SIZE);
#else /* !MM_MANY_APPLZONES */
applzone_memory_segment_size = INIT_APPLZONE_SIZE;
#endif /* !MM_MANY_APPLZONES */
/* Determine total allocated memory. Round up to next 8K
* since that's the page size we pretend to have.
*/
total_mac_visible_memory = (INIT_SYSZONE_SIZE
+ INIT_APPLZONE_SIZE
+ STACK_SIZE);
total_mac_visible_memory = (total_mac_visible_memory + 8191) & ~8191;
total_allocated_memory = (INIT_SYSZONE_SIZE
+ applzone_memory_segment_size
+ STACK_SIZE);
total_allocated_memory = (total_allocated_memory + 8191) & ~8191;
/* Note the memory in gestalt, rounded down the next 8K page multiple. */
gestalt_set_memory_size (total_mac_visible_memory);
/* Allocate memory for SysZone, ApplZone, and stack, contiguously. */
memory = NULL;
#if defined (TRY_TO_MMAP_ZONES)
/* Try to mmap if either malloc failed or bits are set in the high
* byte of any address in the space just allocated.
*/
if (memory == NULL)
memory = mmap_permanent_memory (total_allocated_memory);
#endif /* TRY_TO_MMAP_ZONES */
#if defined (SBRK_PERMANENT_MEMORY)
if (memory == NULL)
{
memory = sbrk (total_allocated_memory);
if (memory == (char *) -1)
memory = NULL;
}
#endif /* SBRK_PERMANENT_MEMORY) */
/* Allocate with malloc if we don't have it yet. */
if (memory == NULL)
memory = malloc (total_allocated_memory);
if (memory == NULL)
{
print_mem_full_message ();
exit (-1);
}
/* can't assign to low-memory globals yet */
mem_top = (Ptr) RM (memory + total_allocated_memory);
stack_begin = ((Ptr) memory
+ INIT_SYSZONE_SIZE
+ applzone_memory_segment_size);
stack_end = stack_begin + STACK_SIZE;
init_syszone_size = INIT_SYSZONE_SIZE;
switch (which)
{
case offset_none:
ROMlib_offset = 0;
break;
case offset_8k:
ROMlib_offset = 8192;
break;
case offset_big:
ROMlib_offset = (uint32) memory;
{
int low_global_room = (char *) &lastlowglobal -
(char *) &nilhandle_H;
#if defined (MSDOS)
dpmi_lock_memory (&nilhandle_H, low_global_room);
#endif
memory += low_global_room;
init_syszone_size -= low_global_room;
}
break;
default:
/* shouldn't get here */
break;
}
MemTop = mem_top;
SysZone = (void *) RM (memory);
ROMlib_syszone = (unsigned long) memory;
ROMlib_memtop = (unsigned long) (memory + total_allocated_memory);
InitZone (0, 32, (Ptr) ((long) MR (SysZone) + init_syszone_size),
(Zone *) MR (SysZone));
beenhere = TRUE;
}
#if defined (MM_MANY_APPLZONES)
if (mm_n_applzones != 1)
{
if (munmap ((char *) MR (SysZone)
+ INIT_SYSZONE_SIZE,
applzone_memory_segment_size) == -1)
warning_errno ("unable to `munmap ()' previous applzone");
ApplZone = (THz) RM ((long) MR (SysZone)
+ INIT_SYSZONE_SIZE
+ (mm_current_applzone * INIT_APPLZONE_SIZE));
mm_current_applzone = (mm_current_applzone + 1) % mm_n_applzones;
if (mmap ((char *) MR (ApplZone), INIT_APPLZONE_SIZE,
PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, -1, 0) == (void *) -1)
errno_fatal ("unable to `mmap ()' new applzone");
}
else
ApplZone = (THz) RM ((long) MR (SysZone) + INIT_SYSZONE_SIZE);
#else /* !MM_MANY_APPLZONES */
ApplZone = (THz) RM ((long) MR (SysZone) + INIT_SYSZONE_SIZE);
#endif
InitApplZone ();
ApplLimit = RM ((Ptr) ((long) MR (ApplZone)
+ INIT_APPLZONE_SIZE));
EM_A7 = (long) US_TO_SYN68K(stack_end - 16 - MANDELSLOP);
MemErr = CWC (noErr);
#if ERROR_SUPPORTED_P (ERROR_MEMORY_MANAGER_SLAM)
error_set_enabled (ERROR_MEMORY_MANAGER_SLAM, old_debug_enabled_p);
#endif
}
void
SetApplBase (Ptr newbase)
{
int32 totend;
if ((char *) newbase < (char *) ZONE_BK_LIM (MR (SysZone)) + MIN_BLOCK_SIZE)
{
SET_MEM_ERR (noErr);
return;
}
/* Find out how big this makes the last bit of the system zone */
totend = (char *) newbase - (char *) ZONE_BK_LIM (MR (SysZone));
if (totend >= 24) /* Make two blocks */
{
block_header_t *newfree = ZONE_BK_LIM (MR (SysZone));
block_header_t *newlast = POINTER_TO_BLOCK (newbase);
mm_set_block_fields_offset (newfree,
FREE_BLOCK_STATE, FREE, 0,
(char *) newlast - (char *) newfree, 0);
mm_set_block_fields_offset (newlast,
FREE_BLOCK_STATE, FREE, 0,
MIN_BLOCK_SIZE, 0);
}
/* Otherwise, blow it off. There isn't room for another block at the end,
so we just let the old bkLim stand. */
ApplZone = RM ((THz) newbase);
InitApplZone ();
SET_MEM_ERR (noErr);
}
void
MoreMasters (void)
{
THz current_zone;
uint32 *handles;
int i;
MM_SLAM ("entry");
current_zone = MR (TheZone);
handles = (uint32 *) NewPtr (ZONE_MORE_MAST (current_zone)
* sizeof (uint32));
if (handles == NULL)
{
SET_MEM_ERR (memFullErr);
return;
}
handles[0] = (uint32) ZONE_HFST_FREE_X (current_zone);
ZONE_HFST_FREE_X (current_zone)
= RM ((Ptr) &handles[ZONE_MORE_MAST (current_zone) - 1]);
for (i = ZONE_MORE_MAST (current_zone) - 1; i > 0; i--)
handles[i] = RM ((uint32) &handles[i - 1]);
MM_SLAM ("exit");
SET_MEM_ERR (noErr);
return;
}
#if !defined (NDEBUG)
void
print_free (void)
{
printf ("%d %d\n", CL (MR(ApplZone)->zcbFree), CL (MR(SysZone)->zcbFree));
}
#endif
void
InitZone (ProcPtr pGrowZone, int16 cMoreMasters,
Ptr limitPtr, THz zone)
{
block_header_t *last_block;
block_header_t *first_block;
/* following line is needed for PPC version of Illustrator 5.5
TODO: check mac carefully to see how they handle the final block */
limitPtr = limitPtr - 8;
last_block = (block_header_t *) ((char *) limitPtr - MIN_BLOCK_SIZE);
first_block = ZONE_HEAP_DATA (zone);
zone->bkLim = RM ((Ptr) last_block);
zone->purgePtr = CLC_NULL;
zone->hFstFree = CLC_NULL;
zone->zcbFree = CL ((uint32) limitPtr - (uint32) zone - 64);
zone->gzProc = RM (pGrowZone);
zone->moreMast = CW (cMoreMasters);
zone->flags = CWC (0);
zone->minCBFree = CWC (0);
zone->purgeProc = CLC_NULL;
zone->cntRel = zone->cntNRel = zone->cntEmpty = zone->cntHandles
= CWC (0);
/* hypercard checks byte `30' (the high byte of the `maxNRel' field)
of the Zone structure to determine if it can set the alloc
pointer to the address of a non-relocatable block it just
`DisposePtr ()'ed (which is allowed in 24bit zones).
#### testing on the mac to see what the `max*' fields actually
mean in a 32bit zone is required, but this is a good a guess as
anything */
zone->maxRel = zone->maxNRel = CWC (-1);
#if 0
zone->sparePtr = CLC ((Ptr) 0x83d2); /* From experimentation */
#else
zone->sparePtr = CLC (0); /* Better safe than sorry */
#endif
zone->allocPtr = RM ((Ptr) first_block);
mm_set_block_fields_offset (first_block,
FREE_BLOCK_STATE, FREE, 0,
(char *) last_block - (char *) first_block, 0);
mm_set_block_fields_offset (last_block,
FREE_BLOCK_STATE, FREE, 0,
MIN_BLOCK_SIZE, 0);
TheZone = RM (zone);
MoreMasters ();
MM_SLAM_ZONE (zone, "exit");
SET_MEM_ERR (noErr);
}
THz
GetZone (void)
{
MM_SLAM ("entry");
SET_MEM_ERR (noErr);
return MR (TheZone);
}
void
SetZone (THz hz)
{
MM_SLAM ("entry");
TheZone = RM (hz);
SET_MEM_ERR (noErr);
}
Handle
_NewEmptyHandle_flags (boolean_t sys_p)
{
THz save_zone, current_zone;
Handle h;
MM_SLAM ("entry");
save_zone = TheZone;
if (sys_p)
TheZone = SysZone;
current_zone = MR (TheZone);
for (;;)
{
h = (Handle) ZONE_HFST_FREE (current_zone);
if (h)
{
ZONE_HFST_FREE_X (current_zone) = h->p;
h->p = NULL;
SET_MEM_ERR (noErr);
break;
}
else
{
MoreMasters ();
if (MemError () != noErr)
{
SET_MEM_ERR (memFullErr);
break;
}
}
}
MM_SLAM ("exit");
TheZone = save_zone;
return h;
}
Handle
_NewHandle_flags (Size size, boolean_t sys_p, boolean_t clear_p)
{
Handle newh;
block_header_t *block;
THz save_zone, current_zone;
MM_SLAM ("entry");
save_zone = TheZone;
if (sys_p)
TheZone = SysZone;
current_zone = MR (TheZone);
newh = NewEmptyHandle ();
if (newh == NULL)
{
SET_MEM_ERR (memFullErr);
goto done;
}
size += HDRSIZE;
if (ROMlib_relalloc (size, &block) != noErr)
{
DisposHandle (newh);
newh = NULL;
SET_MEM_ERR (memFullErr);
goto done;
}
gui_assert (block < ZONE_BK_LIM (current_zone));
ROMlib_setupblock (block, size, REL, newh, 0);
newh->p = BLOCK_DATA_X (block);
if (clear_p)
memset (BLOCK_DATA (block), 0, size - HDRSIZE);
SET_MEM_ERR (noErr);
/* fall through */
done:
MM_SLAM ("exit");
TheZone = save_zone;
return newh;
}
#define TTS_HACK (ROMlib_options & ROMLIB_DISPOSHANDLE_HACK_BIT)
void
DisposHandle (Handle h)
{
MM_SLAM ("entry");
if (TTS_HACK &&
h == (Handle) (CL (*(long *)SYN68K_TO_US (256)) + ROMlib_offset))
h = 0;
if (h)
{
block_header_t *block;
THz current_zone;
THz save_zone;
save_zone = TheZone;
current_zone = HandleZone (h);
if (!current_zone)
{
SET_MEM_ERR (memAZErr);
return;
}
TheZone = RM (current_zone);
block = HANDLE_TO_BLOCK (h);
if (h->p && BLOCK_TO_HANDLE (MR (TheZone), block) != h)
{
TheZone = save_zone;
SET_MEM_ERR (memAZErr);
return;
}
if (block)
{
if (USE (block) == FREE)
{
TheZone = save_zone;
SET_MEM_ERR (memWZErr);
return;
}
if (HANDLE_STATE (h, block) & RSRCBIT)
{
if (h == (Handle) ROMlib_phoney_name_string)
{
SET_MEM_ERR (memAZErr);
return;
}
warning_unexpected ("disposing resource handle");
}
ROMlib_freeblock (block);
}
h->p = ZONE_HFST_FREE_X (current_zone);
ZONE_HFST_FREE_X (current_zone) = RM ((Ptr) h);
TheZone = save_zone;
}
MM_SLAM ("exit");
SET_MEM_ERR (noErr);
}
Size
GetHandleSize (Handle h)
{
block_header_t *block;
Size retval;
MM_SLAM ("entry");
block = HANDLE_TO_BLOCK (h);
if (block == NULL)
{
SET_MEM_ERR (nilHandleErr);
retval = 0;
}
else if (USE (block) == FREE)
{
SET_MEM_ERR (memWZErr);
return 0;
}
else
{
SET_MEM_ERR (noErr);
retval = LSIZE (block);
}
return retval;
}
void
SetHandleSize (Handle h, Size newsize)
{
block_header_t *block;
int32 oldpsize;
THz save_zone, current_zone;
boolean_t save_memnomove_p;
unsigned int state;
#if defined (X) /* what about NEXTSTEP? */
if (h == MR (TEScrpHandle))
WeOwnScrapX ();
#endif
MM_SLAM ("entry");
newsize += HDRSIZE; /* Header */
block = HANDLE_TO_BLOCK (h);
if (!block)
{
SET_MEM_ERR (nilHandleErr);
return;
}
if (USE (block) == FREE)
{
SET_MEM_ERR (memWZErr);
return;
}
save_zone = TheZone;
current_zone = HandleZone (h);
TheZone = RM (current_zone);
state = HANDLE_STATE (h, block);
oldpsize = PSIZE (block);
if (newsize <= oldpsize)
ROMlib_setupblock (block, newsize, REL, h, state);
else
{
block_header_t *nextblock;
block_header_t *newblock;
nextblock = BLOCK_NEXT (block);
/* First try and grow it forward */
save_memnomove_p = ROMlib_memnomove_p;
if (USE (nextblock) == REL && ROMlib_locked (block))
ROMlib_memnomove_p = FALSE;
if (ROMlib_makespace (&nextblock, newsize - oldpsize))
{
ROMlib_memnomove_p = save_memnomove_p;
ZONE_ZCB_FREE_X (current_zone)
= CL (ZONE_ZCB_FREE (current_zone) - PSIZE (nextblock));
SETPSIZE (block, oldpsize + PSIZE (nextblock));
SETSIZEC (block, 0);
ROMlib_setupblock (block, newsize, REL, h, state);
}
else
{
ROMlib_memnomove_p = save_memnomove_p;
/* At this point, if the block is locked, we lose */
if (ROMlib_locked (block))
goto bad;
GZRootHnd = RM (h);
/* Now try and find the space elsewhere */
if (ROMlib_relalloc (newsize, &newblock))
{
GZRootHnd = NULL;
goto bad;
}
GZRootHnd = NULL;
ROMlib_moveblock (block, newblock, newsize);
}
}
/* And now we're done. */
TheZone = save_zone;
SET_MEM_ERR (noErr);
MM_SLAM ("exit");
return;
bad:
TheZone = save_zone;
MM_SLAM ("exit");
SET_MEM_ERR (memFullErr);
}
#define HANDLE_IN_ZONE_P(handle, z) \
( (unsigned long) (handle) >= (unsigned long) MR (z) \
&& (unsigned long) (handle) < (unsigned long) ZONE_BK_LIM (MR (z)))
#define PTR_IN_ZONE_P(ptr, z) \
( (unsigned long) (ptr) >= (unsigned long) MR (z) \
&& (unsigned long) (ptr) <= (unsigned long) ZONE_BK_LIM (MR (z)))
THz
HandleZone (Handle h)
{
THz zone;
block_header_t *block;
boolean_t applzone_p;
boolean_t syszone_p;
MM_SLAM ("entry");
if (h == NULL)
{
SET_MEM_ERR (nilHandleErr);
return NULL;
}
applzone_p = FALSE;
syszone_p = FALSE;
if (HANDLE_IN_ZONE_P (h, ApplZone))
{
Ptr p;
p = STARH (h);
if (p && !PTR_IN_ZONE_P (p, ApplZone))
{
SET_MEM_ERR (memAZErr);
return NULL;
}
applzone_p = TRUE;
}
else if (HANDLE_IN_ZONE_P (h, SysZone))
{
Ptr p;
p = STARH (h);
if (p && !PTR_IN_ZONE_P (p, SysZone))
{
SET_MEM_ERR (memAZErr);
return NULL;
}
syszone_p = TRUE;
}
/*
* Prevent us from returning a zone when a dereference of the handle would
* cause a segmentation fault.
*
* NOTE: we don't use the SysZone or MemTop low-memory globals, because
* it's possible that they have been modified in such a way that
* this test would fail even with an address that can legitimately
* be dereferenced.
*/
else if (!VALID_ADDRESS (h))
{
SET_MEM_ERR (memAZErr);
return NULL;
}
block = HANDLE_TO_BLOCK (h);
if (block && USE (block) == FREE)
{
SET_MEM_ERR (memWZErr);
return NULL;
}
if (block)
zone = (THz) ((int32) h - (int32) BLOCK_LOCATION_OFFSET (block));
else if (applzone_p)
zone = MR (ApplZone);
else if (syszone_p)
zone = MR (SysZone);
else
zone = MR (TheZone);
SET_MEM_ERR (noErr);
return zone;
}
Handle
_RecoverHandle_flags (Ptr p, boolean_t sys_p)
{
block_header_t *block;
THz zones[3];
Handle h;
int i;
MM_SLAM ("entry");
block = POINTER_TO_BLOCK (p);
if (sys_p)
{
zones[0] = MR (SysZone);
zones[1] = MR (TheZone);
}
else
{
zones[0] = MR (TheZone);
zones[1] = MR (SysZone);
}
zones[2] = MR (ApplZone);
for (i = 0; i < 3; i++)
{
h = BLOCK_TO_HANDLE (zones[i], block);
if ((uint32) h > (uint32) zones[i]
&& (uint32) h < (uint32) ZONE_BK_LIM (zones[i])
&& STARH (h) == p)
break;
}
if (i < 3)
SET_MEM_ERR (noErr);
else
{
h = 0;
#warning FIND OUT WHAT A REAL MAC DOES HERE
}
return h;
}
void
ReallocHandle (Handle h, Size size)
{
block_header_t *oldb, *newb;
int32 newsize;
THz save_zone;
THz current_zone;
unsigned int state;
MM_SLAM ("entry");
if (h == NULL)
warning_unexpected ("called with NULL_STRING handle");
oldb = HANDLE_TO_BLOCK (h);
save_zone = TheZone;
current_zone = HandleZone (h);
TheZone = RM (current_zone);
size += HDRSIZE;
if (!oldb)
state = 0;
else
{
if (ROMlib_locked (oldb))
{
TheZone = save_zone;
SET_MEM_ERR (memPurErr);
return;
}
if (USE (oldb) == FREE)
{
TheZone = save_zone;
SET_MEM_ERR (memWZErr);
return;
}
state = BLOCK_STATE (oldb);
if (PSIZE (oldb) >= (uint32) size)
{
ROMlib_setupblock (oldb, size, REL, h, state);
goto done;
}
newb = BLOCK_NEXT (oldb);
if (USE (newb) == FREE)
{
ROMlib_coalesce (newb);
newsize = PSIZE (oldb) + PSIZE (newb);
if (newsize >= size)
{
SETPSIZE (oldb, newsize);
ZONE_ZCB_FREE_X (current_zone)
= CL (ZONE_ZCB_FREE (current_zone) - PSIZE (newb));
ROMlib_setupblock (oldb, size, REL, h, state);
goto done;
}
}
}
if (ROMlib_relalloc (size, &newb))
{
TheZone = save_zone;
SET_MEM_ERR (memFullErr);
return;
}
ROMlib_setupblock (newb, size, REL, h, state);
SETMASTER (h, BLOCK_DATA (newb));
if (oldb)
ROMlib_freeblock (oldb);
/* fall through */
done:
TheZone = save_zone;
MM_SLAM ("exit");
SET_MEM_ERR (noErr);
}
#if 1 && !defined(NDEBUG)
int do_save_alloc = 0;
#endif
Ptr
_NewPtr_flags (Size size, boolean_t sys_p, boolean_t clear_p)
{
Ptr p;
block_header_t *b;
THz save_zone, current_zone;
#if 1
block_header_t *save_alloc_ptr;
#endif
MM_SLAM ("entry");
save_zone = TheZone;
if (sys_p)
TheZone = SysZone;
current_zone = MR (TheZone);
size += HDRSIZE;
#if 1
save_alloc_ptr = (typeof (save_alloc_ptr)) ZONE_ALLOC_PTR_X (current_zone);
#endif
ZONE_ALLOC_PTR_X (current_zone) = CLC_NULL;
ResrvMem (size);
if (ROMlib_relalloc (size, &b))
{
#if 0
ZONE_ALLOC_PTR_X (current_zone) = save_alloc_ptr;
#endif
TheZone = save_zone;
SET_MEM_ERR (memFullErr);
MM_SLAM ("exit");
return NULL;
}
#if 1 && !defined(NDEBUG)
if (do_save_alloc)
ZONE_ALLOC_PTR_X (current_zone)
= (typeof (ZONE_ALLOC_PTR_X (current_zone))) save_alloc_ptr;
else
checkallocptr ();
#endif
gui_assert (b < ZONE_BK_LIM (current_zone));
ROMlib_setupblock (b, size, NREL, 0);
p = BLOCK_DATA (b);
if (clear_p)
memset (p, 0, size - HDRSIZE);
TheZone = save_zone;
SET_MEM_ERR (noErr);
MM_SLAM ("exit");
return p;
}
void
DisposPtr (Ptr p)
{
MM_SLAM ("entry");
if (p)
{
block_header_t *block;
THz zone;
block = POINTER_TO_BLOCK (p);
if (USE (block) == FREE)
{
SET_MEM_ERR (memWZErr);
return;
}
zone = PtrZone (p);
if (zone)
{
ZONE_SAVE_EXCURSION
(RM (zone),
{
ROMlib_freeblock (block);
});
}
else
warning_unexpected (NULL_STRING);
}
SET_MEM_ERR (noErr);
MM_SLAM ("exit");
}
Size
GetPtrSize (Ptr p)
{
block_header_t *block;
MM_SLAM ("entry");
block = POINTER_TO_BLOCK (p);
if (USE (block) == FREE)
{
SET_MEM_ERR (memWZErr);
return 0;
}
SET_MEM_ERR (noErr);
MM_SLAM ("exit");
return LSIZE (block);
}
void
SetPtrSize (Ptr p, Size newsize)
{
block_header_t *block;
LONGINT oldpsize;
THz save_zone, current_zone;
MM_SLAM ("entry");
if (p == NULL)
warning_unexpected ("attempt to set NULL_STRING pointer size");
newsize += HDRSIZE;
block = POINTER_TO_BLOCK (p);
if (USE (block) == FREE)
{
SET_MEM_ERR (memWZErr);
return;
}
save_zone = TheZone;
current_zone = PtrZone (p);
if (!current_zone)
{
warning_unexpected (NULL_STRING);
SET_MEM_ERR (memWZErr); /* Not really sure what we should return in
this case. It's not like the Mac has any
decent error semantics */
}
else
{
TheZone = RM (current_zone);
oldpsize = PSIZE (block);
if (newsize <= oldpsize)
ROMlib_setupblock (block, newsize, NREL, 0);
else
{
block_header_t *nextblock;
nextblock = BLOCK_NEXT (block);
/* First try and grow it forward */
if (ROMlib_makespace (&nextblock, newsize - oldpsize))
{
ZONE_ZCB_FREE_X (current_zone)
= CL (ZONE_ZCB_FREE_X (current_zone) - PSIZE (nextblock));
SETPSIZE (block, oldpsize + PSIZE (nextblock));
SETSIZEC (block, 0);
ROMlib_setupblock (block, newsize, NREL, 0);
}
else
{
TheZone = save_zone;
SET_MEM_ERR (memFullErr);
return;
}
}
}
/* And now we're done. */
TheZone = save_zone;
SET_MEM_ERR (noErr);
MM_SLAM ("exit");
}
PRIVATE boolean_t
legit_addr_p (void *addr)
{
boolean_t retval;
retval = TRUE; /* all addresses are valid for now */
return retval;
}
PRIVATE boolean_t
legit_zone_p (THz zone)
{
boolean_t retval;
if (!legit_addr_p (zone))
retval = FALSE;
else
{
block_header_t *blockp;
blockp = ZONE_HEAP_DATA (zone);
retval = (THz) blockp->location_u == RM (zone);
}
return retval;
}
THz
PtrZone (Ptr p)
{
block_header_t *block;
THz zone;
MM_SLAM ("entry");
if (p == NULL)
warning_unexpected ("attempt to set NULL_STRING pointer size");
block = POINTER_TO_BLOCK (p);
if (USE (block) == FREE)
{
SET_MEM_ERR (memWZErr);
/* don't count on this value (IMII-38) */
return NULL;
}
zone = (THz) BLOCK_LOCATION_ZONE (block);
if (!legit_zone_p (zone))
{
SET_MEM_ERR (memWZErr); /* not sure what this should be */
return NULL;
}
SET_MEM_ERR (noErr);
return zone;
}
int32
_FreeMem_flags (boolean_t sys_p)
{
uint32 freespace;
MM_SLAM ("entry");
if (sys_p)
freespace = ZONE_ZCB_FREE (MR (SysZone));
else
freespace = ZONE_ZCB_FREE (MR (TheZone));
SET_MEM_ERR (noErr);
return freespace;
}
Size
_MaxMem_flags (Size *growp, boolean_t sys_p)
{
block_header_t *b;
THz save_zone;
THz current_zone;
uint32 biggestfree;
uint32 sizesofar;
block_header_t *startb;
Size grow;
enum { SEARCHING, COUNTING } state;
MM_SLAM ("entry");
sizesofar = 0;
startb = 0;
save_zone = TheZone;
if (sys_p)
TheZone = SysZone;
current_zone = MR (TheZone);
/* Purge everyone */
for (b = ZONE_HEAP_DATA (current_zone);
b != ZONE_BK_LIM (current_zone);
b = BLOCK_NEXT (b))
{
Handle h;
if (PSIZE (b) < MIN_BLOCK_SIZE)
HEAP_DEATH ();
h = BLOCK_TO_HANDLE (current_zone, b);
if (USE (b) == REL
&& (HANDLE_STATE (h, b) & (LOCKBIT | PURGEBIT)) == PURGEBIT)
EmptyHandle (h);
}
/* Compact the whole thing */
CompactMem (0x7FFFFFFF);
/* Compress the free blocks */
state = SEARCHING;
biggestfree = 0;
for (b = ZONE_HEAP_DATA (current_zone);
b != ZONE_BK_LIM (current_zone);
b = BLOCK_NEXT (b))
{
if (PSIZE (b) < MIN_BLOCK_SIZE)
HEAP_DEATH ();
if (state == SEARCHING)
{
if (USE (b) == FREE)
{
startb = b;
sizesofar = PSIZE (b);
state = COUNTING;
}
}
else
{
if (USE (b) == FREE)
sizesofar += PSIZE (b);
else
{
SETPSIZE (startb, sizesofar);
if (ZONE_ALLOC_PTR (current_zone) > startb
&& ((char *) ZONE_ALLOC_PTR (current_zone)
< (char *) startb + sizesofar))
ZONE_ALLOC_PTR_X (current_zone) = RM ((Ptr) startb);
if (sizesofar > biggestfree)
biggestfree = sizesofar;
state = SEARCHING;
}
}
}
if (state == COUNTING)
{
SETPSIZE (startb, sizesofar);
if (ZONE_ALLOC_PTR (current_zone) > startb
&& ((char *) ZONE_ALLOC_PTR (current_zone)
< (char *) startb + sizesofar))
ZONE_ALLOC_PTR_X (current_zone) = RM ((Ptr) startb);
if (sizesofar > biggestfree)
biggestfree = sizesofar;
}
if (TheZone == ApplZone)
grow = (uint32) MR (ApplLimit) - (uint32) HEAPEND;
else
grow = 0;
TheZone = save_zone;
*growp = grow;
SET_MEM_ERR (noErr);
MM_SLAM ("exit");
return biggestfree;
}
Size
_CompactMem_flags (Size sizeneeded, boolean_t sys_p)
{
int32 amtfree;
block_header_t *src, *target, *ap;
THz save_zone;
THz current_zone;
boolean_t startfront_p;
MM_SLAM ("entry");
save_zone = TheZone;
if (sys_p)
TheZone = SysZone;
current_zone = MR (TheZone);
/* We've seen HyperCard load allocPtr with -8 before ... yahoo.
Specifically, HC 2.1 would do this after you use the Chart making
stack to make a chart and then you try to "Go Home" via the menu */
ap = ZONE_ALLOC_PTR (current_zone);
if (ap >= ZONE_HEAP_DATA (current_zone)
&& ap <= ZONE_BK_LIM (current_zone))
src = target = ap;
else
src = target = ZONE_HEAP_DATA (current_zone);
startfront_p = (src == ZONE_HEAP_DATA (current_zone));
repeat:
ZONE_ALLOC_PTR_X (current_zone) = CLC_NULL;
amtfree = 0;
while (src != ZONE_BK_LIM (current_zone)
&& amtfree < sizeneeded)
{
if (USE (src) == REL && !ROMlib_locked (src))
{
if (src == target)
src = target = BLOCK_NEXT (target);
else if (src < target)
gui_abort ();
else
{
*target = *src;
SETMASTER (BLOCK_TO_HANDLE (current_zone, src),
BLOCK_DATA (target));
BlockMove (BLOCK_DATA (src), BLOCK_DATA (target), LSIZE (src));
src = (block_header_t *) ((char *) src + PSIZE (target));
target = BLOCK_NEXT (target);
}
}
else if (USE (src) == FREE)
src = BLOCK_NEXT (src);
else
{
if (src > target)
{
int32 src_target_diff = (char *) src - (char *) target;
mm_set_block_fields_offset (target,
FREE_BLOCK_STATE, FREE, 0,
src_target_diff, 0);
if (src_target_diff > amtfree)
{
amtfree = src_target_diff;
if (!ZONE_ALLOC_PTR_X (current_zone))
ZONE_ALLOC_PTR_X (current_zone) = (Ptr) RM (target);
}
}
src = target = BLOCK_NEXT (src);
}
}
/* If we got out because we hit the end, do the last case above for
the final free block. */
if (src == ZONE_BK_LIM (current_zone) && src > target)
{
int32 src_target_diff = (char *) src - (char *) target;
mm_set_block_fields_offset (target,
FREE_BLOCK_STATE, FREE, 0,
src_target_diff, 0);
if (src_target_diff > amtfree)
{
amtfree = src_target_diff;
if (!ZONE_ALLOC_PTR_X (current_zone))
ZONE_ALLOC_PTR_X (current_zone) = RM ((Ptr) target);
}
}
if (amtfree < sizeneeded && !startfront_p)
{
startfront_p = TRUE;
src = target = ZONE_HEAP_DATA (current_zone);
goto repeat;
}
TheZone = save_zone;
SET_MEM_ERR (noErr);
MM_SLAM ("exit");
return amtfree;
}
void
_ResrvMem_flags (Size needed, boolean_t sys_p)
{
THz save_zone;
THz current_zone;
block_header_t *b;
Size free;
long avail;
boolean_t already_maxed_p;
MM_SLAM ("entry");
if (needed <= 0)
{
SET_MEM_ERR (noErr);
return;
}
save_zone = TheZone;
if (sys_p)
TheZone = SysZone;
current_zone = MR (TheZone);
already_maxed_p = FALSE;
again:
for (b = ZONE_HEAP_DATA (current_zone);
b != ZONE_BK_LIM (current_zone);
b = BLOCK_NEXT (b))
{
if (PSIZE (b) < MIN_BLOCK_SIZE)
HEAP_DEATH ();
if (ROMlib_makespace (&b, needed))
{
TheZone = save_zone;
MM_SLAM ("exit");
SET_MEM_ERR (noErr);
return;
}
}
avail = MaxMem (&free);
if (avail >= needed && !already_maxed_p)
{
already_maxed_p = TRUE;
goto again;
}
if (free >= needed)
{
/* relalloc will do the actual extension. */
TheZone = save_zone;
MM_SLAM ("exit");
SET_MEM_ERR (noErr);
return;
}
TheZone = save_zone;
MM_SLAM ("exit");
SET_MEM_ERR (memFullErr);
}
void
_PurgeMem_flags (Size sizeneeded, boolean_t sys_p)
{
long amount_free, max_free;
block_header_t *b;
THz save_zone;
THz current_zone;
MM_SLAM ("entry");
amount_free = 0;
save_zone = TheZone;
if (sys_p)
TheZone = SysZone;
current_zone = MR (TheZone);
max_free = 0;
for (b = ZONE_HEAP_DATA (current_zone);
b != ZONE_BK_LIM (current_zone);
b = BLOCK_NEXT (b))
{
Handle h;
if (PSIZE (b) < MIN_BLOCK_SIZE)
HEAP_DEATH ();
h = BLOCK_TO_HANDLE (current_zone, b);
if (USE (b) == REL
&& (HANDLE_STATE (h, b) & (LOCKBIT | PURGEBIT)) == PURGEBIT)
EmptyHandle (h);
amount_free = ROMlib_amtfree (b);
if (amount_free >= max_free)
max_free = amount_free;
if (amount_free >= sizeneeded)
break;
}
TheZone = save_zone;
if (amount_free < sizeneeded)
SET_MEM_ERR (memFullErr);
else
SET_MEM_ERR (noErr);
MM_SLAM ("exit");
}
PRIVATE void
BlockMove_and_possibly_flush_cache (Ptr src, Ptr dst, Size cnt,
boolean_t flush_p)
{
if (cnt > 0)
{
/* ugly, but probably better than crashing when we try to
dereference 0 */
if (!dst)
dst = (Ptr) SYN68K_TO_US (dst);
if (!src)
src = (Ptr) SYN68K_TO_US (src);
memmove_transfer (dst, src, cnt);
if (flush_p)
ROMlib_destroy_blocks ((syn68k_addr_t) US_TO_SYN68K(dst), cnt, TRUE);
}
/* don't use `SET_MEM_ERR' since that will do a heap slam and we
will lose */
MemErr = CWC (noErr);
}
void
BlockMove (Ptr src, Ptr dst, Size cnt)
{
BlockMove_and_possibly_flush_cache (src, dst, cnt, TRUE);
}
void
BlockMoveData (Ptr src, Ptr dst, Size cnt)
{
BlockMove_and_possibly_flush_cache (src, dst, cnt, FALSE);
}
void
BlockMove_the_trap (Ptr src, Ptr dst, Size cnt, boolean_t flush_p)
{
MM_SLAM ("entry");
BlockMove_and_possibly_flush_cache (src, dst, cnt, flush_p);
MM_SLAM ("exit");
}
void
MaxApplZone (void)
{
MM_SLAM ("entry");
/* #warning MaxApplZone does not do anything -- we start out with max */
SET_MEM_ERR (noErr);
}
void
MoveHHi (Handle h)
{
MM_SLAM ("entry");
/* Oh No! More Lemmings appears to assume that MoveHHi will
* flush the cache. This is not an unreasonable assumption, since
* large BlockMove's are guaranteed to flush the cache, and
* MoveHHi of a large piece of memory would typically involve a
* big BlockMove. Since MoveHHi isn't called very often,
* and is expected to be fairly slow, we use this opportunity
* to flush the cache. We only nuke code whose checksums
* have changed, for speed.
*
* We make an exception for Microsoft Word, because the spelling checker
* will be real slow if we don't.
*/
if (ROMlib_creator != TICK ("MSWD") && ROMlib_creator != TICK ("ddOr"))
ROMlib_destroy_blocks (0, ~0, TRUE);
/* #### there used to be a lot of code here; but it was unused and
returned noErr #if !MOVEHIWORKS -- see the rcsfile for details */
/* #warning MoveHHi not implemented */
/* #### just emits too many unecessary warnings
warning_unimplemented (""); */
SET_MEM_ERR (noErr);
}
int32
_MaxBlock_flags (boolean_t sys_p)
{
THz save_zone;
THz current_zone;
int32 max_free;
int32 total_free;
block_header_t *b;
MM_SLAM ("entry");
save_zone = TheZone;
if (sys_p)
TheZone = SysZone;
current_zone = MR (TheZone);
max_free = total_free = 0;
for (b = ZONE_HEAP_DATA (current_zone);
b != ZONE_BK_LIM (current_zone);
b = BLOCK_NEXT (b))
{
if (PSIZE (b) < MIN_BLOCK_SIZE)
HEAP_DEATH ();
if (USE (b) == FREE)
total_free += PSIZE (b);
else if (USE (b) == NREL || ROMlib_locked (b))
{
if (total_free > max_free)
max_free = total_free;
total_free = 0;
}
}
TheZone = save_zone;
SET_MEM_ERR (noErr);
MM_SLAM ("exit");
return MAX (total_free, max_free) - HDRSIZE;
}
void
_PurgeSpace_flags (Size *total_out, Size *contig_out, boolean_t sys_p)
{
THz save_zone, current_zone;
int32 total_free;
int32 this_contig;
int32 max_contig;
block_header_t *b;
MM_SLAM ("entry");
save_zone = TheZone;
if (sys_p)
TheZone = SysZone;
current_zone = MR (TheZone);
total_free = this_contig = max_contig = 0;
for (b = ZONE_HEAP_DATA (current_zone);
b != ZONE_BK_LIM (current_zone);
b = BLOCK_NEXT (b))
{
Handle h;
if (PSIZE (b) < MIN_BLOCK_SIZE)
HEAP_DEATH ();
h = BLOCK_TO_HANDLE (current_zone, b);
if (USE (b) == FREE
|| (USE (b) == REL
&& (HANDLE_STATE (h, b) & (LOCKBIT | PURGEBIT)) == PURGEBIT))
{
this_contig += PSIZE (b);
total_free += PSIZE (b);
}
else if (USE (b) == NREL || ROMlib_locked (b))
{
if (this_contig > max_contig)
max_contig = this_contig;
this_contig = 0;
}
}
TheZone = save_zone;
SET_MEM_ERR (noErr);
*total_out = total_free - HDRSIZE;
*contig_out = MAX (this_contig, max_contig) - HDRSIZE;
MM_SLAM ("exit");
}
Size
StackSpace (void)
{
int32 fp;
MM_SLAM ("entry");
fp = (int32) SYN68K_TO_US (EM_A7);
/* Stack pointer on return is fp + 8 (4 for old fp, 4 for return
address) */
SET_MEM_ERR (noErr);
return (fp + 8) - (int32) HEAPEND;
}
void
SetApplLimit (Ptr new_limit)
{
/* NOTE TO CLIFF:
We can't do any sanity checks here (not even a brk()), since
the ApplLimit might be directly changed by programs, and we have
to deal with that. */
/* Making the ApplLimit too small has no effect (IMII-30), and making
it too big shouldn't cause a problem until the excess memory starts
being used (by incrementation of HEAPEND). */
MM_SLAM ("entry");
ApplLimit = RM (new_limit);
HeapEnd = RM (new_limit - MIN_BLOCK_SIZE);
SET_MEM_ERR (noErr);
}
void
SetGrowZone (ProcPtr newgz)
{
MM_SLAM ("entry");
ZONE_GZ_PROC_X (MR (TheZone)) = RM (newgz);
SET_MEM_ERR (noErr);
}
void
EmptyHandle (Handle h)
{
THz save_zone, current_zone;
block_header_t *b;
MM_SLAM ("entry");
b = HANDLE_TO_BLOCK (h);
if (b == NULL)
{
SET_MEM_ERR (noErr);
return;
}
save_zone = TheZone;
current_zone = HandleZone (h);
TheZone = RM (current_zone);
if (ROMlib_locked (b))
{
TheZone = save_zone;
SET_MEM_ERR (memPurErr);
return;
}
if (USE (b) == FREE)
{
TheZone = save_zone;
SET_MEM_ERR (memWZErr);
return;
}
if (ZONE_PURGE_PROC_X (current_zone))
{
uint32 saved0, saved1, saved2, savea0, savea1;
ROMlib_hook (memory_purgeprocnumber);
saved0 = EM_D0;
saved1 = EM_D1;
saved2 = EM_D2;
savea0 = EM_A0;
savea1 = EM_A1;
PUSHADDR ((long) US_TO_SYN68K (h));
CALL_EMULATOR ((syn68k_addr_t)
US_TO_SYN68K (ZONE_PURGE_PROC (current_zone)));
EM_D0 = saved0;
EM_D1 = saved1;
EM_D2 = saved2;
EM_A0 = savea0;
EM_A1 = savea1;
}
ROMlib_freeblock (b);
SETMASTER (h, NULL);
TheZone = save_zone;
MM_SLAM ("exit");
SET_MEM_ERR (noErr);
}
/* Fluff for Cliff */
void
ROMlib_installhandle (Handle sh, Handle dh)
{
THz save_zone;
MM_SLAM ("entry");
save_zone = TheZone;
TheZone = RM (HandleZone (dh));
if (TRUE
|| ROMlib_locked (HANDLE_TO_BLOCK (dh))
|| HandleZone (sh) != MR (TheZone))
{
Size size;
size = GetHandleSize (sh);
SetHandleSize (dh, size);
if (MemErr == CWC (noErr))
BlockMove (STARH (sh), STARH (dh), size);
DisposHandle (sh);
}
else
{
block_header_t *db = HANDLE_TO_BLOCK (dh);
block_header_t *sb = HANDLE_TO_BLOCK (sh);
ROMlib_freeblock (db);
SETMASTER (dh, STARH (sh));
BLOCK_LOCATION_OFFSET_X (sb) = CL ((uint32) dh - (uint32) MR (TheZone));
sh->p = (Ptr) ZONE_HFST_FREE_X (MR (TheZone));
ZONE_HFST_FREE_X (MR (TheZone)) = RM ((Ptr) sh);
}
TheZone = save_zone;
MM_SLAM ("exit");
}
OSErr
MemError (void)
{
MM_SLAM ("entry");
return CW (MemErr);
}
THz
SystemZone (void)
{
MM_SLAM ("entry");
return MR (SysZone);
}
THz
ApplicZone (void)
{
MM_SLAM ("entry");
return MR (ApplZone);
}
/* Like NewHandle, but fills in the newly allocated memory by copying
* data from the supplied pointer. Use the NewHandle_copy_ptr and
* NewHandleSys_copy_ptr macros to access this function.
*/
Handle
_NewHandle_copy_ptr_flags (Size size, const void *data_to_copy,
boolean_t sys_p)
{
Handle h;
h = _NewHandle_flags (size, sys_p, FALSE);
if (MemErr == CWC (noErr))
memcpy (STARH (h), data_to_copy, size);
return h;
}
/* Like NewHandle, but fills in the newly allocated memory by copying
* data from the supplied Handle. Use the NewHandle_copy_handle and
* NewHandleSys_copy_handle macros to access this function.
*/
Handle
_NewHandle_copy_handle_flags (Size size, Handle data_to_copy, boolean_t sys_p)
{
Handle h;
if (GetHandleSize (data_to_copy) < size)
warning_unexpected ("Not enough bytes to copy!");
h = _NewHandle_flags (size, sys_p, FALSE);
if (MemErr == CWC (noErr))
memcpy (STARH (h), STARH (data_to_copy), size);
return h;
}
/* Like NewPtr, but fills in the newly allocated memory by copying
* data from the supplied pointer. Use the NewPtr_copy_ptr and
* NewPtrSys_copy_ptr macros to access this function.
*/
Ptr
_NewPtr_copy_ptr_flags (Size size, const void *data_to_copy,
boolean_t sys_p)
{
Ptr p;
p = _NewPtr_flags (size, sys_p, FALSE);
if (MemErr == CWC (noErr))
memcpy (p, data_to_copy, size);
return p;
}
/* Like NewPtr, but fills in the newly allocated memory by copying
* data from the supplied Handle. Use the NewPtr_copy_handle and
* NewPtrSys_copy_handle macros to access this function.
*/
Ptr
_NewPtr_copy_handle_flags (Size size, Handle data_to_copy, boolean_t sys_p)
{
Ptr p;
if (GetHandleSize (data_to_copy) < size)
warning_unexpected ("Not enough bytes to copy!");
p = _NewPtr_flags (size, sys_p, FALSE);
if (MemErr == CWC (noErr))
memcpy (p, STARH (data_to_copy), size);
return p;
}