grownear.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 557 行 · 第 1/2 页
C
557 行
/****************************************************************************
*
* 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__)
#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( void );
#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( void )
{
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 );
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?