0,0 → 1,560 |
/**************************************************************************** |
* |
* Open Watcom Project |
* |
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved. |
* |
* ======================================================================== |
* |
* This file contains Original Code and/or Modifications of Original |
* Code as defined in and that are subject to the Sybase Open Watcom |
* Public License version 1.0 (the 'License'). You may not use this file |
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO |
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is |
* provided with the Original Code and Modifications, and is also |
* available at www.sybase.com/developer/opensource. |
* |
* The Original Code and all software distributed under the License are |
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM |
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF |
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR |
* NON-INFRINGEMENT. Please see the License for the specific language |
* governing rights and limitations under the License. |
* |
* ======================================================================== |
* |
* Description: Heap growing routines - allocate near heap memory from OS. |
* |
****************************************************************************/ |
|
|
//#include "dll.h" // needs to be first |
#include "variety.h" |
#include <stddef.h> |
#include <stdlib.h> |
#include <malloc.h> |
#include "heapacc.h" |
#include "heap.h" |
#include <errno.h> |
#if defined(__DOS_EXT__) |
// #include "extender.h" |
// #include "tinyio.h" |
#endif |
#if defined(__CALL21__) |
// #include "tinyio.h" |
#endif |
#if defined(__WINDOWS_286__) || defined(__NT__) |
void* _stdcall UserAlloc(int size); |
|
// #include "windows.h" |
#endif |
#if defined(__OS2__) |
// #include <wos2.h> |
#endif |
#if defined(__WINDOWS_386__) |
// extern void * pascal DPMIAlloc(unsigned long); |
#endif |
|
static frlptr __LinkUpNewMHeap( mheapptr ); |
|
#if defined(__DOS_EXT__) |
|
extern int SegmentLimit(); |
#pragma aux SegmentLimit = \ |
"xor eax,eax" \ |
"mov ax,ds" \ |
"lsl eax,ax" \ |
"inc eax" \ |
value [eax] \ |
modify exact [eax]; |
|
static void __unlink( mheapptr miniheapptr ) |
{ |
mheapptr prev_link; |
mheapptr next_link; |
|
if( __nheapbeg == miniheapptr ) { |
__nheapbeg = miniheapptr->next; |
} |
if( miniheapptr == __MiniHeapRover ) { |
__MiniHeapRover = miniheapptr->prev; |
if( __MiniHeapRover == NULL ) { |
__MiniHeapRover = __nheapbeg; |
__LargestSizeB4MiniHeapRover = 0; |
} |
} |
if( miniheapptr == __MiniHeapFreeRover ) { |
__MiniHeapFreeRover = 0; |
} |
prev_link = miniheapptr->prev; |
next_link = miniheapptr->next; |
if( prev_link != NULL ) prev_link->next = next_link; |
if( next_link != NULL ) next_link->prev = prev_link; |
} |
|
void __FreeDPMIBlocks() |
{ |
mheapptr mhp; |
struct dpmi_hdr *dpmi; |
|
mhp = __nheapbeg; |
while( mhp != NULL ) { |
// see if the last free entry has the full size of |
// the DPMI block ( - overhead). If it is then we can give this |
// DPMI block back to the DPMI host. |
if( (mhp->freehead.prev)->len + sizeof(struct miniheapblkp) == |
mhp->len ) { |
mheapptr pnext; |
|
dpmi = ((struct dpmi_hdr *)mhp) - 1; |
pnext = mhp->next; |
__unlink( mhp ); |
mhp = pnext; |
if( dpmi->dos_seg_value == 0 ) { // if DPMI block |
TinyDPMIFree( dpmi->dpmi_handle ); |
} else { // else DOS block below 1MB |
TinyFreeBlock( dpmi->dos_seg_value ); |
} |
} else { |
mhp = mhp->next; |
} |
} |
} |
|
void *__ReAllocDPMIBlock( frlptr p1, unsigned req_size ) |
{ |
mheapptr mhp; |
struct dpmi_hdr *dpmi; |
struct dpmi_hdr *prev_dpmi; |
unsigned size; |
frlptr flp, flp2; |
|
if( !__heap_enabled ) return( 0 ); |
__FreeDPMIBlocks(); |
prev_dpmi = NULL; |
for( mhp = __nheapbeg; mhp; mhp = mhp->next ) { |
if( ((PTR)mhp + sizeof(struct miniheapblkp) == (PTR)p1) |
&& (mhp->numalloc == 1) ) { |
// The mini-heap contains only this memblk |
__unlink( mhp ); |
dpmi = ((struct dpmi_hdr *)mhp) - 1; |
if( dpmi->dos_seg_value != 0 ) return( NULL ); |
size = mhp->len + sizeof(struct dpmi_hdr) + TAG_SIZE; |
size += ( req_size - (p1->len-TAG_SIZE) ); |
size += 0x0fff; |
size &= ~0x0fff; |
prev_dpmi = dpmi; |
dpmi = TinyDPMIRealloc( dpmi, size ); |
if( dpmi == NULL ) { |
dpmi = prev_dpmi; |
return( NULL ); // indicate resize failed |
} |
dpmi->dos_seg_value = 0; |
mhp = (mheapptr)( dpmi + 1 ); |
mhp->len = size - sizeof(struct dpmi_hdr) - TAG_SIZE; |
flp = __LinkUpNewMHeap( mhp ); |
mhp->numalloc = 1; |
|
// round up to even number |
req_size = (req_size + 1) & ~1; |
size = flp->len - req_size; |
if( size >= FRL_SIZE ) { // Enough to spare a free block |
flp->len = req_size | 1;// adjust size and set allocated bit |
// Make up a free block at the end |
flp2 = (frlptr)((PTR)flp + req_size); |
flp2->len = size | 1; |
++mhp->numalloc; |
mhp->largest_blk = 0; |
_nfree( (PTR)flp2 + TAG_SIZE ); |
} else { |
flp->len |= 1; // set allocated bit |
} |
return( flp ); |
} |
} |
return( NULL ); |
} |
#endif |
|
static frlptr __LinkUpNewMHeap( mheapptr p1 ) // originally __AddNewHeap() |
{ |
mheapptr p2; |
mheapptr p2_prev; |
tag *last_tag; |
unsigned amount; |
|
/* insert into ordered heap list (14-jun-91 AFS) */ |
/* logic wasn't inserting heaps in proper ascending order */ |
/* (09-nov-93 Fred) */ |
p2_prev = NULL; |
for( p2 = __nheapbeg; p2 != NULL; p2 = p2->next ) { |
if( p1 < p2 ) break; |
p2_prev = p2; |
} |
/* ascending order should be: p2_prev < p1 < p2 */ |
/* except for special cases when p2_prev and/or p2 are NULL */ |
p1->prev = p2_prev; |
p1->next = p2; |
if( p2_prev != NULL ) { |
p2_prev->next = p1; |
} else { /* add p1 to beginning of heap */ |
__nheapbeg = p1; |
} |
if( p2 != NULL ) { |
/* insert before 'p2' (list is non-empty) */ |
p2->prev = p1; |
} |
amount = p1->len - sizeof( struct miniheapblkp ); |
/* Fill out the new miniheap descriptor */ |
p1->freehead.len = 0; |
p1->freehead.prev = &p1->freehead; |
p1->freehead.next = &p1->freehead; |
p1->rover = &p1->freehead; |
p1->b4rover = 0; |
p1->numalloc = 0; |
p1->numfree = 0; |
p1++; |
((frlptr)p1)->len = amount; |
/* fix up end of heap links */ |
last_tag = (tag *) ( (PTR)p1 + amount ); |
*last_tag = END_TAG; |
return( (frlptr) p1 ); |
} |
|
#if ! ( defined(__WINDOWS_286__) || \ |
defined(__WINDOWS_386__) || \ |
defined(__WARP__) || \ |
defined(__NT__) \ |
) |
size_t __LastFree( void ) /* used by nheapgrow to know about adjustment */ |
{ |
frlptr p1; |
unsigned brk_value; |
|
if( __nheapbeg == NULL ) { /* no heap? can't have free blocks */ |
return( 0 ); |
} |
p1 = __nheapbeg->freehead.prev; /* point to last free block */ |
brk_value = (unsigned)((PTR)p1 + p1->len + TAG_SIZE ); |
#if defined(__DOS_EXT__) |
if( _IsPharLap() && !__X32VM) _curbrk = SegmentLimit(); /*19-feb-94*/ |
#endif |
if( brk_value == _curbrk ) { /* if last free block is at the end */ |
return( p1->len ); |
} |
return( 0 ); |
} |
#endif |
|
#if ! defined(__CALL21__) |
#if defined(__DOS_EXT__) |
static void *RationalAlloc( size_t size ) |
{ |
struct dpmi_hdr *dpmi; |
mheapptr mhp; |
tiny_ret_t save_DOS_block; |
tiny_ret_t DOS_block; |
|
__FreeDPMIBlocks(); |
/* size is a multiple of 4k */ |
dpmi = TinyDPMIAlloc( size ); |
if( dpmi != NULL ) { |
mhp = (mheapptr)( dpmi + 1 ); |
mhp->len = size - sizeof( struct dpmi_hdr ); |
dpmi->dos_seg_value = 0; // indicate DPMI block |
return( (void *)mhp ); |
} |
if( __minreal & 0xfff00000 ) { |
/* checks for users that want >1M real memory saved */ |
__minreal = 0xfffff; |
} |
if( size > 0x00010000 ) { |
/* cannot allocate more than 64k from DOS real memory */ |
return( NULL ); |
} |
save_DOS_block = TinyAllocBlock(( __minreal >> 4 ) | 1 ); |
if( TINY_OK( save_DOS_block ) ) { |
DOS_block = TinyAllocBlock( size >> 4 ); |
TinyFreeBlock( save_DOS_block ); |
if( TINY_OK( DOS_block ) ) { |
dpmi = (struct dpmi_hdr *) TinyDPMIBase( DOS_block ); |
dpmi->dos_seg_value = DOS_block; |
mhp = (mheapptr)( dpmi + 1 ); |
mhp->len = size - sizeof( struct dpmi_hdr ); |
return( (void *)mhp ); |
} |
} |
return( NULL ); |
} |
#endif |
#endif |
|
static int __AdjustAmount( unsigned *amount ) |
{ |
unsigned old_amount = *amount; |
unsigned amt; |
#if ! ( defined(__WINDOWS_286__) || \ |
defined(__WINDOWS_386__) || \ |
defined(__WARP__) || \ |
defined(__NT__) \ |
) |
unsigned last_free_amt; |
#endif |
|
amt = old_amount; |
amt = ( amt + TAG_SIZE + ROUND_SIZE) & ~ROUND_SIZE; |
if( amt < old_amount ) { |
return( 0 ); |
} |
#if ! ( defined(__WINDOWS_286__) || \ |
defined(__WINDOWS_386__) || \ |
defined(__WARP__) || \ |
defined(__NT__) \ |
) |
#if defined(__DOS_EXT__) |
if( _IsRationalZeroBase() || _IsCodeBuilder() ) { |
// Allocating extra to identify the dpmi block |
amt += sizeof(struct dpmi_hdr); |
} else { |
#else |
{ |
#endif |
last_free_amt = __LastFree(); /* adjust for last free block */ |
if( last_free_amt >= amt ) { |
amt = 0; |
} else { |
amt -= last_free_amt; |
} |
} |
#endif |
/* amount is even here */ |
/* |
extra amounts (22-feb-91 AFS) |
|
(1) adding a new heap needs: |
frl free block req'd for _nmalloc request |
(frl is the MINIMUM because the block |
may be freed) |
tag end of miniheap descriptor |
struct miniheapblkp start of miniheap descriptor |
(2) extending heap needs: |
tag free block req'd for _nmalloc request |
*/ |
*amount = amt; |
amt += ( (TAG_SIZE) + sizeof(frl) + sizeof(struct miniheapblkp) ); |
if( amt < *amount ) return( 0 ); |
if( amt < _amblksiz ) { |
/* |
_amblksiz may not be even so round down to an even number |
nb. pathological case: where _amblksiz == 0xffff, we don't |
want the usual round up to even |
*/ |
amt = _amblksiz & ~1u; |
} |
#if defined(__WINDOWS_386__) || \ |
defined(__WARP__) || \ |
defined(__NT__) || \ |
defined(__CALL21__) || \ |
defined(__DOS_EXT__) |
/* make sure amount is a multiple of 4k */ |
*amount = amt; |
amt += 0x0fff; |
if( amt < *amount ) return( 0 ); |
amt &= ~0x0fff; |
#endif |
*amount = amt; |
return( *amount != 0 ); |
} |
|
#if defined(__WINDOWS_286__) || \ |
defined(__WINDOWS_386__) || \ |
defined(__WARP__) || \ |
defined(__NT__) || \ |
defined(__CALL21__) || \ |
defined(__DOS_EXT__) |
static int __CreateNewNHeap( unsigned amount ) |
{ |
mheapptr p1; |
frlptr flp; |
unsigned brk_value; |
|
if( !__heap_enabled ) return( 0 ); |
if( _curbrk == ~1u ) return( 0 ); |
if( __AdjustAmount( &amount ) == 0 ) return( 0 ); |
#if defined(__WINDOWS_286__) |
brk_value = (unsigned) LocalAlloc( LMEM_FIXED, amount ); |
if( brk_value == 0 ) { |
return( 0 ); |
} |
#elif defined(__WINDOWS_386__) |
brk_value = (unsigned) DPMIAlloc( amount ); |
if( brk_value == 0 ) { |
return( 0 ); |
} |
#elif defined(__WARP__) |
{ |
PBYTE p; |
|
if( DosAllocMem( &p, amount, PAG_COMMIT|PAG_READ|PAG_WRITE ) ) { |
return( 0 ); |
} |
brk_value = (unsigned)p; |
} |
#elif defined(__NT__) |
// brk_value = (unsigned) VirtualAlloc( NULL, amount, MEM_COMMIT, |
// PAGE_EXECUTE_READWRITE ); |
brk_value = (unsigned) UserAlloc (amount ); |
|
//brk_value = (unsigned) LocalAlloc( LMEM_FIXED, amount ); |
if( brk_value == 0 ) { |
return( 0 ); |
} |
#elif defined(__CALL21__) |
{ |
tag _WCNEAR *tmp_tag; |
|
tmp_tag = (tag _WCNEAR *)TinyMemAlloc( amount ); |
if( tmp_tag == NULL ) { |
return( 0 ); |
} |
/* make sure it will not look like the end of a heap */ |
tmp_tag[0] = ! END_TAG; |
brk_value = (unsigned) &tmp_tag[2]; |
amount -= 2 * TAG_SIZE; // 11-jun-95, subtract extra tag |
} |
#elif defined(__DOS_EXT__) |
// if( _IsRationalZeroBase() || _IsCodeBuilder() ) { |
{ |
tag *tmp_tag; |
|
if( _IsRational() ) { |
tmp_tag = RationalAlloc( amount ); |
if( tmp_tag ) amount = *tmp_tag; |
} else { /* CodeBuilder */ |
tmp_tag = TinyCBAlloc( amount ); |
amount -= TAG_SIZE; |
} |
if( tmp_tag == NULL ) { |
return( 0 ); |
} |
brk_value = (unsigned) tmp_tag; |
} |
// Pharlap, RSI/non-zero can never call this function |
#endif |
if( amount - TAG_SIZE > amount ) { |
return( 0 ); |
} else { |
amount -= TAG_SIZE; |
} |
if( amount < sizeof( struct miniheapblkp ) + sizeof( frl ) ) { |
/* there isn't enough for a heap block (struct miniheapblkp) and |
one free block (frl) */ |
return( 0 ); |
} |
/* we've got a new heap block */ |
p1 = (mheapptr) brk_value; |
p1->len = amount; |
// Now link it up |
flp = __LinkUpNewMHeap( p1 ); |
amount = flp->len; |
/* build a block for _nfree() */ |
flp->len = amount | 1; |
++p1->numalloc; /* 28-dec-90 */ |
p1->largest_blk = 0; |
_nfree( (PTR)flp + TAG_SIZE ); |
return( 1 ); |
} |
#endif |
|
int __ExpandDGROUP( unsigned amount ) |
{ |
#if defined(__WINDOWS_286__) || \ |
defined(__WINDOWS_386__) || \ |
defined(__WARP__) || \ |
defined(__NT__) || \ |
defined(__CALL21__) |
// first try to free any available storage |
_nheapshrink(); |
return( __CreateNewNHeap( amount ) ); |
#else |
mheapptr p1; |
frlptr flp; |
unsigned brk_value; |
tag *last_tag; |
unsigned new_brk_value; |
void _WCNEAR *brk_ret; |
|
#if defined(__DOS_EXT__) |
if( ( _IsRationalZeroBase() || _IsCodeBuilder() ) ) { |
return( __CreateNewNHeap( amount ) ); // Won't slice either |
} |
// Rational non-zero based system should go through. |
#endif |
if( !__heap_enabled ) return( 0 ); |
if( _curbrk == ~1u ) return( 0 ); |
if( __AdjustAmount( &amount ) == 0 ) return( 0 ); |
#if defined(__DOS_EXT__) |
if( _IsPharLap() && !__X32VM ) { /* 19-feb-94 */ |
_curbrk = SegmentLimit(); |
} |
#endif |
new_brk_value = amount + _curbrk; |
if( new_brk_value < _curbrk ) { |
new_brk_value = ~1u; |
} |
brk_ret = __brk( new_brk_value ); |
if( brk_ret == (void _WCNEAR *) -1 ) { |
return( 0 ); |
} |
brk_value = (unsigned) brk_ret; |
if( brk_value > /*0xfff8*/ ~7u ) { |
return( 0 ); |
} |
if( new_brk_value <= brk_value ) { |
return( 0 ); |
} |
amount = new_brk_value - brk_value; |
if( amount - TAG_SIZE > amount ) { |
return( 0 ); |
} else { |
amount -= TAG_SIZE; |
} |
for( p1 = __nheapbeg; p1 != NULL; p1 = p1->next ) { |
if( p1->next == NULL ) break; |
if( (unsigned)p1 <= brk_value && |
((unsigned)p1)+p1->len+TAG_SIZE >= brk_value ) break; |
} |
if( (p1 != NULL) && |
((brk_value - TAG_SIZE) == (unsigned)( (PTR)p1 + p1->len) ) ) { |
/* we are extending the previous heap block (slicing) */ |
/* nb. account for the end-of-heap tag */ |
brk_value -= TAG_SIZE; |
amount += TAG_SIZE; |
flp = (frlptr) brk_value; |
/* adjust current entry in heap list */ |
p1->len += amount; |
/* fix up end of heap links */ |
last_tag = (tag *) ( (PTR)flp + amount ); |
last_tag[0] = END_TAG; |
} else { |
if( amount < sizeof( struct miniheapblkp ) + sizeof( frl ) ) { |
/* there isn't enough for a heap block (struct miniheapblkp) and |
one free block (frl) */ |
return( 0 ); |
} |
// Initializing the near heap if __nheapbeg == NULL, |
// otherwise, a new mini-heap is getting linked up |
p1 = (mheapptr) brk_value; |
p1->len = amount; |
flp = __LinkUpNewMHeap( p1 ); |
amount = flp->len; |
} |
/* build a block for _nfree() */ |
flp->len = amount | 1; |
++p1->numalloc; /* 28-dec-90 */ |
p1->largest_blk = ~0; /* set to largest value to be safe */ |
_nfree( (PTR)flp + TAG_SIZE ); |
return( 1 ); |
#endif |
} |