summaryrefslogtreecommitdiffstats
path: root/private/crt32/heap/heapadd.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/crt32/heap/heapadd.c413
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;
+
+}