diff options
Diffstat (limited to '')
-rw-r--r-- | private/crt32/heap/heapadd.c | 413 |
1 files changed, 413 insertions, 0 deletions
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; + +} |