2179 lines
44 KiB
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;
|
|
}
|