diff options
Diffstat (limited to 'private/crt32/heap')
-rw-r--r-- | private/crt32/heap/calloc.c | 88 | ||||
-rw-r--r-- | private/crt32/heap/delete.cxx | 28 | ||||
-rw-r--r-- | private/crt32/heap/findaddr.c | 108 | ||||
-rw-r--r-- | private/crt32/heap/free.c | 171 | ||||
-rw-r--r-- | private/crt32/heap/handler.cxx | 53 | ||||
-rw-r--r-- | private/crt32/heap/heapadd.c | 413 | ||||
-rw-r--r-- | private/crt32/heap/heapchk.c | 330 | ||||
-rw-r--r-- | private/crt32/heap/heapdump.c | 334 | ||||
-rw-r--r-- | private/crt32/heap/heapgrow.c | 490 | ||||
-rw-r--r-- | private/crt32/heap/heapinit.c | 266 | ||||
-rw-r--r-- | private/crt32/heap/heapmin.c | 520 | ||||
-rw-r--r-- | private/crt32/heap/heapprm.c | 87 | ||||
-rw-r--r-- | private/crt32/heap/heapsrch.c | 150 | ||||
-rw-r--r-- | private/crt32/heap/heapwalk.c | 170 | ||||
-rw-r--r-- | private/crt32/heap/hpabort.c | 47 | ||||
-rw-r--r-- | private/crt32/heap/makefile | 7 | ||||
-rw-r--r-- | private/crt32/heap/malloc.c | 474 | ||||
-rw-r--r-- | private/crt32/heap/msize.c | 112 | ||||
-rw-r--r-- | private/crt32/heap/new.cxx | 28 | ||||
-rw-r--r-- | private/crt32/heap/realloc.c | 477 | ||||
-rw-r--r-- | private/crt32/heap/sources | 71 |
21 files changed, 4424 insertions, 0 deletions
diff --git a/private/crt32/heap/calloc.c b/private/crt32/heap/calloc.c new file mode 100644 index 000000000..1dba04cd2 --- /dev/null +++ b/private/crt32/heap/calloc.c @@ -0,0 +1,88 @@ +/*** +*calloc.c - allocate storage for an array from the heap +* +* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Defines the calloc() function. +* +*Revision History: +* 07-25-89 GJF Module created +* 11-13-89 GJF Added MTHREAD support. Also fixed copyright and got +* rid of DEBUG286 stuff. +* 12-04-89 GJF Renamed header file (now heap.h). Added register +* declarations +* 12-18-89 GJF Added explicit _cdecl to function definition +* 03-09-90 GJF Replaced _cdecl with _CALLTYPE1, added #include +* <cruntime.h> and removed #include <register.h>. +* 09-27-90 GJF New-style function declarator. +* 05-28-91 GJF Tuned a bit. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <heap.h> +#include <malloc.h> +#include <os2dll.h> +#include <stddef.h> + + +/*** +*void *calloc(size_t num, size_t size) - allocate storage for an array from +* the heap +* +*Purpose: +* Allocate a block of memory from heap big enough for an array of num +* elements of size bytes each, initialize all bytes in the block to 0 +* and return a pointer to it. +* +*Entry: +* size_t num - number of elements in the array +* size_t size - size of each element +* +*Exit: +* Success: void pointer to allocated block block +* Failure: NULL +* +*Uses: +* +*Exceptions: +* +*******************************************************************************/ + +void * _CALLTYPE1 calloc ( + size_t num, + size_t size + ) +{ + void *retptr; + REG1 size_t *startptr; + REG2 size_t *lastptr; + + /* lock the heap + */ + _mlock(_HEAP_LOCK); + + /* try to malloc the requested space + */ + retptr = _malloc_lk(num *= size); + + /* if malloc() succeeded, initialize the allocated space to zeros. + * note the assumptions that the size of the allocation block is an + * integral number of sizeof(size_t) bytes and that (size_t)0 is + * sizeof(size_t) bytes of 0. + */ + if ( retptr != NULL ) { + startptr = (size_t *)retptr; + lastptr = startptr + ((num + sizeof(size_t) - 1) / + sizeof(size_t)); + while ( startptr < lastptr ) + *(startptr++) = 0; + } + + /* release the heap lock + */ + _munlock(_HEAP_LOCK); + + return(retptr); +} diff --git a/private/crt32/heap/delete.cxx b/private/crt32/heap/delete.cxx new file mode 100644 index 000000000..bc2d73e7a --- /dev/null +++ b/private/crt32/heap/delete.cxx @@ -0,0 +1,28 @@ +/*** +*delete.cxx - defines C++ delete routine +* +* Copyright (c) 1990-1992, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Defines C++ delete routine. +* +*Revision History: +* 05-07-90 WAJ Initial version. +* 08-30-90 WAJ new now takes unsigned ints. +* 08-08-91 JCR call _halloc/_hfree, not halloc/hfree +* 08-13-91 KRS Change new.hxx to new.h. Fix copyright. +* 08-13-91 JCR ANSI-compatible _set_new_handler names +* 10-30-91 JCR Split new, delete, and handler into seperate sources +* 11-13-91 JCR 32-bit version +* +*******************************************************************************/ + +#include <cruntime.h> +#include <malloc.h> +#include <new.h> + + +void operator delete( void * p ) +{ + free( p ); +} diff --git a/private/crt32/heap/findaddr.c b/private/crt32/heap/findaddr.c new file mode 100644 index 000000000..d7e9c699c --- /dev/null +++ b/private/crt32/heap/findaddr.c @@ -0,0 +1,108 @@ +/*** +*findaddr.c - Find a heap entry +* +* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Defines the _heap_findaddr routine +* +*Revision History: +* 07-06-89 JCR Module created. +* 07-18-89 JCR Return -1 if nothing in heap +* 11-13-89 GJF Fixed copyright +* 12-04-89 GJF Renamed header file (now heap.h). Also, some tuning. +* 12-18-89 GJF Added explicit _cdecl to function definition +* 03-09-90 GJF Replaced _cdecl with _CALLTYPE1, added #include +* <cruntime.h> and removed #include <register.h>. +* 09-27-90 GJF New-style function declarator. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <heap.h> +#include <stddef.h> + +#define TRUE 1 + +/*** +*int _heap_findaddr() - Find a heap entry +* +*Purpose: +* Given an address, find the corresponding heap entry. +* +*Entry: +* void * address = address to look for +* PBLKDESC * ppdesc = pointer to pointer to heap descriptor to be +* filled in by this routine. +* +*Exit: +* +* _HEAPFIND_EXACT = 0 = exact fit, pdesc holds heap descriptor address +* _HEAPFIND_WITHIN = 1 = not exact fit, pdesc holds previous heap +* descriptor address +* +* _HEAPFIND_BEFORE = -1 = address is before the heap (pdesc NOT filled in) +* _HEAPFIND_AFTER = -2 = address is after the heap (pdesc NOT filled in) +* _HEAPFIND_EMPTY = -3 = no memory in heap (pdesc NOT filled in) +* +* [If return is negative, supplied pdesc is NOT filled in.] +* +*Uses: +* +*Exceptions: +* +*******************************************************************************/ + +int _CALLTYPE1 _heap_findaddr ( + void * address, + _PBLKDESC * ppdesc + ) +{ + REG1 _PBLKDESC pcurr; + + /* + * See if heap there's anything in the heap + */ + + if (_heap_desc.pfirstdesc == &_heap_desc.sentinel) + return(_HEAPFIND_EMPTY); + + /* + * See if entry is in the heap or not + */ + + if (_ADDRESS(_heap_desc.pfirstdesc) > address) + return(_HEAPFIND_BEFORE); + + if (_ADDRESS(&_heap_desc.sentinel) <= address) + return(_HEAPFIND_AFTER); + + /* + * Find the entry + */ + +#ifdef DEBUG + for (pcurr = _heap_desc.pfirstdesc; pcurr != &_heap_desc.sentinel; + pcurr = pcurr->pnextdesc) { +#else + for (pcurr = _heap_desc.pfirstdesc; TRUE; pcurr = pcurr->pnextdesc) { +#endif + + if ( _ADDRESS(pcurr->pnextdesc) > address ) { + + /* Address is contained in this entry */ + *ppdesc = pcurr; + + /* Check for an exact fit */ + if ( _ADDRESS(pcurr) == address) + return(_HEAPFIND_EXACT); + else + return(_HEAPFIND_WITHIN); + } + } + +#ifdef DEBUG + /* Should never reach here! */ + _heap_abort(); +#endif +} diff --git a/private/crt32/heap/free.c b/private/crt32/heap/free.c new file mode 100644 index 000000000..44e44475a --- /dev/null +++ b/private/crt32/heap/free.c @@ -0,0 +1,171 @@ +/*** +*free.c - free an entry in the heap +* +* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Defines the following functions: +* free() - free a memory block in the heap +* _free_lk() - non-locking from of free() (multi-thread only) +* +*Revision History: +* 06-30-89 JCR Module created +* 07-07-89 GJF Fixed test for resetting proverdesc +* 11-10-89 GJF Added MTHREAD support. Also, a little cleanup. +* 12-18-89 GJF Change header file name to heap.h, added register +* declarations and added explicit _cdecl to function +* definitions +* 03-09-90 GJF Replaced _cdecl with _CALLTYPE1, added #include +* <cruntime.h> and removed #include <register.h>. +* 09-27-90 GJF New-style function declarators. Also, rewrote expr. +* so that a cast was not used as an lvalue. +* 03-05-91 GJF Changed strategy for rover - old version available +* by #define-ing _OLDROVER_. +* 04-08-91 GJF Temporary hack for Win32/DOS folks - special version +* of free that just calls HeapFree. Change conditioned +* on _WIN32DOS_. +* +*******************************************************************************/ + +#ifndef _WIN32DOS_ + +#include <cruntime.h> +#include <heap.h> +#include <malloc.h> +#include <os2dll.h> +#include <stdlib.h> + +/*** +*void free(pblock) - free a block in the heap +* +*Purpose: +* Free a memory block in the heap. +* +* Special Notes For Multi-thread: The non-multi-thread version is renamed +* to _free_lk(). The multi-thread free() simply locks the heap, calls +* _free_lk(), then unlocks the heap and returns. +* +*Entry: +* void *pblock - pointer to a memory block in the heap +* +*Return: +* <void> +* +*******************************************************************************/ + +#ifdef MTHREAD + +void _CALLTYPE1 free ( + void *pblck + ) +{ + /* lock the heap + */ + _mlock(_HEAP_LOCK); + + /* free the block + */ + _free_lk(pblck); + + /* unlock the heap + */ + _munlock(_HEAP_LOCK); +} + + +/*** +*void _free_lk(pblock) - non-locking form of free +* +*Purpose: +* Same as free() except that no locking is performed +* +*Entry: +* See free +* +*Return: +* +*******************************************************************************/ + +void _CALLTYPE1 _free_lk ( + +#else /* ndef MTHREAD */ + +void _CALLTYPE1 free ( + +#endif /* MTHREAD */ + + REG1 void *pblck + ) +{ + REG2 _PBLKDESC pdesc; + + /* + * If the pointer is NULL, just return [ANSI]. + */ + + if (pblck == NULL) + return; + + /* + * Point to block header and get the pointer back to the heap desc. + */ + + pblck = (char *)pblck - _HDRSIZE; + pdesc = *(_PBLKDESC*)pblck; + + /* + * Validate the back pointer. + */ + + if (_ADDRESS(pdesc) != pblck) + _heap_abort(); + + /* + * Pointer is ok. Mark block free. + */ + + _SET_FREE(pdesc); + + /* + * Back up rover pointer, if appropriate. + */ +#ifdef _OLDROVER_ + + if (_heap_desc.proverdesc->pblock > pdesc->pblock) + _heap_desc.proverdesc = pdesc; + +#else /* ndef _OLDROVER_ */ + + if ( (_heap_resetsize != 0xffffffff) && + (_heap_desc.proverdesc->pblock > pdesc->pblock) && + (_BLKSIZE(pdesc) >= _heap_resetsize) ) + _heap_desc.proverdesc = pdesc; + +#endif /* _OLDROVER_ */ + +} + + +#else /* _WIN32DOS_ */ + +/* + * TEMPORARY HACK! THE CODE BELOW IS INTENDED TO ALLOW LIMITED USE OF THE + * C RUNTIME ON WIN32/DOS. IT WILL BE DELETED AS SOON AS THEY IMPLEMENT + * VirtualAlloc()! + */ + +#include <cruntime.h> +#include <oscalls.h> +#include <malloc.h> + +extern HANDLE _HeapHandle; + +void _CALLTYPE1 free ( + void *pblck + ) +{ + HeapFree(_HeapHandle, pblck); + return; +} + +#endif /* _WIN32DOS_ */ diff --git a/private/crt32/heap/handler.cxx b/private/crt32/heap/handler.cxx new file mode 100644 index 000000000..91db57522 --- /dev/null +++ b/private/crt32/heap/handler.cxx @@ -0,0 +1,53 @@ +/*** +*handler.cxx - defines C++ setHandler routine +* +* Copyright (c) 1990-1992, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Defines C++ setHandler routine. +* +*Revision History: +* 05-07-90 WAJ Initial version. +* 08-30-90 WAJ new now takes unsigned ints. +* 08-08-91 JCR call _halloc/_hfree, not halloc/hfree +* 08-13-91 KRS Change new.hxx to new.h. Fix copyright. +* 08-13-91 JCR ANSI-compatible _set_new_handler names +* 10-30-91 JCR Split new, delete, and handler into seperate sources +* 11-13-91 JCR 32-bit version +* 06-15-92 KRS Break MTHREAD support for NT BETA +* +*******************************************************************************/ + +#include <cruntime.h> +#include <os2dll.h> +#include <new.h> + +/* Warning! MTHREAD is broken! */ +/* Warning! MTHREAD is broken! */ +/* Warning! MTHREAD is broken! */ + +/* #ifndef MTHREAD */ +/* pointer to C++ new handler */ +extern "C" _PNH _pnhHeap; +/* #endif */ + +_PNH _set_new_handler( _PNH pnh ) +{ +_PNH pnhOld; + +/* #ifdef MTHREAD + + _pptiddata tdata; + tdata = _getptd(); + pnhOld = ((*tdata)->_tpnhHeap); + ((*tdata)->_tpnhHeap) = pnh; + +#else */ /* ndef MTHREAD */ + + pnhOld = _pnhHeap; + _pnhHeap = pnh; + +/* #endif */ + + return(pnhOld); +} diff --git a/private/crt32/heap/heapadd.c b/private/crt32/heap/heapadd.c new file mode 100644 index 000000000..587e4cb1e --- /dev/null +++ b/private/crt32/heap/heapadd.c @@ -0,0 +1,413 @@ +/*** +*heapadd.c - Add a block of memory to the heap +* +* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Add a block of memory to the heap. +* +*Revision History: +* 07-07-89 JCR Module created. +* 07-20-89 JCR Re-use dummy descriptor on exact fit (dummy collection) +* 11-09-89 JCR Corrected plastdesc updating code +* 11-13-89 GJF Added MTHREAD support, also fixed copyright +* 11-15-89 JCR Minor improvement (got rid of a local variable) +* 11-16-89 JCR Bug fix - squirrly case in _HEAPFIND_EXACT +* 12-04-89 GJF A little tuning and cleanup. Also, changed header file +* name to heap.h. +* 12-18-89 GJF Removed DEBUG286 stuff. Also, added explicit _cdecl to +* function definitions. +* 12-19-89 GJF Removed references and uses of plastdesc (revising +* code as necessary) +* 03-09-90 GJF Replaced _cdecl with _CALLTYPE1, added #include +* <cruntime.h> and removed #include <register.h>. +* 03-29-90 GJF Made _before() _CALLTYPE4. +* 07-24-90 SBM Compiles cleanly with -W3 (tentatively removed +* unreferenced label) +* 09-27-90 GJF New-style function declarators. +* 03-05-91 GJF Changed strategy for rover - old version available +* by #define-ing _OLDROVER_. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <heap.h> +#include <malloc.h> +#include <os2dll.h> +#include <stdlib.h> + +static void _CALLTYPE4 _before(_PBLKDESC, size_t, _PBLKDESC); + +/*** +*int _heapadd(block, size) - Add a block of memory to the heap +* +*Purpose: +* Add a block of user memory the heap. +* +* NOTE: The reason for the level of indirection between _heapadd +* and _heap_addblock is (1) to validate the input, and (2) for +* mthread locking/unlocking purposes. +* +* NOTE: _heapadd() DOES NOT enter the block of memory into the region +* table! This is the cleanest way to avoid nasty bugs such as attempting +* to grow, shrink or free static memory (e.g., a block that started out +* being a static array). If the memory block does in fact belong in the +* region table, it is the caller's responsibility to do it (internal +* routines only, user programs should NEVER do this). +* +*Entry: +* void * block = block of memory +* size_t size = size of memory block +* +*Exit: +* 0 = success +* -1 = failure +* +*Exceptions: +* +*******************************************************************************/ + +int _CALLTYPE1 _heapadd ( + void * block, + size_t size + ) +{ + int retval; + + /* + * Validate user's input + */ + + if ( (size == 0) || + ((unsigned)block & (sizeof(int)-1)) || + (size & (sizeof(int)-1)) + ) + return(-1); + + /* + * Add the block to the heap. + */ + + _mlock(_HEAP_LOCK); + retval = _heap_addblock(block, size); + _munlock(_HEAP_LOCK); + + return(retval); + +} + + +/*** +*int _heap_addblock(block, size) - Add a block of memory to the heap +* +*Purpose: +* Add a block of memory to the heap. +* +* Notes: +* (1) Must handle case where new memory is already in heap +* (i.e., could be the address of a previous 'dummy' entry). +* +*Entry: +* void * block = address of memory block +* size_t size = size of memory block +* +*Exit: +* 0 = success +* -1 = failure +* +*Exceptions: +* +*******************************************************************************/ + +int _CALLTYPE1 _heap_addblock ( + void * block, + size_t size + ) +{ + _PBLKDESC pdesc; + REG1 _PBLKDESC pnewdesc; + size_t lastsize; + int find; + + + /* + * Find where the address fits into the heap. + */ + + find = _heap_findaddr(block, &pdesc); + + + /* + * Fill in the new heap descriptor. + * (1) If the new address is an exact fit, use the dummy + * descriptor that already exists for it. + * (2) If the address is NOT in the heap, allocate a new one. + */ + + if (find == _HEAPFIND_EXACT) { + + if (!(_IS_DUMMY(pdesc))) + goto error1; + + pnewdesc = pdesc; + } + + else { + _GETEMPTY(pnewdesc); + } + + pnewdesc->pblock = block; /* pointer to block */ + _SET_FREE(pnewdesc); /* set me free (why don't ya, babe) */ + *(_PBLKDESC*)block = pnewdesc; /* init back pointer */ + + + /* + * Put the block in the heap + * find = result of _heap_findaddr() call + * pnewdesc = points to desc to be inserted + * pdesc = filled in by _heap_findaddr() call as appropriate + */ + + switch (find) { + + + case(_HEAPFIND_EMPTY): + + /* + * No memory in heap yet + */ + + _heap_desc.sentinel.pblock = (char *) block + size; + _before(pnewdesc, size, &_heap_desc.sentinel); + + _heap_desc.pfirstdesc = _heap_desc.proverdesc = + pnewdesc; + + break; + + + case(_HEAPFIND_BEFORE): + + /* + * New block is before the heap + */ + + _before(pnewdesc, size, _heap_desc.pfirstdesc); + _heap_desc.pfirstdesc = pnewdesc; + break; + + + case(_HEAPFIND_AFTER): + + /* + * New block is after the heap + * + * Find the current last block in the heap + */ + + if ( _heap_findaddr((void *)((char *) + (_heap_desc.sentinel.pblock) - 1), &pdesc) != + _HEAPFIND_WITHIN ) + _heap_abort(); + + lastsize = _MEMSIZE(pdesc); + + /* + * Start insertion by placing new block immediately + * in front of the sentinel + */ + + _heap_desc.sentinel.pblock = (char *) block + size; + pnewdesc->pnextdesc = &_heap_desc.sentinel; + + /* + * Finish insertion by placing new block after the + * old last block (with a possible intervening dummy + * block being created) + */ + + _before(pdesc, lastsize, pnewdesc); + break; + + + case(_HEAPFIND_EXACT): + + /* + * Block is already in the heap (and we've checked + * that it was a "dummy" before this call). + * + * [NOTES: (1) pnewdesc and pdesc are the same, + * (2) pnewdesc is already linked to the previous + * heap entry, (3) pdesc->pnextdesc is still valid! + * (4) Also, if pdesc->pnextdesc is the sentinel, + * then simply update the sentinel size (calling + * before will cause an error if the previous last + * block was bigger than the current one!). + * (see code at top of this routine).] + */ + + if (pdesc->pnextdesc == &_heap_desc.sentinel) + + _heap_desc.sentinel.pblock = + (char *) _ADDRESS(pdesc) + size; + + else + _before(pnewdesc, size, pdesc->pnextdesc); + + break; + +#ifdef DEBUG + case(_HEAPFIND_WITHIN): +#else + default: +#endif + /* + * New block is within heap + */ + + if (!(_IS_DUMMY(pdesc))) + goto error0; + + _before(pnewdesc, size, pdesc->pnextdesc); + _before(pdesc, _MEMSIZE(pdesc), pnewdesc); + break; + +#ifdef DEBUG + /* + * Return value unknown -- abort! + */ + + default: + _heap_abort(); +#endif + + } + + /* + * Update rover, if appropriate + */ +#ifdef _OLDROVER_ + + if (block < _ADDRESS(_heap_desc.proverdesc)) + _heap_desc.proverdesc = pnewdesc; + +#else /* ndef _OLDROVER_ */ + + if ( (block < _ADDRESS(_heap_desc.proverdesc)) && + (_BLKSIZE(pnewdesc) >= _heap_resetsize) ) + _heap_desc.proverdesc = pnewdesc; + +#endif /* _OLDROVER_ */ + + /* + * Good return + */ + + /* good: unreferenced label to be removed */ + return(0); + + /* + * Error return + */ + + error0: + _PUTEMPTY(pnewdesc); + error1: + return(-1); + +} + + +/*** +*static void _before(pdesc1, size, pdesc2) - Insert a block before a +* supplied descriptor +* +*Purpose: +* This routine inserts a new descriptor before +* another descriptor. +* +* Notes: +* (1) A dummy descriptor will be inserted into the heap as +* necessary. +* (2) This routine only updates FORWARD links. Call this +* routine twice to update links in both directions. +* +*Entry: +* _PBLKDESC pdesc1 = new descriptor to insert in the heap +* size_t size = size of pdesc1 block +* _PBLKDESC pdesc2 = descriptor before which block should go +* +*Exit: +* (void) +* +*Exceptions: +* +*******************************************************************************/ + +static void _CALLTYPE4 _before ( + REG1 _PBLKDESC pdesc1, + size_t size, + REG2 _PBLKDESC pdesc2 + ) +{ + size_t diff; + _PBLKDESC pdummydesc; + void * dummyaddr; + + /* + * Check for dummy descriptors: + * (1) If first block is dummy, no adjustement needed. + * (2) If second block is dummy, simply adjust size. + */ + + if (_IS_DUMMY(pdesc1)) + goto link; + + if (_IS_DUMMY(pdesc2)) { + pdesc2->pblock = (char *)_ADDRESS(pdesc1) + size; + _SET_DUMMY(pdesc2); + goto link; + } + + + /* + * See how much space is between this block and the next one. + */ + + diff = ( (char *) _ADDRESS(pdesc2) - + (char *) (dummyaddr = (char *) _ADDRESS(pdesc1) + size) ); + + if (diff != 0) { + +#ifdef DEBUG + /* + * Internal bogosity check + */ + + if ((int)diff < 0) + _heap_abort(); +#endif + /* + * There is some space between the two blocks. Insert + * a fake "in use" block. Remember, there is no 'back + * pointer' in dummy blocks. + */ + + _GETEMPTY(pdummydesc); + + pdummydesc->pblock = (char *) dummyaddr; + _SET_DUMMY(pdummydesc); + + pdesc1->pnextdesc = pdummydesc; + pdesc1 = pdummydesc; + + } + + /* + * Put the new block in the heap. + */ + + link: + pdesc1->pnextdesc = pdesc2; + +} diff --git a/private/crt32/heap/heapchk.c b/private/crt32/heap/heapchk.c new file mode 100644 index 000000000..872b124d5 --- /dev/null +++ b/private/crt32/heap/heapchk.c @@ -0,0 +1,330 @@ +/*** +*heapchk.c - perform a consistency check on the heap +* +* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Defines the _heapchk() and _heapset() functions +* +*Revision History: +* 06-30-89 JCR Module created. +* 07-28-89 GJF Added check for free block preceding the rover +* 11-13-89 GJF Added MTHREAD support, also fixed copyright +* 12-13-89 GJF Added check for descriptor order, did some tuning, +* changed header file name to heap.h +* 12-15-89 GJF Purged DEBUG286 stuff. Also added explicit _cdecl to +* function definitions. +* 12-19-89 GJF Got rid of checks involving plastdesc (revised check +* of proverdesc and DEBUG errors accordingly) +* 03-09-90 GJF Replaced _cdecl with _CALLTYPE1, added #include +* <cruntime.h> and removed #include <register.h>. +* 03-29-90 GJF Made _heap_checkset() _CALLTYPE4. +* 09-27-90 GJF New-style function declarators. +* 03-05-91 GJF Changed strategy for rover - old version available +* by #define-ing _OLDROVER_. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <heap.h> +#include <malloc.h> +#include <os2dll.h> +#include <stddef.h> +#include <string.h> +#ifdef DEBUG +#include <stdio.h> +#endif + +static int _CALLTYPE4 _heap_checkset(unsigned int _fill); + +/* Debug error values */ +#define _EMPTYHEAP 0 +#define _BADROVER 1 +#define _BADRANGE 2 +#define _BADSENTINEL 3 +#define _BADEMPTY 4 +#define _EMPTYLOOP 5 +#define _BADFREE 6 +#define _BADORDER 7 + +#ifdef DEBUG + +static char *errmsgs[] = { + "_heap_desc.pfirstdesc == NULL", + "_heap_desc.proverdesc not found in desc list", + "address is outside the heap", + "sentinel descriptor corrupted", + "empty desc pblock != NULL (debug version)", + "header ptr found twice in emptylist", + "free block precedes rover", + "adjacent descriptors in reverse order from heap blocks" + }; + +#define _PRINTERR(msg) \ + printf("\n*** HEAP ERROR: %s ***\n", errmsgs[(msg)]); \ + fflush(stdout); + +#else /* !DEBUG */ + +#define _PRINTERR(msg) + +#endif /* DEBUG */ + + +/*** +*int _heapchk() - Validate the heap +*int _heapset(_fill) - Validate the heap and fill in free entries +* +*Purpose: +* Performs a consistency check on the heap. +* +*Entry: +* For heapchk() +* No arguments +* For heapset() +* int _fill - value to be used as filler in free entries +* +*Exit: +* Returns one of the following values: +* +* _HEAPOK - completed okay +* _HEAPEMPTY - heap not initialized +* _HEAPBADBEGIN - can't find initial header info +* _HEAPBADNODE - malformed node somewhere +* +* Debug version prints out a diagnostic message if an error is found +* (see errmsg[] above). +* +* NOTE: Add code to support memory regions. +* +*Uses: +* +*Exceptions: +* +*******************************************************************************/ + +int _CALLTYPE1 _heapchk(void) +{ + return(_heap_checkset((unsigned int)_HEAP_NOFILL)); +} + +/******************************************************************************/ + +int _CALLTYPE1 _heapset ( + unsigned int _fill + ) +{ + return(_heap_checkset(_fill)); +} + + +/*** +*static int _heap_checkset(_fill) - check the heap and fill in the +* free entries +* +*Purpose: +* Workhorse routine for both _heapchk() and _heapset(). +* +*Entry: +* int _fill - either _HEAP_NOFILL or a value to be used as filler in +* free entries +* +*Exit: +* See description of _heapchk()/_heapset() +* +*******************************************************************************/ + +static int _CALLTYPE4 _heap_checkset ( + unsigned int _fill + ) +{ + REG1 _PBLKDESC pdesc; + REG2 _PBLKDESC pnext; + int roverfound=0; + int retval = _HEAPOK; + + /* + * lock the heap + */ + + _mlock(_HEAP_LOCK); + + /* + * Validate the sentinel + */ + + if (_heap_desc.sentinel.pnextdesc != NULL) { + _PRINTERR(_BADSENTINEL); + retval = _HEAPBADNODE; + goto done; + } + + /* + * Test for an empty heap + */ + + if ( (_heap_desc.pfirstdesc == &_heap_desc.sentinel) && + (_heap_desc.proverdesc == &_heap_desc.sentinel) ) { + retval = _HEAPEMPTY; + goto done; + } + + /* + * Get and validate the first descriptor + */ + + if ((pdesc = _heap_desc.pfirstdesc) == NULL) { + _PRINTERR(_EMPTYHEAP); + retval = _HEAPBADBEGIN; + goto done; + } + + /* + * Walk the heap descriptor list + */ + + while (pdesc != &_heap_desc.sentinel) { + + /* + * Make sure address for this entry is in range. + */ + + if ( (_ADDRESS(pdesc) < _ADDRESS(_heap_desc.pfirstdesc)) || + (_ADDRESS(pdesc) > _heap_desc.sentinel.pblock) ) { + _PRINTERR(_BADRANGE); + retval = _HEAPBADNODE; + goto done; + } + + pnext = pdesc->pnextdesc; + + /* + * Make sure the blocks corresponding to pdesc and pnext are + * in proper order. + */ + + if ( _ADDRESS(pdesc) >= _ADDRESS(pnext) ) { + _PRINTERR(_BADORDER); + retval = _HEAPBADNODE; + goto done; + } + + /* + * Check the backpointer. + */ + + if (_IS_INUSE(pdesc) || _IS_FREE(pdesc)) { + + if (!_CHECK_PDESC(pdesc)) { + retval = _HEAPBADPTR; + goto done; + } + } + + /* + * Check for proverdesc + */ + + if (pdesc == _heap_desc.proverdesc) + roverfound++; + +#ifdef _OLDROVER_ + + /* + * If it is free, make sure it doesn't precede the rover + * block and fill it in if appropriate + */ + + if ( _IS_FREE(pdesc) ) { + + if ( roverfound == 0 ) { + _PRINTERR(_BADFREE); + retval = _HEAPBADNODE; + goto done; + } + + if ( _fill != _HEAP_NOFILL ) + memset( (void *)((unsigned)_ADDRESS(pdesc)+_HDRSIZE), + _fill, _BLKSIZE(pdesc) ); + } + +#else /* ndef _OLDROVER_ */ + + /* + * If it is free, fill it in if appropriate + */ + + if ( _IS_FREE(pdesc) && (_fill != _HEAP_NOFILL) ) + memset( (void *)((unsigned)_ADDRESS(pdesc)+_HDRSIZE), + _fill, _BLKSIZE(pdesc) ); + +#endif /* _OLDROVER_ */ + + /* + * Onto the next block + */ + + pdesc = pnext; + } + + /* + * Make sure we found 1 and only 1 rover + */ + + if (_heap_desc.proverdesc == &_heap_desc.sentinel) + roverfound++; + + if (roverfound != 1) { + _PRINTERR(_BADROVER); + retval = _HEAPBADBEGIN; + goto done; + } + + /* + * Walk the empty list. We can't really compare values against + * anything but we may loop forever or may cause a fault. + */ + + pdesc = _heap_desc.emptylist; + + while (pdesc != NULL) { + +#ifdef DEBUG + if (pdesc->pblock != NULL) { + _PRINTERR(_BADEMPTY) + retval = _HEAPBADPTR; + goto done; + } +#endif + + pnext = pdesc->pnextdesc; + + /* + * Header should only appear once + */ + + if (pnext == _heap_desc.emptylist) { + _PRINTERR(_EMPTYLOOP) + retval = _HEAPBADPTR; + goto done; + } + + pdesc = pnext; + + } + + + /* + * Common return + */ + +done: + /* + * release the heap lock + */ + + _munlock(_HEAP_LOCK); + + return(retval); + +} diff --git a/private/crt32/heap/heapdump.c b/private/crt32/heap/heapdump.c new file mode 100644 index 000000000..1255b44c8 --- /dev/null +++ b/private/crt32/heap/heapdump.c @@ -0,0 +1,334 @@ +/*** +*heapdump.c - Output the heap data bases +* +* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Display the heap data bases. +* +* NOTE: This module is NOT released with the C libs. It is for +* debugging purposes only. +* +*Revision History: +* 06-28-89 JCR Module created. +* 07-18-89 JCR Added _heap_print_regions() routine +* 11-13-89 GJF Added MTHREAD support, also fixed copyright +* 12-13-89 GJF Changed name of include file to heap.h +* 12-19-89 GJF Removed references to plastdesc +* 03-11-90 GJF Made the calling type _CALLTYPE1 and added #include +* <cruntime.h>. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <heap.h> +#include <malloc.h> +#include <os2dll.h> +#include <stdio.h> + +#ifdef DEBUG + +/*** +*_heap_print_all - Print the whole heap +* +*Purpose: +* +*Entry: +* <void> +* +*Exit: +* <void> +* +*Exceptions: +* +*******************************************************************************/ + +void _CALLTYPE1 _heap_print_all(void) +{ + /* lock the heap + */ + _mlock(_HEAP_LOCK); + + _heap_print_regions_lk(); + _heap_print_desc_lk(); + _heap_print_emptylist_lk(); + _heap_print_heaplist_lk(); + + /* release the heap lock + */ + _munlock(_HEAP_LOCK); +} + + +/*** +*_heap_print_regions - Print the heap region table +* +*Purpose: +* +*Entry: +* <void> +* +*Exit: +* <void> +* +*Exceptions: +* +*******************************************************************************/ + +#ifdef MTHREAD + +void _CALLTYPE1 _heap_print_regions(void) +{ + /* lock the heap + */ + _mlock(_HEAP_LOCK); + + _heap_print_regions_lk(); + + /* release the heap lock + */ + _munlock(_HEAP_LOCK); +} + +void _CALLTYPE1 _heap_print_regions_lk(void) + +#else /* ndef MTHREAD */ + +void _CALLTYPE1 _heap_print_regions(void) + +#endif /* MTHREAD */ +{ + int i; + + printf("\n--- Heap Regions ---\n\n"); + + printf("\t_heap_growsize (_amblksiz) = \t%x\n", _heap_growsize); + printf("\t_heap_regionsize = \t%x\n\n", _heap_regionsize); + + printf("\t_regbase\t_currsize\t_totalsize\n"); + printf("\t--------\t---------\t----------\n"); + for (i=0; i < _HEAP_REGIONMAX; i++) { + printf("\t%x\t\t%x\t\t%x\n", + _heap_regions[i]._regbase, + _heap_regions[i]._currsize, + _heap_regions[i]._totalsize); + } +} + + +/*** +*_heap_print_desc - Print the heap descriptor +* +*Purpose: +* +*Entry: +* <void> +* +*Exit: +* <void> +* +*Exceptions: +* +*******************************************************************************/ + +#ifdef MTHREAD + +void _CALLTYPE1 _heap_print_desc(void) +{ + _mlock(_HEAP_LOCK); + + _heap_print_desc_lk(); + + _munlock(_HEAP_LOCK); +} + +void _CALLTYPE1 _heap_print_desc_lk(void) + +#else /* ndef MTHREAD */ + +void _CALLTYPE1 _heap_print_desc(void) + +#endif /* MTHREAD */ +{ + + printf("\n--- Heap Descriptor ---\n\n"); + printf("\tpfirstdesc = %p\n", _heap_desc.pfirstdesc); + printf("\tproverdesc = %p\n", _heap_desc.proverdesc); + printf("\temptylist = %p\n", _heap_desc.emptylist); + printf("\t&sentinel = %p\n", &(_heap_desc.sentinel)); + +} + + +/*** +*_heap_print_emptylist - Print out the empty heap desc list +* +*Purpose: +* +*Entry: +* <void> +* +*Exit: +* <void> +* +*Exceptions: +* +*******************************************************************************/ + +#ifdef MTHREAD + +void _CALLTYPE1 _heap_print_emptylist(void) +{ + /* lock the heap + */ + _mlock(_HEAP_LOCK); + + _heap_print_emptylist_lk(); + + /* release the heap lock + */ + _munlock(_HEAP_LOCK); +} + +void _CALLTYPE1 _heap_print_emptylist_lk(void) + +#else /* ndef MTHREAD */ + +void _CALLTYPE1 _heap_print_emptylist(void) + +#endif /* MTHREAD */ +{ + + _PBLKDESC p; + int i; + + printf("\n--- Heap Empty Descriptor List ---\n\n"); + + if ((p = _heap_desc.emptylist) == NULL) { + printf("\t *** List is empty ***\n"); + return; + } + + for (i=1; p != NULL; p=p->pnextdesc, i++) { + + printf("\t(%i) Address = %p\n", i, p); + printf("\t\tpnextdesc = %p, pblock = %p\n\n", + p->pnextdesc, p->pblock); + + } + + printf("\t--- End of table ---\n"); + +} + + +/*** +*_heap_print_heaplist - Print out the heap desc list +* +*Purpose: +* +*Entry: +* <void> +* +*Exit: +* <void> +* +*Exceptions: +* +*******************************************************************************/ + +#ifdef MTHREAD + +void _CALLTYPE1 _heap_print_heaplist(void) +{ + /* lock the heap + */ + _mlock(_HEAP_LOCK); + + _heap_print_heaplist_lk(); + + /* release the heap lock + */ + _munlock(_HEAP_LOCK); +} + +void _CALLTYPE1 _heap_print_heaplist_lk(void) + +#else /* ndef MTHREAD */ + +void _CALLTYPE1 _heap_print_heaplist(void) + +#endif /* MTHREAD */ +{ + + _PBLKDESC p; + _PBLKDESC next; + int i; + int error = 0; + + printf("\n--- Heap Descriptor List ---\n\n"); + + if ((p = _heap_desc.pfirstdesc) == NULL) { + printf("\t *** List is empty ***\n"); + return; + } + + for (i=1; p != NULL; i++) { + + next = p->pnextdesc; + + /* Print descriptor address */ + + printf("\t(%i) Address = %p ", i, p); + + if (p == &_heap_desc.sentinel) + printf("<SENTINEL>\n"); + else if (p == _heap_desc.proverdesc) + printf("<ROVER>\n"); + else + printf("\n"); + + + + /* Print descriptor contents */ + + printf("\t\tpnextdesc = %p, pblock = %p", + p->pnextdesc, p->pblock); + + if (p == &_heap_desc.sentinel) { + if (next != NULL) { + printf("\n\t*** ERROR: sentinel.pnextdesc != NULL ***\n"); + error++; + } + } + else if (_IS_INUSE(p)) + printf(", usersize = %u <INUSE>", _BLKSIZE(p)); + + else if (_IS_FREE(p)) + printf(", usersize = %u <FREE>", _BLKSIZE(p)); + + else if (_IS_DUMMY(p)) + printf(", size = %u <DUMMY>", _MEMSIZE(p)); + + else { + printf(",\n\t*** ERROR: unknown status ***\n"); + error++; + } + + printf("\n\n"); + + if (_heap_desc.pfirstdesc == &_heap_desc.sentinel) { + printf("[No memory in heap]\n"); + } + + p = next; + } + + if (error) + printf("\n\t *** ERRORS IN HEAP TABLE ***\n"); + + printf("\t--- End of table ---\n"); + +} + +#endif /* DEBUG */ 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; + +} diff --git a/private/crt32/heap/heapinit.c b/private/crt32/heap/heapinit.c new file mode 100644 index 000000000..6658596fe --- /dev/null +++ b/private/crt32/heap/heapinit.c @@ -0,0 +1,266 @@ +/*** +*heapinit.c - Initialze the heap +* +* Copyright (c) 1989-1993, Microsoft Corporation. All rights reserved. +* +*Purpose: +* +*Revision History: +* 06-28-89 JCR Module created. +* 06-30-89 JCR Added _heap_grow_emptylist +* 11-13-89 GJF Fixed copyright +* 11-15-89 JCR Moved _heap_abort routine to another module +* 12-15-89 GJF Removed DEBUG286 stuff, did some tuning, changed header +* file name to heap.h and made functions explicitly +* _cdecl. +* 12-19-89 GJF Removed plastdesc field from _heap_desc_ struct +* 03-11-90 GJF Replaced _cdecl with _CALLTYPE1, added #include +* <cruntime.h> and removed #include <register.h>. +* 07-24-90 SBM Removed '32' from API names +* 10-03-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_) +* 03-05-91 GJF Added definition of _heap_resetsize (conditioned on +* _OLDROVER_ not being #define-d). +* 04-04-91 GJF Reduce _heap_regionsize to 1/2 a meg for Dosx32 +* (_WIN32_). +* 04-05-91 GJF Temporary hack for Win32/DOS folks - special version +* of _heap_init which calls HeapCreate. The change +* conditioned on _WIN32DOS_. +* 04-09-91 PNT Added _MAC_ conditional +* 02-23-93 SKS Remove DOSX32 support under WIN32 ifdef +* +*******************************************************************************/ + +#ifndef _WIN32DOS_ + +#include <cruntime.h> +#include <oscalls.h> +#include <dos.h> +#include <heap.h> +#include <stddef.h> +#include <stdio.h> + +#define _HEAP_EMPTYLIST_SIZE (1 * _PAGESIZE_) + +/* + * 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]; + +/* + * Control parameter locations + */ + +#ifndef _OLDROVER_ +unsigned int _heap_resetsize = 0xffffffff; +#endif /* _OLDROVER_ */ + +/* 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 _CALLTYPE1 _heap_init ( + void + ) +{ +#ifdef _CRUISER_ + + /* + * Currently nothing to do to init the 386 heap!!! + * If this stays true, we can get rid of the _heapinit call + * in startup and remove this module! + */ + +#else /* ndef _CRUISER*/ + +#ifdef _WIN32_ + + /* + * Currently nothing to do to init the 386 heap!!! + * If this stays true, we can get rid of the _heapinit call + * in startup and remove this module! + */ + +#else /* ndef _WIN32_ */ + +#error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED! + +#endif /* _WIN32_ */ + +#endif /* _CRUISER_ */ + +} + + + +/*** +* _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: +* +*******************************************************************************/ + +void _CALLTYPE1 _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. + */ + +#ifdef _CRUISER_ + + if ( DOSALLOCMEM(&last, _HEAP_EMPTYLIST_SIZE, _COMMIT, 0) != 0 ) + _heap_abort(); + +#else /* ndef _CRUISER_ */ + +#ifdef _WIN32_ + + if (!(last = VirtualAlloc(NULL, _HEAP_EMPTYLIST_SIZE, MEM_COMMIT, + PAGE_READWRITE))) + _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_ */ + + /* + * 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 */ +#ifdef DEBUG + first->pblock = NULL; +#endif + first->pnextdesc = next; + + /* onto the next block */ + + first = next++; + + } + + /* + * Take care of the last descriptor (end of the empty list) + */ + + last->pnextdesc = NULL; + +#ifdef DEBUG + last->pblock = NULL; +#endif + +} + +#else /* _WIN32DOS_ */ + +/* + * TEMPORARY HACK! THE CODE BELOW IS INTENDED TO ALLOW LIMITED USE OF THE + * C RUNTIME ON WIN32/DOS. IT WILL BE DELETED AS SOON AS THEY IMPLEMENT + * VirtualAlloc()! + */ + +#include <cruntime.h> +#include <oscalls.h> +#include <heap.h> + +HANDLE _HeapHandle; + +void _CALLTYPE1 _heap_init ( + void + ) +{ + if ( (_HeapHandle = HeapCreate(HEAP_SERIALIZE, 0x10000, 0)) == NULL ) + _heap_abort(); +} + +#endif /* _WIN32DOS_ */ diff --git a/private/crt32/heap/heapmin.c b/private/crt32/heap/heapmin.c new file mode 100644 index 000000000..dade55a47 --- /dev/null +++ b/private/crt32/heap/heapmin.c @@ -0,0 +1,520 @@ +/*** +*heapmin.c - Minimize the heap +* +* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Minimize the heap freeing as much memory as possible back +* to the OS. +* +*Revision History: +* 08-28-89 JCR Module created. +* 11-06-89 JCR Improved, partitioned +* 11-13-89 GJF Added MTHREAD support, also fixed copyright +* 12-14-89 GJF Couple of bug fixes, some tuning, cleaned up the +* formatting a bit and changed header file name to +* heap.h +* 12-20-89 GJF Removed references to plastdesc +* 03-11-90 GJF Replaced _cdecl with _CALLTYPE1, added #include +* <cruntime.h> and removed #include <register.h>. +* 03-29-90 GJF Made _heapmin_region() and _free_partial_region() +* _CALLTYPE4. +* 07-24-90 SBM Compiles cleanly with -W3 (tentatively removed +* unreferenced labels and unreachable code), removed +* '32' from API names +* 09-28-90 GJF New-style function declarators. Also, rewrote expr. +* to avoid using cast as lvalue. +* 12-04-90 SRW Changed to include <oscalls.h> instead of <doscalls.h> +* 12-06-90 SRW Added _CRUISER_ and _WIN32 conditionals. +* 12-28-90 SRW Added cast of void * to char * for Mips C Compiler +* 03-05-91 GJF Changed strategy for rover - old version available +* by #define-ing _OLDROVER_. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <oscalls.h> +#include <heap.h> +#include <malloc.h> +#include <os2dll.h> +#include <stdlib.h> + +static int _CALLTYPE4 _heapmin_region(int, void *, _PBLKDESC); +static void _CALLTYPE4 _free_partial_region(_PBLKDESC, unsigned, int); + + +/*** +*_heapmin() - Minimize the heap +* +*Purpose: +* Minimize the heap freeing as much memory as possible back +* to the OS. +* +*Entry: +* (void) +* +*Exit: +* +* 0 = no error has occurred +* -1 = an error has occurred (errno is set) +* +*Exceptions: +* +*******************************************************************************/ + +int _CALLTYPE1 _heapmin(void) +{ + REG1 int index; + _PBLKDESC pdesc; + +#ifdef _OLDROVER_ + REG2 _PBLKDESC pprev; +#else /* ndef _OLDROVER_ */ + REG2 _PBLKDESC pdesc2; +#endif /* _OLDROVER_ */ + + void * regend; + int region_min_count = 0; + + /* + * Lock the heap + */ + + _mlock(_HEAP_LOCK); + + /* + * Coalesce the heap (should return NULL) + */ + + if ( _heap_search(_HEAP_COALESCE) != NULL ) + _heap_abort(); + + /* + * Loop through the region descriptor table freeing as much + * memory to the OS as possible. + */ + + for ( index=0 ; index < _HEAP_REGIONMAX ; index++ ) { + + if ( _heap_regions[index]._regbase == NULL ) + continue; /* region entry is empty */ + + /* + * Get the entry that contains the last address of + * the region (allocated so far, that is). + */ + + regend = (char *) _heap_regions[index]._regbase + + _heap_regions[index]._currsize - 1; + + if ( _heap_findaddr(regend, &pdesc) != _HEAPFIND_WITHIN ) + _heap_abort(); /* last address not within a block */ + + /* + * See if the containing block is free + */ + + if ( !(_IS_FREE(pdesc)) ) + continue; /* block is not free */ + + + /* + * Region ends with a free block, go free as much mem + * as possible. + */ + + region_min_count += _heapmin_region(index, regend, pdesc); + + + } /* region loop */ + + /* + * By minimizing the heap, we've likely invalidated the rover and + * may have produced contiguous dummy blocks so: + * + * (1) reset the rover + * (2) coalesce contiguous dummy blocks + */ + + if ( region_min_count ) { + +#ifdef _OLDROVER_ + + for ( _heap_desc.proverdesc = pprev = pdesc = + _heap_desc.pfirstdesc ; pdesc != &_heap_desc.sentinel ; + pprev = pdesc, pdesc = pdesc->pnextdesc ) { + + /* + * set rover to first free block + */ + + if ( _IS_FREE(pdesc) && + !_IS_FREE(_heap_desc.proverdesc) ) + _heap_desc.proverdesc = pdesc; + + /* + * Check and remove consecutive dummy blocks + */ + + if ( _IS_DUMMY(pprev) ) { + + while ( _IS_DUMMY(pdesc) ) { + + /* + * be sure that pdesc and pprev are + * not the same (i.e., not both equal + * to pfirstdesc) + */ + + if ( pdesc == pprev ) + break; + + /* + * coalesce the dummy blocks + */ + + pprev->pnextdesc = pdesc->pnextdesc; + _PUTEMPTY(pdesc); + + /* + * advance pdesc and check for the + * sentinel + */ + + if ( (pdesc = pprev->pnextdesc) + == &_heap_desc.sentinel ) + goto endloop; + + } /* dummy loop */ + + } /* if */ + + } /* heap loop */ + + /* + * If still necessary, reset the rover descriptor pointer + */ + + endloop: + + if ( !_IS_FREE(_heap_desc.proverdesc) ) + _heap_desc.proverdesc = &_heap_desc.sentinel; + +#else /* ndef _OLDROVER_ */ + + /* + * Set proverdesc to pfirstdesc + */ + + _heap_desc.proverdesc = _heap_desc.pfirstdesc; + + for ( pdesc = _heap_desc.pfirstdesc ; pdesc != + &_heap_desc.sentinel ; pdesc = pdesc->pnextdesc ) { + + /* + * Check and remove consecutive dummy blocks + */ + + if ( _IS_DUMMY(pdesc) ) { + + for ( pdesc2 = pdesc->pnextdesc ; + _IS_DUMMY(pdesc2) ; + pdesc2 = pdesc->pnextdesc ) { + + /* + * coalesce the dummy blocks + */ + + pdesc->pnextdesc = pdesc2->pnextdesc; + _PUTEMPTY(pdesc2); + + } /* dummy loop */ + + } /* if */ + + } /* heap loop */ + +#endif /* _OLDROVER_ */ + + } /* region_min_count */ + + /* + * Good return + */ + + /* goodrtn: unreferenced label to be removed */ + /* + * Release the heap lock + */ + + _munlock(_HEAP_LOCK); + + return(0); + +#if 0 + /* unreachable code tentatively removed */ + + /* + * Error return + */ + + errrtn: + /* + * Release the heap lock + */ + + _munlock(_HEAP_LOCK); + + /* *** SET ERRNO *** */ + return(-1); +#endif +} + + +/*** +*_heapmin_region() - Minimize a region +* +*Purpose: +* Free as much of a region back to the OS as possible. +* +*Entry: +* int index = index of the region in the region table +* void * regend = last valid address in region +* pdesc = pointer to the last block of memory in the region +* (it has already been determined that this block is free) +* +*Exit: +* int 1 = minimized region +* 0 = no change to region +* +*Exceptions: +* +*******************************************************************************/ + +static int _CALLTYPE4 _heapmin_region ( + int index, + void * regend, + REG1 _PBLKDESC pdesc + ) +{ + unsigned size; + REG2 _PBLKDESC pnew; + + + /* + * Init some variables + * + * regend = 1st address AFTER region + * size = amount of free memory at end of current region + */ + + regend = (char *) regend + 1; /* "regend++" give compiler error... */ + size = ((char *)regend - (char *)_ADDRESS(pdesc)); + + + /* + * See if there's enough free memory to release to the OS. + * (NOTE: Need more than a page since we may need a back pointer.) + */ + + if ( size <= _PAGESIZE_ ) + return(0); /* 0 = no change to region */ + + /* + * We're going to free some memory to the OS. See if the + * free block crosses the end of the region and, if so, + * split up the block appropriately. + */ + + if ( (_MEMSIZE(pdesc) - size) != 0 ) { + + /* + * The free block spans the end of the region. + * Divide it up. + */ + + _GETEMPTY(pnew); /* get a new block */ + + pnew->pblock = regend; /* init block pointer */ + * (_PBLKDESC*)regend = pnew; /* init back pointer */ + _SET_FREE(pnew); /* set the block free */ + + pnew->pnextdesc = pdesc->pnextdesc; /* link it in */ + pdesc->pnextdesc = pnew; + + } + + + /* + * At this point, we have a free block of memory that goes + * up to (but not exceeding) the end of the region. + * + * pdesc = descriptor of the last free block in region + * size = amount of free mem at end of region (i.e., _MEMSIZE(pdesc)) + * regend = 1st address AFTER end of region + */ + + + /* + * See if we should return the whole region of only part of it. + */ + + if ( _ADDRESS(pdesc) == _heap_regions[index]._regbase ) { + + /* + * Whole region is free, return it to OS + */ + + _heap_free_region(index); + + /* + * Put a dummy block in the heap to hold space for + * the memory we just freed up. + */ + + _SET_DUMMY(pdesc); + + } + + else { + + /* + * Whole region is NOT free, return part of it to OS + */ + + _free_partial_region(pdesc, size, index); + + } + + /* + * Exit paths + */ + + return(1); /* 1 = minimized region */ + +} + + +/*** +*_free_partial_region() - Free part of a region to the OS +* +*Purpose: +* Free a portion of a region to the OS +* +*Entry: +* pdesc = descriptor of last free block in region +* size = amount of free mem at end of region (i.e., _MEMSIZE(pdesc)) +* index = index of region +* +*Exit: +* +*Exceptions: +* +*******************************************************************************/ + +static void _CALLTYPE4 _free_partial_region ( + REG1 _PBLKDESC pdesc, + unsigned size, + int index + ) +{ + unsigned left; + void * base; + REG2 _PBLKDESC pnew; + + /* + * Init a few variables. + */ + + left = (size & (_PAGESIZE_-1)); + base = (char *)_ADDRESS(pdesc); + + /* + * We return memory to the OS in page multiples. If the + * free block is not page aligned, we'll insert a new free block + * to fill in the difference. + */ + + if ( left != 0 ) { + + /* + * The block is not a multiple of pages so we need + * to adjust variables accordingly. + */ + + size -= left; + base = (char *)base + left; + } + + + /* + * Return the free pages to the OS. + */ + +#ifdef _CRUISER_ + + if ( DOSSETMEM(base, size, _DECOMMIT) != 0 ) + _heap_abort(); + +#else /* ndef _CRUISER_ */ + +#ifdef _WIN32_ + + if (!VirtualFree(base, size, MEM_DECOMMIT)) + _heap_abort(); + +#else /* ndef _WIN32_ */ + +#error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED! + +#endif /* _WIN32_ */ + +#endif /* _CRUISER_ */ + + /* + * Adjust the region table entry + */ + + _heap_regions[index]._currsize -= size; + + + /* + * Adjust the heap according to whether we released the whole + * free block or not. (Don't worry about consecutive dummies, + * we'll coalesce them later.) + * + * base = address of block we just gave back to OS + * size = size of block we gave back to OS + * left = size of block we did NOT give back to OS + */ + + if ( left == 0 ) { + + /* + * The free block was released to the OS in its + * entirety. Make the free block a dummy place holder. + */ + + _SET_DUMMY(pdesc); + + } + + else { + + /* + * Did NOT release the whole free block to the OS. + * There's a block of free memory we want to leave + * in the heap. Insert a dummy entry after it. + */ + + _GETEMPTY(pnew); + + pnew->pblock = (char *)base; + _SET_DUMMY(pnew); + + pnew->pnextdesc = pdesc->pnextdesc; + pdesc->pnextdesc = pnew; + + } + +} diff --git a/private/crt32/heap/heapprm.c b/private/crt32/heap/heapprm.c new file mode 100644 index 000000000..c0d810ecc --- /dev/null +++ b/private/crt32/heap/heapprm.c @@ -0,0 +1,87 @@ +/*** +*heapprm.c - Set/report heap parameters +* +* Copyright (c) 1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Set or report the values of certain parameters in the heap. +* +*Revision History: +* 03-04-91 GJF Module created. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <heap.h> +#include <malloc.h> +#include <os2dll.h> + +/*** +*_heap_param(int flag, int param_id, void *pparam) - set or report the values +* of the specified heap parameter. +* +*Purpose: +* Get or set certain parameters which affect the behavior of the heap. +* The supported parameters vary implementation to implementation and +* version to version. See description of entry conditions for the +* currently supported parameters. +* +*Entry: +* int flag - _HP_GETPARAM, to get a parameter value, or _HP_SETPARAM, +* to set a parameter value +* +* int param_id - identifier for the heap parameter. values supported in +* this release are: +* +* _HP_AMBLKSIZ - _amblksiz (aka _heap_growsize) parameter +* _HP_GROWSIZE - same as _HP_AMBLKSIZ +* _HP_RESETSIZE - _heap_resetsize parameter +* +* void *pparam - pointer to variable of appropriate type for the heap +* parameter to be fetched/set +* +*Exit: +* 0 = no error has occurred +* -1 = an error has occurred (errno is set) +* +*Exceptions: +* +*******************************************************************************/ + +int _CALLTYPE1 _heap_param ( + int flag, + int param_id, + void *pparam + ) +{ + + switch ( param_id ) { + + case _HP_RESETSIZE: + if ( flag == _HP_SETPARAM ) { + _mlock(_HEAP_LOCK); + _heap_resetsize = *(unsigned *)pparam; + _munlock(_HEAP_LOCK); + } + else + *(unsigned *)pparam = _heap_resetsize; + break; + + case _HP_AMBLKSIZ: + if ( flag == _HP_SETPARAM ) + /* + * the only references to _amblksiz (aka + * _heap_growsize) are atomic. therefore, the + * heap does not need to be locked. + */ + _amblksiz = *(unsigned *)pparam; + else + *(unsigned *)pparam = _amblksiz; + break; + + default: + return -1; + } + + return 0; +} diff --git a/private/crt32/heap/heapsrch.c b/private/crt32/heap/heapsrch.c new file mode 100644 index 000000000..2b07277cd --- /dev/null +++ b/private/crt32/heap/heapsrch.c @@ -0,0 +1,150 @@ +/*** +*heapsrch.c - search the heap for a free block +* +* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Defines the _heap_search() function. +* +*Revision History: +* 06-30-89 GJF Module created. Yea, it's ugly, but it seems to work. +* 07-21-89 GJF Now assumes proverdesc points to the descriptor for +* first free block in the heap, if any, or is plastdesc, +* if there are no free blocks +* 11-08-89 GJF Fixed copyright, added register attribute to vars +* 12-18-89 GJF Removed some redundant code, updated the description, +* changed include file name to heap.h, added explicit +* _cdecl to function definition. +* 12-19-89 GJF Got rid of code to maintain plastdesc +* 03-11-90 GJF Replaced _cdecl with _CALLTYPE1, added #include +* <cruntime.h> and removed #include <register.h>. +* 09-28-90 GJF New-style function declarator. +* 03-05-91 GJF Changed strategy for rover - old version available +* by #define-ing _OLDROVER_. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <heap.h> +#include <stddef.h> + +#define LOOP_FOREVER while(1) + +/*** +*_PBLKDESC _heap_search(unsigned size) - Find a free block of a least size +* bytes. +* +*Purpose: +* Finds a free block of at least size bytes. Searches the list of block +* descriptors from *proverdesc to the end (marked by the sentinel). The +* search is strictly first fit. Adjacent free blocks are coalesced as +* they are encountered during the search. +* +*Entry: +* unsigned size - size of block requested +* +*Exit: +* Success: Pointer to descriptor for free memory block of at least size +* bytes +* Failure: NULL +* +*Uses: +* +*Exceptions: +* +*******************************************************************************/ + +_PBLKDESC _CALLTYPE1 _heap_search ( + unsigned size + ) +{ + REG1 _PBLKDESC pdesc; + REG2 _PBLKDESC pdesc2; + _PBLKDESC pretdesc = NULL; + + /* search from proverdesc thru plastdesc, looking for free block of + * at least size bytes. coalesce adjacent free blocks during the + * search. the search is strictly first fit. that is, it terminates + * when the first block is found of adequate size. + */ + for ( pdesc = _heap_desc.proverdesc ; pdesc != &(_heap_desc.sentinel) ; + pdesc = pdesc->pnextdesc ) + /* is pdesc free? + */ + if ( _IS_FREE(pdesc) ) + /* coalesce loop + */ + LOOP_FOREVER { + /* if pdesc is big enough, return it + */ + if ( _BLKSIZE(pdesc) >= size ) { + pretdesc = pdesc; + goto searchdone; + } + + /* see if the next block is free and, if so, + * coalesce it with pdesc + */ + pdesc2 = pdesc->pnextdesc; + if ( _IS_FREE(pdesc2) ) { + /* coalesce pdesc2 with pdesc + */ + pdesc->pnextdesc = pdesc2->pnextdesc; + _PUTEMPTY(pdesc2); + } + else + break; + } /* end LOOP_FOREVER */ + +#ifndef _OLDROVER_ + + for ( pdesc = _heap_desc.pfirstdesc ; pdesc != _heap_desc.proverdesc ; + pdesc = pdesc->pnextdesc ) + /* is pdesc free? + */ + if ( _IS_FREE(pdesc) ) + /* coalesce loop + */ + LOOP_FOREVER { + /* if pdesc is big enough, return it + */ + if ( _BLKSIZE(pdesc) >= size ) { + pretdesc = pdesc; + goto searchdone; + } + + /* see if the next block is free and, if so, + * coalesce it with pdesc + */ + pdesc2 = pdesc->pnextdesc; + if ( _IS_FREE(pdesc2) ) { + /* coalesce pdesc2 with pdesc + */ + pdesc->pnextdesc = pdesc2->pnextdesc; + _PUTEMPTY(pdesc2); + + /* special handling for the case where + * the rover has been coalesced (search + * ends) + */ + if ( _heap_desc.proverdesc == pdesc2 ) + { + _heap_desc.proverdesc = pdesc; + if ( _BLKSIZE(pdesc) >= size ) + pretdesc = pdesc; + goto searchdone; + } + } + else + break; + } /* end LOOP_FOREVER */ + +#endif /* _OLDROVER_ */ + +searchdone: + + /* common exit for all code paths. win, lose or draw, this is the + * only code path back to the caller. + */ + return(pretdesc); +} diff --git a/private/crt32/heap/heapwalk.c b/private/crt32/heap/heapwalk.c new file mode 100644 index 000000000..8dc6067ca --- /dev/null +++ b/private/crt32/heap/heapwalk.c @@ -0,0 +1,170 @@ +/*** +*heapwalk.c - walk the heap +* +* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Defines the _heapwalk() function +* +*Revision History: +* 07-05-89 JCR Module created. +* 11-13-89 GJF Added MTHREAD support, also fixed copyright. +* 11-14-89 JCR Fixed bug -- returned address was off by HDRSIZE +* 12-18-89 GJF Removed DEBUG286 stuff, also some tuning, cleaned up +* format a bit, changed header file name to heap.h, added +* explicit _cdecl to function definition +* 12-20-89 GJF Removed references to plastdesc +* 03-11-90 GJF Replaced _cdecl with _CALLTYPE1, added #include +* <cruntime.h> and removed #include <register.h>. +* 09-28-90 GJF New-style function declarator. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <heap.h> +#include <malloc.h> +#include <os2dll.h> +#include <stddef.h> + + +/*** +*int _heapwalk() - Walk the heap +* +*Purpose: +* Walk the heap returning information on one entry at a time. +* +*Entry: +* struct _heapinfo { +* int * _pentry; heap entry pointer +* size_t size; size of heap entry +* int _useflag; free/inuse flag +* } *entry; +* +*Exit: +* Returns one of the following values: +* +* _HEAPOK - completed okay +* _HEAPEMPTY - heap not initialized +* _HEAPBADPTR - _pentry pointer is bogus +* _HEAPBADBEGIN - can't find initial header info +* _HEAPBADNODE - malformed node somewhere +* _HEAPEND - end of heap successfully reached +* +*Uses: +* +*Exceptions: +* +*******************************************************************************/ + +int _CALLTYPE1 _heapwalk ( + struct _heapinfo *_entry + ) +{ + REG1 _PBLKDESC pdesc; + _PBLKDESC polddesc; + int retval = _HEAPOK; + + /* + * Lock the heap + */ + + _mlock(_HEAP_LOCK); + + /* + * Quick header check + */ + + if ( (_heap_desc.pfirstdesc == NULL) || + (_heap_desc.proverdesc == NULL) || + (_heap_desc.sentinel.pnextdesc != NULL) ) { + retval = _HEAPBADBEGIN; + goto done; + } + + /* + * Check for an empty heap + */ + + if ( _heap_desc.pfirstdesc == &_heap_desc.sentinel ) { + retval = _HEAPEMPTY; + goto done; + } + + /* + * If _pentry is NULL, return info about the first entry. + * Else, get info about the next entry in the heap. + */ + + if ( _entry->_pentry == NULL ) { + pdesc = _heap_desc.pfirstdesc; + } + else { + /* + * Find the entry we gave to the user last time around + */ + + if ( _heap_findaddr( (void *)((char *)(_entry->_pentry) - + _HDRSIZE), &polddesc) != _HEAPFIND_EXACT ) { + retval = _HEAPBADPTR; + goto done; + } + + pdesc = polddesc->pnextdesc; + + } /* else */ + + + /* + * pdesc = entry to return info about + */ + + /* + * Skip over dummy entries + */ + + while ( _IS_DUMMY(pdesc) ) + pdesc = pdesc->pnextdesc; + + + /* + * See if we're at the end of the heap + */ + + if ( pdesc == &_heap_desc.sentinel ) { + retval = _HEAPEND; + goto done; + } + + /* + * Check back pointer (note that pdesc cannot point to a dummy + * descriptor since we have skipped over them) + */ + + if (!_CHECK_PDESC(pdesc)) { + retval = _HEAPBADPTR; + goto done; + } + + /* + * Return info on the next block + */ + + _entry->_pentry = ( (void *)((char *)_ADDRESS(pdesc) + _HDRSIZE) ); + _entry->_size = _BLKSIZE(pdesc); + _entry->_useflag = ( _IS_INUSE(pdesc) ? _USEDENTRY : _FREEENTRY ); + + + /* + * Common return + */ + +done: + /* + * Release the heap lock + */ + + _munlock(_HEAP_LOCK); + + return(retval); + +} diff --git a/private/crt32/heap/hpabort.c b/private/crt32/heap/hpabort.c new file mode 100644 index 000000000..9227a5b4b --- /dev/null +++ b/private/crt32/heap/hpabort.c @@ -0,0 +1,47 @@ +/*** +* hpabort.c - Abort process due to fatal heap error +* +* Copyright (c) 1988-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* +*Revision History: +* 11-13-89 JCR Module created +* 12-18-89 GJF #include-ed heap.h, also added explicit _cdecl to +* function definition. +* 03-11-90 GJF Replaced _cdecl with _CALLTYPE1 and added #include +* <cruntime.h>. +* 10-03-90 GJF New-style function declarator. +* 10-11-90 GJF Changed interface to _amsg_exit(). +* +*******************************************************************************/ + +#include <cruntime.h> +#include <heap.h> +#include <internal.h> +#include <rterr.h> + + +/*** +* _heap_abort() - Abort process due to fatal heap error +* +*Purpose: +* Terminate the process and output a heap error message +* +*Entry: +* Void +* +*Exit: +* Never returns +* +*Exceptions: +* +*******************************************************************************/ + +void _CALLTYPE1 _heap_abort ( + void + ) +{ + _amsg_exit(_RT_HEAP); /* heap error */ + /*** PROCESS TERMINATED ***/ +} diff --git a/private/crt32/heap/makefile b/private/crt32/heap/makefile new file mode 100644 index 000000000..9e18c9a05 --- /dev/null +++ b/private/crt32/heap/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +BLDCRT=1 +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/crt32/heap/malloc.c b/private/crt32/heap/malloc.c new file mode 100644 index 000000000..85148301b --- /dev/null +++ b/private/crt32/heap/malloc.c @@ -0,0 +1,474 @@ +/*** +*malloc.c - Get a block of memory from the heap +* +* Copyright (c) 1989-1993, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Defines the malloc() function. Also defines the internal utility +* functions _flat_malloc(), _heap_split_block(), _heap_advance_rover() +* and, for multi-thread, _malloc_lk(). +* +*Revision History: +* 06-29-89 GJF Module created (no rest for the wicked). +* 07-07-89 GJF Several bug fixes +* 07-21-89 GJF Added code to maintain proverdesc such that proverdesc +* either points to the descriptor for the first free +* block in the heap or, if there are no free blocks, is +* the same as plastdesc. +* 11-07-89 GJF Substantially revised to cope with 'tiling'. +* 11-09-89 GJF Embarrassing bug (didn't bother to assign pdesc) +* 11-10-89 GJF Added MTHREAD support. +* 11-17-89 GJF Oops, must call _free_lk() instead of free()! +* 12-18-89 GJF Changed name of header file to heap.h, also added +* explicit _cdecl to function definitions. +* 12-19-89 GJF Got rid of plastdesc from _heap_split_block() and +* _heap_advance_rover(). +* 03-11-90 GJF Replaced _cdecl with _CALLTYPE1, added #include +* <cruntime.h> and removed #include <register.h>. +* 07-25-90 SBM Replaced <stdio.h> by <stddef.h>, replaced +* <assertm.h> by <assert.h> +* 09-28-90 GJF New-style function declarators. +* 02-26-91 SRW Optimize heap rover for _WIN32_. +* 03-07-91 FAR Fix bug in heap rover +* 03-11-91 FAR REALLY Fix bug in heap rover +* 03-14-91 GJF Changed strategy for rover - old version available +* by #define-ing _OLDROVER_. +* 04-05-91 GJF Temporary hack for Win32/DOS folks - special version +* of malloc that just calls HeapAlloc. Change conditioned +* on _WIN32DOS_. +* 05-28-91 GJF Removed M_I386 conditionals and put in _CRUISER_ +* conditionals so the 'tiling' version is built only for +* Cruiser. +* 03-03-93 SKS Add new handler support (_pnhHeap and related code) +* +*******************************************************************************/ + +#include <cruntime.h> +#include <assert.h> +#include <heap.h> +#include <malloc.h> +#include <os2dll.h> +#include <stddef.h> + +#ifndef _POSIX_ +#include <new.h> +_PNH _pnhHeap = NULL; /* pointer to new() handler */ +#endif + +/*** +*void *malloc(size_t size) - Get a block of memory from the heap +* +*Purpose: +* Allocate of block of memory of at least size bytes from the heap and +* return a pointer to it. +* +* Special Notes For Cruiser Implementaton: For OS/2 2.0, malloc() is +* required to ensure that allocations of not more than 64 Kb do not +* cross 64 Kb boundaries in the address space. For this implementation, +* the straightforward, flat-model malloc is renamed to _flat_malloc() +* and a malloc() that worries about 'tiling' is built on top of this. +* +* Special Notes For Multi-thread: The non-multi-thread version is +* renamed to _malloc_lk(). The multi-thread malloc() simply locks the +* heap calls _malloc_lk, released the heap lock and returns. +* +*Entry: +* size_t size - size of block requested +* +*Exit: +* Success: Pointer to memory block +* Failure: NULL (or some error value) +* +*Uses: +* +*Exceptions: +* +*******************************************************************************/ + +#ifdef MTHREAD + +void * _CALLTYPE1 malloc ( + size_t size + ) +{ + void *pret; + +#ifndef _POSIX_ + for (;;) + { +#endif + /* lock the heap + */ + _mlock(_HEAP_LOCK); + + /* do the allocation + */ + pret = _malloc_lk(size); + + /* unlock the heap + */ + _munlock(_HEAP_LOCK); + +#ifndef _POSIX_ + if (pret || _pnhHeap == NULL || (*_pnhHeap)(size) == 0) +#endif + return(pret); + +#ifndef _POSIX_ + } +#endif /* ndef _POSIX_ */ +} + + +/*** +*void *_malloc_lk(size_t size) - non-locking form of malloc +* +*Purpose: +* Same as malloc() except that no locking or unlocking is performed. +* +*Entry: +* See malloc +* +*Exit: +* See malloc +* +*Uses: +* +*Exceptions: +* +*******************************************************************************/ + +void * _CALLTYPE1 _malloc_lk ( + size_t size + ) + +#else /* ndef MTHREAD */ + +void * _CALLTYPE1 malloc ( + size_t size + ) + +#endif /* MTHREAD */ + +#ifdef _CRUISER_ + +{ + char *pblck; + _PBLKDESC pdesc; + size_t dist; + + /* round size up to the nearest whole number of dwords + */ + size = _ROUND2(size, 4); + + /* first try allocating a block of size bytes + */ + if ( ((pblck = _flat_malloc(size)) == NULL) || (size > _SEGSIZE_) || + (_DISTTOBNDRY(pblck) >= size) ) + /* all done! + */ + goto done; + else + /* doesn't meet requirements, free the allocation back to the + * heap + */ + _free_lk(pblck); + + /* now, try allocating a block of 2*size bytes. if successful, the + * allocated block is guaranteed to contain a region of size bytes + * which does not cross a 64 K boundary. + */ + if ( (pblck = _flat_malloc(2*size)) == NULL ) + /* allocation failed, return NULL to the caller + */ + goto done; + + /* set pdesc to point to the descriptor for the allocation block + */ + pdesc = _BACKPTR(pblck); + + /* find a subregion of at least size bytes which does not cross a + * 64 Kb boundary and build a heap block around it. set pblck to + * point to to allocation area of the block and pdesc to point to + * its descriptor + */ + if ( (dist = _DISTTOBNDRY(pblck)) < size ) { + /* the subregion from pblck to (pblck + size) crosses a 64 Kb + * boundary, but the subregion from (pblck + dist) to (pblck + + * dist + size) cannot (it starts on one). therefore, split + * the block into two heap blocks, with the later block + * starting at (pblck + dist - _HDRSIZE), and free the first + * block. + */ + _heap_split_block(pdesc, dist - _HDRSIZE); + _free_lk(pblck); + pdesc = pdesc->pnextdesc; + _SET_INUSE(pdesc); + pblck += dist; + } + + /* pblck and pdesc are now bound to allocation block whose first size + * bytes do not cross any 64 Kb boundary. only detail is the block + * may be too large so... + */ +#ifdef _OLDROVER_ + + _heap_split_block(pdesc, size); + _SET_FREE(pdesc->pnextdesc); + _heap_advance_rover(); + +#else /* ndef _OLDROVER_ */ + + if ( _BLKSIZE(pdesc) > size ) { + _heap_split_block(pdesc, size); + _SET_FREE(pdesc->pnextdesc); + _heap_desc.proverdesc = pdesc->pnextdesc; + } + +#endif /* _OLDROVER_ */ + +done: + return(pblck); +} + + +/*** +*void *_flat_malloc(size_t size) - Get a block of memory from the heap +* +*Purpose: +* Allocate of block of memory of at least size bytes from the heap, +* without regard to whether or not it crosses a 64 Kb boundary, and +* return a pointer to it. +* +*Entry: +* size_t size - size of block requested +* +*Exit: +* Success: Pointer to memory block +* Failure: NULL (or some error value) +* +*Uses: +* +*Exceptions: +* +*******************************************************************************/ + + +void * _CALLTYPE1 _flat_malloc ( + size_t size + ) + +#endif /* _CRUISER_ */ + +{ + _PBLKDESC pdesc; + + /* validate size + */ + /***** COMMENTED OUT UNTIL _HEAP_MAXREQ IS DEFINED + if ( size > _HEAP_MAXREQ ) + return(NULL); + *****/ + + /* round requested size + */ + size = _ROUND2(size, 4); + +#if !defined(_POSIX_) && !defined(MTHREAD) + for (;;) + { +#endif /* !_POSIX && !MTHREAD */ + /* try to find a big enough free block + */ + if ( (pdesc = _heap_search(size)) == NULL ) + if ( _heap_grow(size) != -1 ) { + /* try finding a big enough free block again. the + * success of the call to _heap_grow should guarantee + * it, but... + */ + if ( (pdesc = _heap_search(size)) == NULL ) + /* something unexpected, and very bad, has + * happened. abort! + */ + _heap_abort(); + } +#if !defined(_POSIX_) && !defined(MTHREAD) + else if (!_pnhHeap || (*_pnhHeap)(size) == 0) + return(NULL); + else + continue; + else + break; /* success! */ + } +#else /* _POSIX || MTHREAD */ + else + return(NULL); +#endif /* !_POSIX && !MTHREAD */ + + /* carve the block into two pieces (if necessary). the first piece + * shall be of the exact requested size, marked inuse and returned to + * the caller. the leftover piece is to be marked free. + */ + if ( _BLKSIZE(pdesc) != size ) { + /* split up the block and free the leftover piece back to + * the heap + */ + _heap_split_block(pdesc, size); + _SET_FREE(pdesc->pnextdesc); + } + + /* mark pdesc inuse + */ + _SET_INUSE(pdesc); + + /* check proverdesc and reset, if necessary + */ +#ifdef _OLDROVER_ + + _heap_advance_rover(); + +#else /* ndef _OLDROVER_ */ + + _heap_desc.proverdesc = pdesc->pnextdesc; + +#endif /* _OLDROVER_ */ + + return( (void *)((char *)_ADDRESS(pdesc) + _HDRSIZE) ); +} + + +/*** +*void _heap_split_block(pdesc, newsize) - split a heap allocation block into +* two allocation blocks +* +*Purpose: +* Split the allocation block described by pdesc into two blocks, the +* first one being of newsize bytes. +* +* Notes: It is caller's responsibilty to set the status (i.e., free +* or inuse) of the two new blocks, and to check and reset proverdesc +* if necessary. See Exceptions (below) for additional requirements. +* +*Entry: +* _PBLKDESC pdesc - pointer to the allocation block descriptor +* size_t newsize - size for the first of the two sub-blocks (i.e., +* (i.e., newsize == _BLKSIZE(pdesc), on exit) +* +*Exit: +* There is no return value. +* +*Exceptions: +* It is assumed pdesc points to a valid allocation block descriptor and +* newsize is a valid heap block size as is (i.e., WITHOUT rounding). If +* either of these of assumption is violated, _heap_split_block() will +* likely corrupt the heap. Note also that _heap_split_block will simply +* return to the caller if newsize >= _BLKSIZE(pdesc), on entry. +* +*******************************************************************************/ + +void _CALLTYPE1 _heap_split_block ( + REG1 _PBLKDESC pdesc, + size_t newsize + ) +{ + REG2 _PBLKDESC pdesc2; + + assert(("_heap_split_block: bad pdesc arg", _CHECK_PDESC(pdesc))); + assert(("_heap_split_block: bad newsize arg", _ROUND2(newsize,4) == newsize)); + + /* carve the block into two pieces (if possible). the first piece + * is to be exactly newsize bytes. + */ + if ( _BLKSIZE(pdesc) > newsize ) { + /* get an empty decriptor + */ + _GETEMPTY(pdesc2) + + /* set it up to manage the second piece and link it in to + * the list + */ + pdesc2->pblock = (void *)((char *)_ADDRESS(pdesc) + newsize + + _HDRSIZE); + *(void **)(pdesc2->pblock) = pdesc2; + pdesc2->pnextdesc = pdesc->pnextdesc; + pdesc->pnextdesc = pdesc2; + } +} + +#ifdef _OLDROVER_ + +/*** +*void _heap_advance_rover(void) - check proverdesc and advance it, if necessary +* +*Purpose: +* Check proverdesc. If it is not pointing to the descriptor of a free +* block and is not equal to &sentinel, then walk up the list of heap +* block descriptors until the descriptor of a free block is reached +* and reset proverdesc to point to this descriptor, or until the end +* of the heap is reached and reset proverdesc to &sentinel. +* +*Entry: +* No arguments. +* +*Exit: +* No return value. +* +*Exceptions: +* +*******************************************************************************/ + +void _CALLTYPE1 _heap_advance_rover(void) +{ + REG1 _PBLKDESC pdesc; + + /* check proverdesc and advance it, if necessary + */ + +#ifdef _CRUISER_ /* CRUISER TARGET */ + + if ( !_IS_FREE(_heap_desc.proverdesc) && (_heap_desc.proverdesc != + &_heap_desc.sentinel) ) { + +#else /* ndef _CRUISER_ */ + +#ifdef _WIN32_ + + if ( _heap_desc.proverdesc != &_heap_desc.sentinel && + (!_IS_FREE(_heap_desc.proverdesc) || + _BLKSIZE(_heap_desc.proverdesc) <= 8)) { + +#else /* ndef _WIN32_ */ + +#error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED! + +#endif /* _WIN32_ */ + +#endif /* _CRUISER_ */ + + /* set pdesc to point to the descriptor for the next free + * block, if any, or &sentinel, otherwise. + */ + for ( pdesc = (_heap_desc.proverdesc)->pnextdesc ; +#ifdef _CRUISER_ /* CRUISER TARGET */ + !(_IS_FREE(pdesc)) && (pdesc != &_heap_desc.sentinel) ; +#else /* ndef _CRUISER_ */ +#ifdef _WIN32_ + pdesc != &_heap_desc.sentinel && + (!(_IS_FREE(pdesc)) || _BLKSIZE(pdesc) <= 8) ; +#else /* ndef _WIN32_ */ + +#error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED! + +#endif /* _WIN32_ */ + +#endif /* _CRUISER_ */ + pdesc = pdesc->pnextdesc ) + ; + + /* update proverdesc with pdesc + */ + _heap_desc.proverdesc = pdesc; + } +} + +#endif /* _OLDROVER_ */ diff --git a/private/crt32/heap/msize.c b/private/crt32/heap/msize.c new file mode 100644 index 000000000..103f2af9d --- /dev/null +++ b/private/crt32/heap/msize.c @@ -0,0 +1,112 @@ +/*** +*msize.c - calculate the size of a memory block in the heap +* +* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Defines the following function: +* _msize() - calculate the size of a block in the heap +* +*Revision History: +* 07-18-89 GJF Module created +* 11-13-89 GJF Added MTHREAD support. Also fixed copyright and got +* rid of DEBUG286 stuff. +* 12-18-89 GJF Changed name of header file to heap.h, also added +* explicit _cdecl to function definitions. +* 03-11-90 GJF Replaced _cdecl with _CALLTYPE1 and added #include +* <cruntime.h> +* 07-30-90 SBM Added return statement to MTHREAD _msize function +* 09-28-90 GJF New-style function declarators. +* 04-08-91 GJF Temporary hack for Win32/DOS folks - special version +* of _msize that calls HeapSize. Change conditioned on +* _WIN32DOS_. +* +*******************************************************************************/ + +#ifndef _WIN32DOS_ + +#include <cruntime.h> +#include <heap.h> +#include <malloc.h> +#include <os2dll.h> +#include <stdlib.h> + +/*** +*size_t _msize(pblck) - calculate the size of specified block in the heap +* +*Purpose: +* Calculates the size of memory block (in the heap) pointed to by +* pblck. +* +*Entry: +* void *pblck - pointer to a memory block in the heap +* +*Return: +* size of the block +* +*******************************************************************************/ + +#ifdef MTHREAD + +size_t _CALLTYPE1 _msize ( + void *pblck + ) +{ + size_t retval; + + /* lock the heap + */ + _mlock(_HEAP_LOCK); + + retval = _msize_lk(pblck); + + /* release the heap lock + */ + _munlock(_HEAP_LOCK); + + return retval; +} + +size_t _CALLTYPE1 _msize_lk ( + +#else /* ndef MTHREAD */ + +size_t _CALLTYPE1 _msize ( + +#endif /* MTHREAD */ + + void *pblck + ) +{ +#ifdef DEBUG + if (!_CHECK_BACKPTR(pblck)) + _heap_abort(); +#endif + + return( (size_t) ((char *)_ADDRESS(_BACKPTR(pblck)->pnextdesc) - + (char *)pblck) ); +} + + +#else /* _WIN32DOS_ */ + +/* + * TEMPORARY HACK! THE CODE BELOW IS INTENDED TO ALLOW LIMITED USE OF THE + * C RUNTIME ON WIN32/DOS. IT WILL BE DELETED AS SOON AS THEY IMPLEMENT + * VirtualAlloc()! + */ + +#include <cruntime.h> +#include <oscalls.h> +#include <malloc.h> + +extern HANDLE _HeapHandle; + +size_t _CALLTYPE1 _msize ( + void *pblck + ) +{ + return( (size_t)HeapSize(_HeapHandle, pblck) ); +} + +#endif /* _WIN32DOS_ */ diff --git a/private/crt32/heap/new.cxx b/private/crt32/heap/new.cxx new file mode 100644 index 000000000..4a47fb1c5 --- /dev/null +++ b/private/crt32/heap/new.cxx @@ -0,0 +1,28 @@ +/*** +*new.cxx - defines C++ new routine +* +* Copyright (c) 1990-1992, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Defines C++ new routine. +* +*Revision History: +* 05-07-90 WAJ Initial version. +* 08-30-90 WAJ new now takes unsigned ints. +* 08-08-91 JCR call _halloc/_hfree, not halloc/hfree +* 08-13-91 KRS Change new.hxx to new.h. Fix copyright. +* 08-13-91 JCR ANSI-compatible _set_new_handler names +* 10-30-91 JCR Split new, delete, and handler into seperate sources +* 11-13-91 JCR 32-bit version +* +*******************************************************************************/ + +#include <cruntime.h> +#include <malloc.h> +#include <new.h> + + +void * operator new( unsigned int cb ) +{ + return malloc( cb ); +} diff --git a/private/crt32/heap/realloc.c b/private/crt32/heap/realloc.c new file mode 100644 index 000000000..53d5a23b5 --- /dev/null +++ b/private/crt32/heap/realloc.c @@ -0,0 +1,477 @@ +/*** +*realloc.c - Reallocate a block of memory in the heap +* +* Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Defines the realloc() and _expand() functions. +* +*Revision History: +* 10-25-89 GJF Module created. +* 11-06-89 GJF Massively revised to handle 'tiling' and to properly +* update proverdesc. +* 11-10-89 GJF Added MTHREAD support. +* 11-17-89 GJF Fixed pblck validation (i.e., conditional call to +* _heap_abort()) +* 12-18-89 GJF Changed header file name to heap.h, also added explicit +* _cdecl or _pascal to function defintions +* 12-20-89 GJF Removed references to plastdesc +* 01-04-90 GJF Fixed a couple of subtle and nasty bugs in _expand(). +* 03-11-90 GJF Replaced _cdecl with _CALLTYPE1, added #include +* <cruntime.h> and removed #include <register.h>. +* 03-29-90 GJF Made _heap_expand_block() _CALLTYPE4. +* 07-25-90 SBM Replaced <stdio.h> by <stddef.h>, replaced +* <assertm.h> by <assert.h> +* 09-28-90 GJF New-style function declarators. +* 12-28-90 SRW Added cast of void * to char * for Mips C Compiler +* 03-05-91 GJF Changed strategy for rover - old version available +* by #define-ing _OLDROVER_. +* 04-08-91 GJF Temporary hack for Win32/DOS folks - special version +* of realloc that uses just malloc, _msize, memcpy and +* free. Change conditioned on _WIN32DOS_. +* 05-28-91 GJF Removed M_I386 conditionals and put in _WIN32_ +* conditionals to build non-tiling heap for Win32. +* +*******************************************************************************/ + +#ifndef _WIN32DOS_ + +#include <cruntime.h> +#include <assert.h> +#include <heap.h> +#include <malloc.h> +#include <os2dll.h> +#include <stddef.h> +#include <string.h> + +/* useful macro to compute the size of an allocation block given both a + * pointer to the descriptor and a pointer to the user area of the block + * (more efficient variant of _BLKSIZE macro, given the extra information) + */ +#define BLKSZ(pdesc,pblk) ((unsigned)_ADDRESS((pdesc)->pnextdesc) - \ + (unsigned)(pblck)) + +/* expand an allocation block, in place, up to or beyond a specified size + * by coalescing it with subsequent free blocks (if possible) + */ +static int _CALLTYPE4 _heap_expand_block(_PBLKDESC, size_t *, size_t); + +/*** +*void *realloc(void *pblck, size_t newsize) - reallocate a block of memory in +* the heap +* +*Purpose: +* Re-allocates a block in the heap to newsize bytes. newsize may be +* either greater or less than the original size of the block. The +* re-allocation may result in moving the block as well as changing +* the size. If the block is moved, the contents of the original block +* are copied over. +* +* Special ANSI Requirements: +* +* (1) realloc(NULL, newsize) is equivalent to malloc(newsize) +* +* (2) realloc(pblck, 0) is equivalent to free(pblck) (except that +* NULL is returned) +* +* (3) if the realloc() fails, the object pointed to by pblck is left +* unchanged +* +* Special Notes For Cruiser Implementaton: For OS/2 2.0, realloc() is +* required to ensure that the re-allocated block does not cross a 64 Kb +* boundary unless the new size is more than 64 Kb or the original block +* already crossed such a boundary. +* +* Special Notes For Multi-thread: The heap is locked immediately prior +* to assigning pdesc. This is after special cases (1) and (2), listed +* above, are taken care of. The lock is released immediately prior to +* the final return statement. +* +*Entry: +* void *pblck - pointer to block in the heap previously allocated +* by a call to malloc(), realloc() or _expand(). +* +* size_t newsize - requested size for the re-allocated block +* +*Exit: +* Success: Pointer to the re-allocated memory block +* Failure: NULL +* +*Uses: +* +*Exceptions: +* If pblck does not point to a valid allocation block in the heap, +* realloc() will behave unpredictably and probably corrupt the heap. +* +*******************************************************************************/ + +void * _CALLTYPE1 realloc ( + REG1 void *pblck, + size_t newsize + ) +{ + REG2 _PBLKDESC pdesc; + void *pretblck; + size_t oldsize; + size_t currsize; + + /* special cases, handling mandated by ANSI + */ + if ( pblck == NULL ) + /* just do a malloc of newsize bytes and return a pointer to + * the new block + */ + return( malloc(newsize) ); + + if ( newsize == 0 ) { + /* free the block and return NULL + */ + free(pblck); + return( NULL ); + } + + /* make newsize a valid allocation block size (i.e., round up to the + * nearest whole number of dwords) + */ + newsize = _ROUND2(newsize,4); + + /* if multi-thread support enabled, lock the heap here + */ + _mlock(_HEAP_LOCK); + + /* set pdesc to point to the descriptor for *pblck + */ + pdesc = _BACKPTR(pblck); + + if ( _ADDRESS(pdesc) != ((char *)pblck - _HDRSIZE) ) + _heap_abort(); + + /* see if pblck is big enough already, or can be expanded (in place) + * to be big enough. + */ +#ifdef _CRUISER_ + + /* if the block was expanded in place, ensure that it does not cross + * a 64 Kb boundary unless it already did so or newsize is greater + * than 64 Kb + */ + if ( ((oldsize = currsize = BLKSZ(pdesc, pblck)) >= newsize) || + ((_heap_expand_block(pdesc, &currsize, newsize) == 0) && + ((newsize > _SEGSIZE_) || (_DISTTOBNDRY(pdesc) >= newsize) || + (_DISTTOBNDRY(pdesc) < oldsize))) ) { + +#else /* ndef _CRUISER_ */ + +#ifdef _WIN32_ + + if ( ((oldsize = currsize = BLKSZ(pdesc, pblck)) > newsize) || + (_heap_expand_block(pdesc, &currsize, newsize) == 0) ) { + +#else /* ndef _WIN32_ */ + +#error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED! + +#endif /* _WIN32_ */ + +#endif /* _CRUISER_ */ + + /* if necessary, mark pdesc as inuse + */ + if ( _IS_FREE(pdesc) ) { + _SET_INUSE(pdesc); +#ifdef _OLDROVER_ + _heap_advance_rover(); +#endif /* _OLDROVER_ */ + } + + /* trim pdesc down to be exactly newsize bytes, if necessary + */ + if ( currsize > newsize ) { + _heap_split_block(pdesc, newsize); + _free_lk((char *)pblck + newsize + _HDRSIZE); + } + + pretblck = pblck; + goto realloc_done; + } + + /* try malloc-ing a new block of the requested size. if successful, + * copy over the data from the original block and free it. + */ + if ( (pretblck = _malloc_lk(newsize)) != NULL ) { + memcpy(pretblck, pblck, oldsize); + _free_lk(pblck); + } + else { + /* restore pblck to its orignal size + */ + _heap_split_block(pdesc, oldsize); + _free_lk((char *)pblck + oldsize + _HDRSIZE); + } + +realloc_done: + /* if multi-thread support is enabled, unlock the heap here + */ + _munlock(_HEAP_LOCK); + + return(pretblck); +} + + +/*** +*void *_expand(void *pblck, size_t newsize) - expand/contract a block of memory +* in the heap +* +*Purpose: +* Resizes a block in the heap to newsize bytes. newsize may be either +* greater (expansion) or less (contraction) than the original size of +* the block. The block is NOT moved. In the case of expansion, if the +* block cannot be expanded to newsize bytes, it is expanded as much as +* possible. +* +* Special Notes For Cruiser Implementaton: For OS/2 2.0, _expand() is +* required to ensure the resized block does not cross a 64 Kb boundary +* unless the requested new size is more than 64 Kb or the block already +* did so. Note that, because of the peculiar semantics of _expand(), it +* may produce block of less than 64 Kb in size which does cross a 64 Kb +* boundary. +* +* Special Notes For Multi-thread: The heap is locked just before pdesc +* is assigned and unlocked immediately prior to the return statement. +* +*Entry: +* void *pblck - pointer to block in the heap previously allocated +* by a call to malloc(), realloc() or _expand(). +* +* size_t newsize - requested size for the resized block +* +*Exit: +* Success: Pointer to the resized memory block (i.e., pblck) +* Failure: NULL +* +*Uses: +* +*Exceptions: +* If pblck does not point to a valid allocation block in the heap, +* _expand() will behave unpredictably and probably corrupt the heap. +* +*******************************************************************************/ + +void * _CALLTYPE1 _expand ( + REG1 void *pblck, + size_t newsize + ) +{ + REG2 _PBLKDESC pdesc; + void *pretblck = pblck; + size_t oldsize; + size_t currsize; + unsigned index; +#ifdef _CRUISER_ + size_t dist; +#endif /* _CRUISER_ */ + + /* make newsize a valid allocation block size (i.e., round up to the + * nearest whole number of dwords) + */ + newsize = _ROUND2(newsize,4); + + /* if multi-thread support enabled, lock the heap here + */ + _mlock(_HEAP_LOCK); + + /* set pdesc to point to the descriptor for *pblck + */ + pdesc = _BACKPTR(pblck); + + /* see if pblck is big enough already, or can be expanded (in place) + * to be big enough. + */ + if ( ((oldsize = currsize = BLKSZ(pdesc, pblck)) >= newsize) || + (_heap_expand_block(pdesc, &currsize, newsize) == 0) ) { + /* pblck is (now) big enough. trim it down, if necessary + */ + if ( currsize > newsize ) { + _heap_split_block(pdesc, newsize); + _free_lk((char *)pblck + newsize + _HDRSIZE); + currsize = newsize; + } + goto expand_done; + } + + /* if the heap block is at the end of a region, attempt to grow the + * region + */ + if ( (pdesc->pnextdesc == &_heap_desc.sentinel) || + _IS_DUMMY(pdesc->pnextdesc) ) { + + /* look up the region index + */ + for ( index = 0 ; index < _HEAP_REGIONMAX ; index++ ) + if ( (_heap_regions[index]._regbase < pblck) && + (((char *)(_heap_regions[index]._regbase) + + _heap_regions[index]._currsize) >= (char *)pblck) ) + break; + + /* make sure a valid region index was obtained (pblck could + * lie in a portion of heap memory donated by a user call to + * _heapadd(), which therefore would not appear in the region + * table) + */ + if ( index == _HEAP_REGIONMAX ) { + pretblck = NULL; + goto expand_done; + } + + /* try growing the region. the difference between newsize and + * the current size of the block, rounded up to the nearest + * whole number of pages, is the amount the region needs to + * be grown. if successful, try expanding the block again + */ + if ( (_heap_grow_region(index, _ROUND2(newsize - currsize, + _PAGESIZE_)) == 0) && + (_heap_expand_block(pdesc, &currsize, newsize) == 0) ) { + /* pblck is (now) big enough. trim it down to be + * exactly size bytes, if necessary + */ + if ( currsize > newsize ) { + _heap_split_block(pdesc, newsize); + _free_lk((char *)pblck + newsize + _HDRSIZE); + currsize = newsize; + } + } + else + pretblck = NULL; + } + else + pretblck = NULL; + +expand_done: +#ifdef _CRUISER_ + /* check for crossing of 64 Kb boundaries. the resized allocation + * block must be trimmed down if the following conditions all hold + * true: + * (1) the block was grown + * (2) the requested new size was less than 64 Kb + * (3) the block now crosses a 64 Kb boundary + * (4) the block did not originally cross a 64 Kb + * boundary + */ + if ( (currsize > oldsize) && (newsize <= _SEGSIZE_) && + (currsize > (dist = _DISTTOBNDRY(pblck))) && (oldsize <= dist) ) { + _heap_split_block(pdesc, dist); + _free_lk((char *)pblck + dist + _HDRSIZE); + pretblck = NULL; + } +#endif /* _CRUISER_ */ + + /* if multi-thread support is enabled, unlock the heap here + */ + _munlock(_HEAP_LOCK); + + return(pretblck); +} + + +/*** +*int _heap_expand_block(pdesc, pcurrsize, newsize) - expand an allocation block +* in place (without trying to 'grow' the heap) +* +*Purpose: +* +*Entry: +* _PBLKDESC pdesc - pointer to the allocation block descriptor +* size_t *pcurrsize - pointer to size of the allocation block (i.e., +* *pcurrsize == _BLKSIZE(pdesc), on entry) +* size_t newsize - requested minimum size for the expanded allocation +* block (i.e., newsize >= _BLKSIZE(pdesc), on exit) +* +*Exit: +* Success: 0 +* Failure: -1 +* In either case, *pcurrsize is updated with the new size of the block +* +*Exceptions: +* It is assumed that pdesc points to a valid allocation block descriptor. +* It is also assumed that _BLKSIZE(pdesc) == *pcurrsize on entry. If +* either of these assumptions is violated, _heap_expand_block will almost +* certainly trash the heap. +* +*******************************************************************************/ + +static int _CALLTYPE4 _heap_expand_block ( + REG1 _PBLKDESC pdesc, + REG3 size_t *pcurrsize, + size_t newsize + ) +{ + REG2 _PBLKDESC pdesc2; + + assert(("_heap_expand_block: bad pdesc arg", _CHECK_PDESC(pdesc))); + assert(("_heap_expand_block: bad pcurrsize arg", *pcurrsize == _BLKSIZE(pdesc))); + + for ( pdesc2 = pdesc->pnextdesc ; _IS_FREE(pdesc2) ; + pdesc2 = pdesc->pnextdesc ) { + + /* coalesce with pdesc. check for special case of pdesc2 + * being proverdesc. + */ + pdesc->pnextdesc = pdesc2->pnextdesc; + + if ( pdesc2 == _heap_desc.proverdesc ) +#ifdef _OLDROVER_ + /* temporarily set proverdesc to pdesc + */ +#endif /* _OLDROVER_ */ + _heap_desc.proverdesc = pdesc; + + /* update *pcurrsize, place *pdesc2 on the empty descriptor + * list and see if the coalesced block is now big enough + */ + *pcurrsize += _MEMSIZE(pdesc2); + + _PUTEMPTY(pdesc2) + } + +#ifdef _OLDROVER_ + if ( pdesc == _heap_desc.proverdesc ) + _heap_advance_rover(); +#endif /* _OLDROVER_ */ + + if ( *pcurrsize >= newsize ) + return(0); + else + return(-1); +} + +#else /* _WIN32DOS_ */ + +/* + * TEMPORARY HACK! THE CODE BELOW IS INTENDED TO ALLOW LIMITED USE OF THE + * C RUNTIME ON WIN32/DOS. IT WILL BE DELETED AS SOON AS THEY IMPLEMENT + * VirtualAlloc()! + */ + +#include <cruntime.h> +#include <malloc.h> +#include <stdlib.h> +#include <string.h> + +void * _CALLTYPE1 realloc ( + REG1 void *pblck, + size_t newsize + ) +{ + void *pnew; + size_t oldsize; + + if ( (pnew = malloc(newsize)) != NULL ) { + oldsize = _msize(pblck); + memcpy(pnew, pblck, min(newsize, oldsize)); + free(pblck); + } + + return pnew; +} + +#endif /* _WIN32DOS_ */ diff --git a/private/crt32/heap/sources b/private/crt32/heap/sources new file mode 100644 index 000000000..11d18fa85 --- /dev/null +++ b/private/crt32/heap/sources @@ -0,0 +1,71 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Steve Wood (stevewo) 12-Apr-1990 + jeffrob 29-sep-1990, use crt32.def + +NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl + +!ENDIF + +MAJORCOMP=crt +MINORCOMP=heap + +TARGETNAME=heap +TARGETPATH=..\obj +TARGETTYPE=LIBRARY +386_STDCALL=0 + +!INCLUDE ..\crt32.def + +!IFDEF 386_BLDCRT +SOURCES=calloc.c \ + findaddr.c \ + free.c \ + heapadd.c \ + heapchk.c \ + heapgrow.c \ + heapinit.c \ + heapmin.c \ + heapprm.c \ + heapsrch.c \ + hpabort.c \ + heapwalk.c \ + malloc.c \ + msize.c \ + realloc.c \ + handler.cxx \ + delete.cxx \ + new.cxx +!ELSE +SOURCES=calloc.c \ + findaddr.c \ + free.c \ + heapadd.c \ + heapchk.c \ + heapgrow.c \ + heapinit.c \ + heapmin.c \ + heapprm.c \ + heapsrch.c \ + hpabort.c \ + heapwalk.c \ + malloc.c \ + msize.c \ + realloc.c +!ENDIF |