summaryrefslogtreecommitdiffstats
path: root/private/crt32/heap
diff options
context:
space:
mode:
Diffstat (limited to 'private/crt32/heap')
-rw-r--r--private/crt32/heap/calloc.c88
-rw-r--r--private/crt32/heap/delete.cxx28
-rw-r--r--private/crt32/heap/findaddr.c108
-rw-r--r--private/crt32/heap/free.c171
-rw-r--r--private/crt32/heap/handler.cxx53
-rw-r--r--private/crt32/heap/heapadd.c413
-rw-r--r--private/crt32/heap/heapchk.c330
-rw-r--r--private/crt32/heap/heapdump.c334
-rw-r--r--private/crt32/heap/heapgrow.c490
-rw-r--r--private/crt32/heap/heapinit.c266
-rw-r--r--private/crt32/heap/heapmin.c520
-rw-r--r--private/crt32/heap/heapprm.c87
-rw-r--r--private/crt32/heap/heapsrch.c150
-rw-r--r--private/crt32/heap/heapwalk.c170
-rw-r--r--private/crt32/heap/hpabort.c47
-rw-r--r--private/crt32/heap/makefile7
-rw-r--r--private/crt32/heap/malloc.c474
-rw-r--r--private/crt32/heap/msize.c112
-rw-r--r--private/crt32/heap/new.cxx28
-rw-r--r--private/crt32/heap/realloc.c477
-rw-r--r--private/crt32/heap/sources71
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(&region, 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