diff options
Diffstat (limited to 'private/crt32/heap/heapgrow.c')
-rw-r--r-- | private/crt32/heap/heapgrow.c | 490 |
1 files changed, 490 insertions, 0 deletions
diff --git a/private/crt32/heap/heapgrow.c b/private/crt32/heap/heapgrow.c new file mode 100644 index 000000000..a9bdb7b59 --- /dev/null +++ b/private/crt32/heap/heapgrow.c @@ -0,0 +1,490 @@ +/*** +*heapgrow.c - Grow the heap +* +* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Get memory from OS and add to the heap. +* +*Revision History: +* 06-06-89 JCR Module created. +* 07-19-89 JCR Added region support +* 11-07-89 JCR Region table is no longer "packed" +* 11-08-89 JCR Use new _ROUND/_ROUND2 macros +* 11-10-89 JCR Don't abort on ERROR_NOT_ENOUGH_MEMORY +* 11-13-89 GJF Fixed copyright +* 12-18-89 GJF Removed DEBUG286 stuff, a little tuning, cleaned up +* the formatting a bit, changed header file name to +* heap.h, also added _cdecl to functions (that didn't +* already have explicit calling type) +* 03-11-90 GJF Replaced _cdecl with _CALLTYPE1, added #include +* <cruntime.h> and removed #include <register.h>. +* 03-29-90 GJF Made _heap_new_region() _CALLTYPE4. +* 07-24-90 SBM Compiles cleanly with -W3 (tentatively removed +* unreferenced labels), removed '32' from API names +* 09-28-90 GJF New-style function declarators. +* 12-04-90 SRW Changed to include <oscalls.h> instead of <doscalls.h> +* 12-06-90 SRW Added _CRUISER_ and _WIN32 conditionals. +* 02-01-91 SRW Changed for new VirtualAlloc interface (_WIN32_) +* 04-09-91 PNT Added _MAC_ conditional +* 04-26-91 SRW Removed level 3 warnings +* +*******************************************************************************/ + +#include <cruntime.h> +#include <oscalls.h> +#include <heap.h> +#include <malloc.h> +#include <stdlib.h> + +static int _CALLTYPE4 _heap_new_region(unsigned, size_t); + + +/*** +*_heap_grow() - Grow the heap +* +*Purpose: +* Get memory from the OS and add it to the heap. +* +*Entry: +* size_t _size = user's block request +* +*Exit: +* 0 = success, new mem is in the heap +* -1 = failure +* +*Exceptions: +* +*******************************************************************************/ + +int _CALLTYPE1 _heap_grow ( + REG1 size_t size + ) +{ + REG2 int index; + int free_entry = -1; + + /* + * Bump size to include header and round to nearest page boundary. + */ + + size += _HDRSIZE; + size = _ROUND2(size,_PAGESIZE_); + + /* + * Loop through the region table looking for an existing region + * we can grow. Remember the index of the first null region entry. + * + * size = size of grow request + */ + + for (index = 0; index < _HEAP_REGIONMAX; index++) { + + if ( (_heap_regions[index]._totalsize - + _heap_regions[index]._currsize) >= size ) + + /* + * Grow this region to satisfy the request. + */ + + return( _heap_grow_region(index, size) ); + + + if ( (free_entry == -1) && + (_heap_regions[index]._regbase == NULL) ) + + /* + * Remember 1st free table entry for later + */ + + free_entry = index; + + } + + /* + * Could not find any existing regions to grow. Try to + * get a new region. + * + * size = size of grow request + * free_entry = index of first free entry in table + */ + + if ( free_entry >= 0 ) + + /* + * Get a new region to satisfy the request. + */ + + return( _heap_new_region(free_entry, size) ); + + else + /* + * No free table entries: return an error. + */ + + return(-1); + +} + + +/*** +*_heap_new_region() - Get a new heap region +* +*Purpose: +* Get a new heap region and put it in the region table. +* Also, grow it large enough to support the caller's +* request. +* +* NOTES: +* (1) Caller has verified that there is room in the _heap_region +* table for another region. +* (2) The caller must have rounded the size to a page boundary. +* +*Entry: +* int index = index in table where new region data should go +* size_t size = size of request (this has been rounded to a +* page-sized boundary) +* +*Exit: +* 0 = success +* -1 = failure +* +*Exceptions: +* +*******************************************************************************/ + +static int _CALLTYPE4 _heap_new_region ( + REG1 unsigned index, + size_t size + ) +{ + void * region; + REG2 unsigned int regsize; + +#ifdef DEBUG + + int i; + + /* + * Make sure the size has been rounded to a page boundary + */ + + if (size & (_PAGESIZE_-1)) + _heap_abort(); + + /* + * Make sure there's a free slot in the table + */ + + for (i=0; i < _HEAP_REGIONMAX; i++) { + if (_heap_regions[i]._regbase == NULL) + break; + } + + if (i >= _HEAP_REGIONMAX) + _heap_abort(); + +#endif + + /* + * Round the heap region size to a page boundary (in case + * the user played with it). + */ + + regsize = _ROUND2(_heap_regionsize, _PAGESIZE_); + + /* + * See if region is big enough for request + */ + + if (regsize < size) + regsize = size; + + /* + * Go get the new region + */ + +#ifdef _CRUISER_ + + if ( DOSALLOCMEM(®ion, regsize, _NEWREGION, 0) != 0) + goto error; + +#else /* ndef _CRUISER_ */ + +#ifdef _WIN32_ + + if (!(region = VirtualAlloc(NULL, regsize, MEM_RESERVE, + PAGE_READWRITE))) + goto error; + +#else /* ndef _WIN32_ */ + +#ifdef _MAC_ + + TBD(); + +#else /* ndef _MAC_ */ + +#error ERROR - ONLY CRUISER, WIN32, OR MAC TARGET SUPPORTED! + +#endif /* _MAC_ */ + +#endif /* _WIN32_ */ + +#endif /* _CRUISER_ */ + /* + * Put the new region in the table. + */ + + _heap_regions[index]._regbase = region; + _heap_regions[index]._totalsize = regsize; + _heap_regions[index]._currsize = 0; + + + /* + * Grow the region to satisfy the size request. + */ + + if (_heap_grow_region(index, size) != 0) { + + /* + * Ouch. Allocated a region but couldn't commit + * any pages in it. Free region and return error. + */ + + _heap_free_region(index); + goto error; + } + + + /* + * Good return + */ + + /* done: unreferenced label to be removed */ + return(0); + + /* + * Error return + */ + + error: + return(-1); + +} + + +/*** +*_heap_grow_region() - Grow a heap region +* +*Purpose: +* Grow a region and add the new memory to the heap. +* +* NOTES: +* (1) The caller must have rounded the size to a page boundary. +* +*Entry: +* unsigned index = index of region in the _heap_regions[] table +* size_t size = size of request (this has been rounded to a +* page-sized boundary) +* +*Exit: +* 0 = success +* -1 = failure +* +*Exceptions: +* +*******************************************************************************/ + +int _CALLTYPE1 _heap_grow_region ( + REG1 unsigned index, + size_t size + ) +{ + size_t left; + REG2 size_t growsize; + void * base; + unsigned dosretval; + + + /* + * Init some variables + * left = space left in region + * base = base of next section of region to validate + */ + + left = _heap_regions[index]._totalsize - + _heap_regions[index]._currsize; + + base = (char *) _heap_regions[index]._regbase + + _heap_regions[index]._currsize; + + /* + * Make sure we can satisfy request + */ + + if (left < size) + goto error; + + /* + * Round size up to next _heap_growsize boundary. + * (Must round _heap_growsize itself to page boundary, in + * case user set it himself). + */ + + growsize = _ROUND2(_heap_growsize, _PAGESIZE_); + growsize = _ROUND(size, growsize); + + if (left < growsize) + growsize = left; + + /* + * Validate the new portion of the region + */ + +#ifdef _CRUISER_ + + dosretval = DOSSETMEM(base, growsize, _COMMIT); + +#else /* ndef _CRUISER_ */ + +#ifdef _WIN32_ + + if (!VirtualAlloc(base, growsize, MEM_COMMIT, PAGE_READWRITE)) + dosretval = GetLastError(); + else + dosretval = 0; + +#else /* ndef _WIN32_ */ + +#ifdef _MAC_ + + TBD(); + +#else /* ndef _MAC_ */ + +#error ERROR - ONLY CRUISER, WIN32, OR MAC TARGET SUPPORTED! + +#endif /* _MAC_ */ + +#endif /* _WIN32_ */ + +#endif /* _CRUISER_ */ + + if (dosretval) + /* + * Error committing pages. If out of memory, return + * error, else abort. + */ + + if (dosretval == ERROR_NOT_ENOUGH_MEMORY) + goto error; + else + _heap_abort(); + + + /* + * Update the region data base + */ + + _heap_regions[index]._currsize += growsize; + + +#ifdef DEBUG + /* + * The current size should never be greater than the total size + */ + + if (_heap_regions[index]._currsize > _heap_regions[index]._totalsize) + _heap_abort(); +#endif + + + /* + * Add the memory to the heap + */ + + if (_heap_addblock(base, growsize) != 0) + _heap_abort(); + + + /* + * Good return + */ + + /* done: unreferenced label to be removed */ + return(0); + + /* + * Error return + */ + + error: + return(-1); + +} + + +/*** +*_heap_free_region() - Free up a region +* +*Purpose: +* Return a heap region to the OS and zero out +* corresponding region data entry. +* +*Entry: +* int index = index of region to be freed +* +*Exit: +* void +* +*Exceptions: +* +*******************************************************************************/ + +void _CALLTYPE1 _heap_free_region ( + REG1 int index + ) +{ + + /* + * Give the memory back to the OS + */ + +#ifdef _CRUISER_ + + if (DOSFREEMEM(_heap_regions[index]._regbase)) + _heap_abort(); + +#else /* ndef _CRUISER_ */ + +#ifdef _WIN32_ + + if (!VirtualFree(_heap_regions[index]._regbase, 0, MEM_RELEASE)) + _heap_abort(); + +#else /* ndef _WIN32_ */ + +#ifdef _MAC_ + + TBD(); + +#else /* ndef _MAC_ */ + +#error ERROR - ONLY CRUISER, WIN32, OR MAC TARGET SUPPORTED! + +#endif /* _MAC_ */ + +#endif /* _WIN32_ */ + +#endif /* _CRUISER_ */ + + /* + * Zero out the heap region entry + */ + + _heap_regions[index]._regbase = NULL; + _heap_regions[index]._currsize = + _heap_regions[index]._totalsize = 0; + +} |