mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
359 lines
8.2 KiB
359 lines
8.2 KiB
/*++
|
|
|
|
Copyright (c) 1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
memory.cxx
|
|
|
|
Abstract:
|
|
|
|
This file contains the new and delete operators for memory management in
|
|
the RPC runtime for the Macintosh system. Rather than using the memory
|
|
management provided by the C++ system (which may not even exist) we will
|
|
write our own.
|
|
|
|
Cloned from NT's memory.cxx
|
|
|
|
Author:
|
|
|
|
Mario Goertzel (mariogo) 18-Oct-1994
|
|
|
|
Revision History:
|
|
|
|
18-Oct-1994 (mariogo) Cloned from NT's memory.cxx
|
|
|
|
--*/
|
|
|
|
#include <sysinc.h>
|
|
#include <rpc.h>
|
|
#include <util.hxx>
|
|
|
|
/* ***************************************************************** *\
|
|
|
|
Mac memory layout:
|
|
|
|
High Mem -> ('high memory' owned by the system or another app)
|
|
Top of your A5 world (A5+32k)
|
|
App Jump Table
|
|
App Jump Table
|
|
|
|
|
|
Application Parameters (and ptr to QD globals)
|
|
Your A5+0
|
|
App 'near' Globals
|
|
App 'near' Globals
|
|
|
|
QuickDraw Globals
|
|
QuickDraw Globals
|
|
|
|
Bottom of your A5 world (A5-32k)
|
|
Stack Base
|
|
Stack (growing down)
|
|
Stack
|
|
|
|
|
|
|
|
------------------- (ApplLimit between stack and heap)
|
|
Top of Heap
|
|
Short term fixed blocks
|
|
|
|
|
|
Relocatable blocks
|
|
Relocatable blocks
|
|
|
|
Relocatable blocks
|
|
|
|
Long term fixed blocks
|
|
Bottom of Heap
|
|
Low -> ('low memory' owned by system or another app)
|
|
|
|
Notes:
|
|
|
|
Blank lines represent areas which are quite possibly free.
|
|
|
|
Your apps code is off someplace else. Hard to say where esp. since
|
|
it is swapped by VM and/or the swapper stuff.
|
|
|
|
Summary of A5 World:
|
|
|
|
The A5 register points into the center of the applications
|
|
A5 world. The world in 64K. It is reference by an offset
|
|
from A5 +- signed short. Using a 16bit offset is both
|
|
faster and smaller then using full 32bit addresses.
|
|
|
|
A5 +N contains
|
|
1) Application jump table (calls between segments fixed up here)
|
|
2) App parameters (32b) for passing args to system
|
|
3) App parameters contain pointer to QuickDraw globals.
|
|
|
|
A5 -N contains
|
|
1) Your applications 'near' globals. (limited to <32K)
|
|
2) The QuickDraw globals. (Used by QD (ie GDI), for
|
|
storage and better performance)
|
|
|
|
NOTE: If A5 ever gets trashed you are hosed.
|
|
|
|
Stack Overflows:
|
|
|
|
If you overflow stack you will always trash to heap from high to low.
|
|
|
|
Check buffers first, since they are high in the stack.
|
|
|
|
Your sp is checked against the ApplLimit line by the Virtical
|
|
Retrace Manager (60Hz) which does a SysErr() on overflows.
|
|
|
|
Checked builds include stack checking on each function call.
|
|
|
|
Summary of RPC allocation rules on the Mac:
|
|
|
|
RPC expects all memory to be fixed. This is not changing.
|
|
|
|
Since the new and delete operators are only used for RPC data structures
|
|
(which have a long life) they are allocated low in the heap. In contrast
|
|
things allocated with RpcpFarAlloc() (buffers and stub mem) are allocated
|
|
and then moved high in the heap before they are fixed.
|
|
|
|
\* ***************************************************************** */
|
|
|
|
inline void * __nw_do (
|
|
IN size_t size
|
|
)
|
|
{
|
|
return(NewPtr(size));
|
|
|
|
}
|
|
|
|
inline void __dl_do (
|
|
IN void *p
|
|
)
|
|
{
|
|
DisposePtr((char *)p);
|
|
}
|
|
|
|
#ifndef DEBUGRPC
|
|
|
|
// Retail heap
|
|
|
|
void *
|
|
operator new (
|
|
IN size_t size
|
|
)
|
|
{
|
|
return(__nw_do(size));
|
|
}
|
|
|
|
void
|
|
operator delete (
|
|
IN void * obj
|
|
)
|
|
{
|
|
__dl_do(obj);
|
|
}
|
|
|
|
#else
|
|
|
|
// Checked heap
|
|
|
|
typedef struct _RPC_MEMORY_BLOCK
|
|
{
|
|
// Guards the very beginning of the memory block. We validate this
|
|
// before messing with the rest of the block.
|
|
|
|
unsigned char blockguard[4];
|
|
|
|
// Specifies the size of the block of memory in bytes.
|
|
|
|
unsigned long size;
|
|
|
|
// The next block in the chain of allocated blocks.
|
|
|
|
struct _RPC_MEMORY_BLOCK * next;
|
|
|
|
// The previous block in the chain of allocated blocks; this makes
|
|
// deletion of a block simpler.
|
|
|
|
struct _RPC_MEMORY_BLOCK * previous;
|
|
|
|
// Pad so that the end of the frontguard (and hence the beginning of
|
|
// the block passed to the user) is on a 0 mod 8 boundary.
|
|
|
|
unsigned long pad;
|
|
|
|
// Reserve an extra 4 bytes as the front guard of each block.
|
|
|
|
unsigned char frontguard[4];
|
|
|
|
// Reserve an extra 4 bytes as the rear guard of each block.
|
|
|
|
unsigned char rearguard[4];
|
|
} RPC_MEMORY_BLOCK;
|
|
|
|
RPC_MEMORY_BLOCK * AllocatedBlocks = 0;
|
|
|
|
int
|
|
CheckMemoryBlock (
|
|
RPC_MEMORY_BLOCK * block
|
|
)
|
|
{
|
|
if ( (block->blockguard[0] != 0xBA)
|
|
|| (block->blockguard[1] != 0xAD)
|
|
|| (block->blockguard[2] != 0xB0)
|
|
|| (block->blockguard[3] != 0x0B))
|
|
{
|
|
PrintToDebugger("RPC : BAD BLOCK (block) @ %08lx\n",&(block->rearguard[0]));
|
|
ASSERT(0);
|
|
return(1);
|
|
}
|
|
|
|
if ( (block->frontguard[0] != 0xBA)
|
|
|| (block->frontguard[1] != 0xAD)
|
|
|| (block->frontguard[2] != 0xB0)
|
|
|| (block->frontguard[3] != 0x0B))
|
|
{
|
|
PrintToDebugger("RPC : BAD BLOCK (front) @ %08lx\n",&(block->rearguard[0]));
|
|
ASSERT(0);
|
|
return(1);
|
|
}
|
|
|
|
if ( (block->rearguard[block->size] != 0xBA)
|
|
|| (block->rearguard[block->size+1] != 0xAD)
|
|
|| (block->rearguard[block->size+2] != 0xB0)
|
|
|| (block->rearguard[block->size+3] != 0x0B))
|
|
{
|
|
PrintToDebugger("RPC : BAD BLOCK (rear) @ %08lx\n",&(block->rearguard[0]));
|
|
ASSERT(0);
|
|
return(1);
|
|
}
|
|
if ( block->next != 0)
|
|
{
|
|
ASSERT(block->next->previous == block);
|
|
}
|
|
if ( block->previous != 0)
|
|
{
|
|
ASSERT(block->previous->next == block);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
int // Returns zero if the heap is ok, and non-zero otherwise.
|
|
CheckLocalHeapDo (
|
|
void
|
|
)
|
|
{
|
|
RPC_MEMORY_BLOCK * block;
|
|
|
|
RequestGlobalMutex();
|
|
|
|
block = AllocatedBlocks;
|
|
while (block != 0)
|
|
{
|
|
if (CheckMemoryBlock(block))
|
|
{
|
|
ClearGlobalMutex();
|
|
return(1);
|
|
}
|
|
block = block->next;
|
|
}
|
|
|
|
ClearGlobalMutex();
|
|
return(0);
|
|
}
|
|
|
|
int
|
|
RpcpCheckHeap (
|
|
void
|
|
)
|
|
{
|
|
int retval;
|
|
|
|
RequestGlobalMutex();
|
|
retval = CheckLocalHeapDo();
|
|
ClearGlobalMutex();
|
|
return(retval);
|
|
}
|
|
|
|
void *
|
|
operator new(
|
|
size_t size
|
|
)
|
|
{
|
|
RPC_MEMORY_BLOCK * block;
|
|
|
|
RequestGlobalMutex();
|
|
block = (RPC_MEMORY_BLOCK *) __nw_do(size + sizeof(RPC_MEMORY_BLOCK));
|
|
CheckLocalHeapDo();
|
|
if ( block == 0 )
|
|
{
|
|
ClearGlobalMutex();
|
|
return(0);
|
|
}
|
|
block->size = size;
|
|
block->pad = 0xFEEDBEEF;
|
|
|
|
if (AllocatedBlocks != 0)
|
|
AllocatedBlocks->previous = block;
|
|
|
|
block->next = AllocatedBlocks;
|
|
block->previous = 0;
|
|
AllocatedBlocks = block;
|
|
|
|
block->blockguard[0] = 0xBA;
|
|
block->blockguard[1] = 0xAD;
|
|
block->blockguard[2] = 0xB0;
|
|
block->blockguard[3] = 0x0B;
|
|
|
|
block->frontguard[0] = 0xBA;
|
|
block->frontguard[1] = 0xAD;
|
|
block->frontguard[2] = 0xB0;
|
|
block->frontguard[3] = 0x0B;
|
|
|
|
block->rearguard[size] = 0xBA;
|
|
block->rearguard[size+1] = 0xAD;
|
|
block->rearguard[size+2] = 0xB0;
|
|
block->rearguard[size+3] = 0x0B;
|
|
|
|
ClearGlobalMutex();
|
|
return(&(block->rearguard[0]));
|
|
}
|
|
|
|
void
|
|
operator delete (
|
|
IN void * obj
|
|
)
|
|
{
|
|
RPC_MEMORY_BLOCK * block;
|
|
|
|
if (obj == 0)
|
|
return;
|
|
|
|
RequestGlobalMutex();
|
|
block = (RPC_MEMORY_BLOCK *) (((unsigned char *) obj)
|
|
- sizeof(RPC_MEMORY_BLOCK) + 4);
|
|
CheckMemoryBlock(block);
|
|
if (block->next != 0)
|
|
{
|
|
CheckMemoryBlock(block->next);
|
|
ASSERT(block->next->previous == block);
|
|
}
|
|
if (block->previous != 0)
|
|
{
|
|
CheckMemoryBlock(block->previous);
|
|
ASSERT(block->previous->next == block);
|
|
}
|
|
if (block == AllocatedBlocks)
|
|
AllocatedBlocks = block->next;
|
|
if (block->next != 0)
|
|
block->next->previous = block->previous;
|
|
if (block->previous != 0)
|
|
block->previous->next = block->next;
|
|
CheckLocalHeapDo();
|
|
memset(block,0xEF,(unsigned int) (block->size+sizeof(RPC_MEMORY_BLOCK))) ;
|
|
|
|
ClearGlobalMutex();
|
|
__dl_do(block);
|
|
}
|
|
|
|
#endif DEBUGRPC
|
|
|
|
// rpcfar alloc and far free moved to miscmac
|