diff options
Diffstat (limited to 'private/crt32/heap/malloc.c')
-rw-r--r-- | private/crt32/heap/malloc.c | 474 |
1 files changed, 474 insertions, 0 deletions
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_ */ |