home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Windows Gam…ming Gurus (2nd Edition)
/
Disc2.iso
/
vc98
/
crt
/
src
/
heapinit.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-06-17
|
16KB
|
658 lines
/***
*heapinit.c - Initialze the heap
*
* Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
*
*Purpose:
*
*******************************************************************************/
#ifdef WINHEAP
#include <cruntime.h>
#include <malloc.h>
#include <winheap.h>
HANDLE _crtheap;
/*
* Dummy definition of _amblksiz. Included primarily so the dll will build
* without having to change crtlib.c (there is an access function for _amblksiz
* defined in crtlib.c).
*/
unsigned int _amblksiz = BYTES_PER_PARA;
/***
*_heap_init() - Initialize the heap
*
*Purpose:
* Setup the initial C library heap.
*
* NOTES:
* (1) This routine should only be called once!
* (2) This routine must be called before any other heap requests.
*
*Entry:
* <void>
*Exit:
* Returns 1 if successful, 0 otherwise.
*
*Exceptions:
* If heap cannot be initialized, the program will be terminated
* with a fatal runtime error.
*
*******************************************************************************/
int __cdecl _heap_init (
int mtflag
)
{
// Initialize the "big-block" heap first.
if ( (_crtheap = HeapCreate( mtflag ? 0 : HEAP_NO_SERIALIZE,
BYTES_PER_PAGE, 0 )) == NULL )
return 0;
// Initialize the small-block heap
if (__sbh_heap_init() == 0)
{
HeapDestroy(_crtheap);
return 0;
}
return 1;
}
/***
*_heap_term() - return the heap to the OS
*
*Purpose:
*
* NOTES:
* (1) This routine should only be called once!
* (2) This routine must be called AFTER any other heap requests.
*
*Entry:
* <void>
*Exit:
* <void>
*
*Exceptions:
*
*******************************************************************************/
void __cdecl _heap_term (void)
{
PHEADER pHeader = __sbh_pHeaderList;
int cntHeader;
// scan through all the headers
for (cntHeader = 0; cntHeader < __sbh_cntHeaderList; cntHeader++)
{
// decommit and release the address space for the region
VirtualFree(pHeader->pHeapData, BYTES_PER_REGION, MEM_DECOMMIT);
VirtualFree(pHeader->pHeapData, 0, MEM_RELEASE);
// free the region data structure
HeapFree(_crtheap, 0, pHeader->pRegion);
pHeader++;
}
// free the header list
HeapFree(_crtheap, 0, __sbh_pHeaderList);
// destroy the large-block heap
HeapDestroy(_crtheap);
}
#else /* WINHEAP */
#ifdef _WIN32
#include <cruntime.h>
#include <oscalls.h>
#include <dos.h>
#include <heap.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
/*
* Heap descriptor
*/
struct _heap_desc_ _heap_desc = {
&_heap_desc.sentinel, /* pfirstdesc */
&_heap_desc.sentinel, /* proverdesc */
NULL, /* emptylist */
NULL, /* sentinel.pnextdesc */
NULL /* sentinel.pblock */
};
/*
* Array of region structures
* [Note: We count on the fact that this is always initialized to zero
* by the compiler.]
*/
struct _heap_region_ _heap_regions[_HEAP_REGIONMAX];
void ** _heap_descpages; /* linked list of pages used for descriptors */
/*
* Control parameter locations
*/
unsigned int _heap_resetsize = 0xffffffff;
/* NOTE: Currenlty, _heap_growsize is a #define to _amblksiz */
unsigned int _heap_growsize = _HEAP_GROWSIZE; /* region inc size */
unsigned int _heap_regionsize = _HEAP_REGIONSIZE_L; /* region size */
unsigned int _heap_maxregsize = _HEAP_MAXREGSIZE_L; /* max region size */
/***
*_heap_init() - Initialize the heap
*
*Purpose:
* Setup the initial C library heap. All necessary memory and
* data bases are init'd appropriately so future requests work
* correctly.
*
* NOTES:
* (1) This routine should only be called once!
* (2) This routine must be called before any other heap requests.
*
*
*Entry:
* <void>
*Exit:
* <void>
*
*Exceptions:
* If heap cannot be initialized, the program will be terminated
* with a fatal runtime error.
*
*******************************************************************************/
void __cdecl _heap_init (
void
)
{
/*
* Test for Win32S or Phar Lap TNT environment
* which cannot allocate uncommitted memory
* without actually allocating physical memory
*
* High bit of _osver is set for both of those environments
* -AND- the Windows version will be less than 4.0.
*/
if ( ( _osver & 0x8000 ) && ( _winmajor < 4 ) )
{
_heap_regionsize = _HEAP_REGIONSIZE_S;
_heap_maxregsize = _HEAP_MAXREGSIZE_S;
}
}
/***
*_heap_term() - Clean-up the heap
*
*Purpose:
* This routine will decommit and release ALL of the CRT heap.
* All memory malloc-ed by the CRT will then be invalid.
*
* NOTES:
* (1) This routine should only be called once!
* (2) This routine must be called AFTER any other heap requests.
*
*Entry:
* <void>
*Exit:
* <void>
*
*Exceptions:
*
*******************************************************************************/
void __cdecl _heap_term (
void
)
{
int index;
void **pageptr;
/*
* Loop through the region descriptor table, decommitting
* and releasing (freeing up) each region that is in use.
*/
for ( index=0 ; index < _HEAP_REGIONMAX ; index++ ) {
void * regbase ;
if ( (regbase = _heap_regions[index]._regbase)
&& VirtualFree(regbase, _heap_regions[index]._currsize, MEM_DECOMMIT)
&& VirtualFree(regbase, 0, MEM_RELEASE) )
regbase = _heap_regions[index]._regbase = NULL ;
}
/*
* Now we need to decommit and release the pages used for descriptors
* _heap_descpages points to the head of a singly-linked list of the pages.
*/
pageptr = _heap_descpages;
while ( pageptr ) {
void **nextpage;
nextpage = *pageptr;
if(!VirtualFree(pageptr, 0, MEM_RELEASE))
break; /* if the linked list is corrupted, give up */
pageptr = nextpage;
}
}
/***
* _heap_grow_emptylist() - Grow the empty heap descriptor list
*
*Purpose:
* (1) Get memory from OS
* (2) Form it into a linked list of empty heap descriptors
* (3) Attach it to the master empty list
*
* NOTE: This routine assumes that the emptylist is NULL
* when called (i.e., there are no available empty heap descriptors).
*
*Entry:
* (void)
*
*Exit:
* 1, if the empty heap descriptor list was grown
* 0, if the empty heap descriptor list could not be grown.
*
*Exceptions:
*
*******************************************************************************/
static int __cdecl _heap_grow_emptylist (
void
)
{
REG1 _PBLKDESC first;
REG2 _PBLKDESC next;
_PBLKDESC last;
/*
* Get memory for the new empty heap descriptors
*
* Note that last is used to hold the returned pointer because
* first (and next) are register class.
*/
if ( !(last = VirtualAlloc(NULL,
_HEAP_EMPTYLIST_SIZE,
MEM_COMMIT,
PAGE_READWRITE)) )
return 0;
/*
* Add this descriptor block to the front of the list
*
* Advance "last" to skip over the
*/
*(void **)last = _heap_descpages;
_heap_descpages = (void **)(last++);
/*
* Init the empty heap descriptor list.
*/
_heap_desc.emptylist = first = last;
/*
* Carve the memory into an empty list
*/
last = (_PBLKDESC) ((char *) first + _HEAP_EMPTYLIST_SIZE - 2 * sizeof(_BLKDESC));
next = (_PBLKDESC) ((char *) first + sizeof(_BLKDESC));
while ( first < last ) {
/* Init this descriptor */
first->pnextdesc = next;
/* onto the next block */
first = next++;
}
/*
* Take care of the last descriptor (end of the empty list)
*/
last->pnextdesc = NULL;
return 1;
}
/***
*__getempty() - get an empty heap descriptor
*
*Purpose:
* Get a descriptor from the list of empty heap descriptors. If the list
* is empty, call _heap_grow_emptylist.
*
*Entry:
* no arguments
*
*Exit:
* If successful, a pointer to the descriptor is returned.
* Otherwise, NULL is returned.
*
*Exceptions:
*
*******************************************************************************/
_PBLKDESC __cdecl __getempty(
void
)
{
_PBLKDESC pdesc;
if ( (_heap_desc.emptylist == NULL) && (_heap_grow_emptylist()
== 0) )
return NULL;
pdesc = _heap_desc.emptylist;
_heap_desc.emptylist = pdesc->pnextdesc;
return pdesc;
}
#else /* _WIN32 */
#if defined (_M_MPPC) || defined (_M_M68K)
#include <cruntime.h>
#include <dos.h>
#include <heap.h>
#include <malloc.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <dbgint.h>
#include <macos\types.h>
#include <macos\errors.h>
#include <macos\memory.h> // Mac OS interface header
#include <macos\lowmem.h>
#include <macos\segload.h>
#define _HEAP_EMPTYLIST_SIZE (1 * _PAGESIZE_)
#define DSErrCode (*(short*)(0x0af0))
/*
* Heap descriptor
*/
struct _heap_desc_ _heap_desc = {
&_heap_desc.sentinel, /* pfirstdesc */
&_heap_desc.sentinel, /* proverdesc */
NULL, /* emptylist */
NULL, /* sentinel.pnextdesc */
NULL /* sentinel.pblock */
};
/*
* Array of region structures
* [Note: We count on the fact that this is always initialized to zero
* by the compiler.]
*/
Handle hHeapRegions = NULL;
int _heap_region_table_cur = 0;
/*
* Control parameter locations
*/
unsigned int _heap_resetsize = 0xffffffff;
/* NOTE: Currenlty, _heap_growsize is a #define to _amblksiz */
unsigned int _heap_growsize = _HEAP_GROWSIZE; /* region inc size */
unsigned int _heap_regionsize = _HEAP_REGIONSIZE; /* region size */
/***
*_heap_init() - Initialize the heap
*
*Purpose:
* Setup the initial C library heap. All necessary memory and
* data bases are init'd appropriately so future requests work
* correctly.
*
* NOTES:
* (1) This routine should only be called once!
* (2) This routine must be called before any other heap requests.
*
*
*Entry:
* <void>
*Exit:
* <void>
*
*Exceptions:
* If heap cannot be initialized, the program will be terminated
* with a fatal runtime error.
*
*******************************************************************************/
void __cdecl _heap_init (
void
)
{
#define _INITREGIONSZ 0x1000
/*LATER -- do we need to do anything to init heap? Yes, in case user not malloc first*/
int oldregionsz = _heap_regionsize; /* save current region size */
struct _heap_region_ *pHeapRegions;
void *p;
void *p2;
if (hHeapRegions == NULL)
{
hHeapRegions = NewHandle(sizeof(struct _heap_region_)*_HEAP_REGIONMAX);
if (hHeapRegions == NULL)
{
DSErrCode = appMemFullErr;
ExitToShell();
}
HLock(hHeapRegions);
pHeapRegions = (struct _heap_region_ *)(*hHeapRegions);
memset(pHeapRegions, 0, sizeof(struct _heap_region_)*_HEAP_REGIONMAX);
_heap_region_table_cur = _HEAP_REGIONMAX;
}
_heap_regionsize = _INITREGIONSZ; /* set region size to 64 Kb */
/* make sure we have enough memory to do initialization */
if ((p = NewPtr(_HEAP_EMPTYLIST_SIZE)) == NULL)
{
DSErrCode = appMemFullErr;
ExitToShell();
}
if ((p2 = NewPtr(_heap_regionsize)) == NULL)
{
DSErrCode = appMemFullErr;
ExitToShell();
}
if (p)
{
DisposePtr(p);
}
if (p2)
{
DisposePtr(p2);
}
p = _malloc_base(4);
if (p == NULL)
{
DSErrCode = appMemFullErr;
ExitToShell();
}
_free_base( p ); /* malloc, then free a block */
_heap_regionsize = oldregionsz; /* restore region size */
}
/***
* _heap_grow_emptylist() - Grow the empty heap descriptor list
*
*Purpose:
* (1) Get memory from OS
* (2) Form it into a linked list of empty heap descriptors
* (3) Attach it to the master empty list
*
* NOTE: This routine assumes that the emptylist is NULL
* when called (i.e., there are no available empty heap descriptors).
*
*Entry:
* (void)
*
*Exit:
* (void)
*
*Exceptions:
*
*******************************************************************************/
static int __cdecl _heap_grow_emptylist (
void
)
{
REG1 _PBLKDESC first;
REG2 _PBLKDESC next;
_PBLKDESC last;
/*
* Get memory for the new empty heap descriptors
*
* Note that last is used to hold the returned pointer because
* first (and next) are register class.
*/
if ((last = (_PBLKDESC)NewPtr(_HEAP_EMPTYLIST_SIZE)) == NULL)
{
return 0;
}
/*
* Init the empty heap descriptor list.
*/
_heap_desc.emptylist = first = last;
/*
* Carve the memory into an empty list
*/
last = (_PBLKDESC) ((char *) first + _HEAP_EMPTYLIST_SIZE - sizeof(_BLKDESC));
next = (_PBLKDESC) ((char *) first + sizeof(_BLKDESC));
while ( first < last ) {
/* Init this descriptor */
first->pnextdesc = next;
/* onto the next block */
first = next++;
}
/*
* Take care of the last descriptor (end of the empty list)
*/
last->pnextdesc = NULL;
return 1;
}
/***
*__getempty() - get an empty heap descriptor
*
*Purpose:
* Get a descriptor from the list of empty heap descriptors. If the list
* is empty, call _heap_grow_emptylist.
*
*Entry:
* no arguments
*
*Exit:
* If successful, a pointer to the descriptor is returned.
* Otherwise, NULL is returned.
*
*Exceptions:
*
*******************************************************************************/
_PBLKDESC __cdecl __getempty(
void
)
{
_PBLKDESC pdesc;
if ( (_heap_desc.emptylist == NULL) && (_heap_grow_emptylist()
== 0) )
return NULL;
pdesc = _heap_desc.emptylist;
_heap_desc.emptylist = pdesc->pnextdesc;
return pdesc;
}
#endif /* defined (_M_MPPC) || defined (_M_M68K) */
#endif /* _WIN32 */
#endif /* WINHEAP */