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 + -
显示快捷键?