mem.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 344 行 · 第 1/2 页

C
344
字号
/****************************************************************************
*
*                            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:  Heart of the heap manager. Do not break
*               unless you have a death wish.
*
****************************************************************************/


#include "variety.h"
#include <limits.h>
#include <malloc.h>
#include "heap.h"


#if defined(M_I86)
    extern unsigned setup_ds( unsigned );
    #pragma aux setup_ds = \
                "push ax" \
                "mov ax,ds" \
                "pop ds" \
                parm [ax] value [ax];
    #define setup_segment( _x ) _x = setup_ds( _x );
#else
    #define setup_segment( _x ) (void)(_x = _x);
#endif

//
// input:
//      size    - #bytes to allocate
//      segment - 16bit Intel data selector containing heap
//      offset  - address of heap control block
//                if 16bit Intel -> offset within segment
//                else           -> absolute pointer value
//
// output:
//      result  - address of allocated storage or zero on failure
//                if 16bit Intel -> offset within segment
//                else           -> absolute pointer value
//
unsigned __MemAllocator( unsigned size, unsigned segment, unsigned offset )
{
    frlptr result;
    result = 0;                                 // assume the worst

    setup_segment( segment );                   // setup DS for 16bit Intel

    if( size != 0 ) {                           // quit if size is zero
        unsigned new_size;
        new_size = size + TAG_SIZE + ROUND_SIZE;// round up size
        if( new_size >= size ) {                // quit if overflowed
            struct heapblkp _WCI86NEAR *heap;
            unsigned largest;
            heap = (struct heapblkp _WCI86NEAR *)offset;
            size = new_size & ~ROUND_SIZE;      // make size even
            largest = heap->largest_blk;
            if( size < FRL_SIZE ) {
                size = FRL_SIZE;
            }
            if( size <= largest ) {             // quit if size too big
                frlptr pcur;
                unsigned len;
                pcur = heap->rover;             // start at rover
                largest = heap->b4rover;
                if( size <= largest ) {         // check size with rover
                    pcur = heap->freehead.next; // start at beginning
                    largest = 0;                // reset largest block size
                }
                for(;;) {                       // search free list
                    len = pcur->len;
                    if( size <= len ) {         // found one
                        break;
                    }
                    if( len > largest ) {       // update largest block size
                        largest = len;
                    }
                    pcur = pcur->next;          // advance to next entry
                    if( pcur ==                 // if back at start
                        (frlptr)&(heap->freehead)) {
                        heap->largest_blk = largest;    // update largest
                        setup_segment( segment );       // 16bit Intel restore
                        return( (unsigned)result );     // return 0
                    }
                }
                heap->b4rover = largest;        // update rover size
                heap->numalloc++;               // udpate allocation count
                len -= size;                    // compute leftover size
                if( len >= FRL_SIZE ) {         // if leftover big enough
                                                // split into two chunks
                    frlptr pprev;               // before current
                    frlptr pnext;               // after current
                    frlptr pnew;                // start of new piece
                    pnew = (frlptr)((PTR)pcur + size);
                    heap->rover = pnew;         // update rover
                    pnew->len = len;            // set new size
                    pcur->len = size;           // reset current size
                    pprev = pcur->prev;         // update next/prev links
                    pnew->prev = pprev;
                    pnext = pcur->next;
                    pnew->next = pnext;
                    pprev->next = pnew;
                    pnext->prev = pnew;
                } else {                        // just use this chunk
                    frlptr pprev;               // before current
                    frlptr pnext;               // after current
                    heap->numfree--;            // 1 fewer entries in free list
                    pprev = pcur->prev;
                    heap->rover = pprev;        // update rover
                    pnext = pcur->next;         // update next/prev links
                    pprev->next = pnext;
                    pnext->prev = pprev;
                }
                pcur->len |= 1;                 // mark as allocated
                                                // get pointer to user area
                result = (frlptr)((PTR)pcur + TAG_SIZE);
            }
        }
    }
    setup_segment( segment );                   // 16bit Intel restore
    return( (unsigned)result );
}

//
// input:
//      pointer - address of block to free
//                if 16bit Intel -> offset within segment
//                else           -> absolute pointer value
//      segment - 16bit Intel data selector containing heap
//      offset  - address of heap control block
//                if 16bit Intel -> offset within segment
//                else           -> absolute pointer value
//
// output:
//      none
//
void __MemFree( unsigned pointer, unsigned segment, unsigned offset )
{
    setup_segment( segment );                   // setup DS for 16bit Intel

    if( pointer != 0 ) {                        // quit if pointer is zero
        frlptr pfree;
        pfree = (frlptr)(pointer - TAG_SIZE);
        if( pfree->len & 1 ) {                  // quit if storage is free
            struct heapblkp _WCI86NEAR *heap;
            frlptr pnext;
            frlptr pprev;
            frlptr ptr;
            unsigned len;
            heap = (struct heapblkp _WCI86NEAR *)offset;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?