memmgr.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 358 行

C
358
字号
/****************************************************************************
*
*                            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:  WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
*               DESCRIBE IT HERE!
*
****************************************************************************/


#define USE_CG_MEMMGT

#include "plusplus.h"

#include <stddef.h>
#include <unistd.h>

#include "errdefns.h"
#include "memmgr.h"
#include "toggle.h"
#include "ring.h"
#include "initdefs.h"
#include "pragdefn.h"
#include "codegen.h"
#ifdef TRACKER
#include "trmem.h"
#endif


#ifdef USE_CG_MEMMGT
#   include "sysmacro.h"
    extern void CGFree( void* );
#   undef TRACKER
#else
#   ifdef TRACKER
#       include "trmem.h"
#   endif
#endif


typedef struct cleanup *CLEANPTR;
struct cleanup {
    CLEANPTR            next;
    void                (*rtn)( void );
};

typedef struct perm_blk *PERMPTR;
struct perm_blk {
    PERMPTR             next;
    size_t              amt_left;
    size_t              size;
    char                mem[1];
};
#define PERM_MAX_ALLOC  (1024)
#define PERM_MIN_ALLOC  (128)

static CLEANPTR cleanupList;
static PERMPTR permList;

#ifndef NDEBUG
static void *deferredFreeList;
#endif

#ifdef TRACKER

static _trmem_hdl   trackerHdl;

static void printLine( void *dummy, const char *buf, size_t len )
/***************************************************************/
{
    dummy = dummy;      /* done to avoid a warning */
    write( STDOUT_FILENO, buf, len );
}

#define alloc_mem( size ) _trmem_alloc( size, _trmem_guess_who(), trackerHdl )

#else

  #ifdef USE_CG_MEMMGT
    #define alloc_mem( size ) CGAlloc( size )
  #else
    #define alloc_mem( size ) malloc( size )
  #endif

#endif



static void *alloc_from_cleanup(
    size_t amt )
{
    PERMPTR p;
    CLEANPTR curr;

    RingIterBeg( cleanupList, curr ) {
        curr->rtn();
        p = alloc_mem( amt );
        if( p != NULL ) {
            return( p );
        }
    } RingIterEnd( curr )
    return( NULL );
}

void CMemRegisterCleanup( void (*cleanup)( void ) )
/*************************************************/
{
    CLEANPTR new_cleanup;

    new_cleanup = (CLEANPTR) RingAlloc( &cleanupList
                                      , sizeof( *new_cleanup ) );
    new_cleanup->rtn = cleanup;
}

void *CMemAlloc( size_t size )
/****************************/
{
    void *p;

    if( size == 0 ) {
        return( NULL );
    }
#ifndef NDEBUG
    if( ! PragDbgToggle.no_mem_cleanup ) {
        CLEANPTR curr;
        static unsigned test_cleanup;
        static unsigned test_inc = 1;

        test_cleanup += test_inc;
        if( test_cleanup > 1000 ) {
            test_cleanup = 0;
            RingIterBeg( cleanupList, curr ) {
                curr->rtn();
            } RingIterEnd( curr )
        }
    }
#endif
    p = alloc_mem( size );
    if( p != NULL ) {
        return( p );
    }
    p = alloc_from_cleanup( size );
    if( p == NULL ) {
        CErr1( ERR_OUT_OF_MEMORY );
        CSuicide();
    }
    return( p );
}

#ifdef TRACKER
    #define _doFree( p )    _trmem_free( p, _trmem_guess_who(), trackerHdl );
#else
  #ifdef USE_CG_MEMMGT
    #define _doFree( p )    CGFree( p );
  #else
    #define _doFree( p )    free( p );
  #endif
#endif

void CMemFree( void *p )
/**********************/
{
    if( p != NULL ) {
        _doFree( p );
    }
}

void CMemFreePtr( void **pp )
/***************************/
{
    void *p;

    p = *pp;
    if( p != NULL ) {
        _doFree( p );
        *pp = NULL;
    }
}

#ifndef NDEBUG
void CMemDeferredFree( void *p )
/******************************/
{
    if( p != NULL ) {
        RingPush( &deferredFreeList, p );
    }
}
#endif

static void linkPerm( PERMPTR p, size_t amt )
{
    p->size = amt;
    p->amt_left = amt;
    RingPush( &permList, p );
}

static void addPerm( size_t size )
{
    PERMPTR p;
    size_t amt;

    if( size > PERM_MAX_ALLOC ) {
        p = CMemAlloc( ( sizeof( *p ) - sizeof( char ) ) + size );
        linkPerm( p, size );
        return;
    }
    amt = PERM_MAX_ALLOC;
    for(;;) {
        p = alloc_mem( ( sizeof( *p ) - sizeof( char ) ) + amt );
        if( p != NULL ) {
            linkPerm( p, amt );
            return;
        }
        p = alloc_from_cleanup( ( sizeof( *p ) - sizeof( char ) ) + amt );
        if( p != NULL ) {
            linkPerm( p, amt );
            return;
        }
        if( amt == PERM_MIN_ALLOC ) break;
        amt >>= 1;
    }
}

static void *cutPerm( PERMPTR find, size_t size )
{
    void *p;

    if( size <= find->amt_left ) {
        p = &(find->mem[find->size - find->amt_left]);
        find->amt_left -= size;
        return( p );
    }
    return( NULL );
}

void *CPermAlloc( size_t size )
/*****************************/
{
    void *p;
    PERMPTR find;

    size += sizeof( int ) - 1;
    size &= ~( sizeof( int ) - 1 );
    RingIterBeg( permList, find ) {
        p = cutPerm( find, size );
        if( p != NULL ) {
            return( p );
        }
    } RingIterEnd( find )
    addPerm( size );
    RingIterBeg( permList, find ) {
        p = cutPerm( find, size );
        if( p != NULL ) {
            return( p );
        }
    } RingIterEnd( find )
    CErr1( ERR_OUT_OF_MEMORY );
    CSuicide();
    return( NULL );
}


static void cmemInit(           // INITIALIZATION
    INITFINI* defn )            // - definition
{
    defn = defn;
#ifdef USE_CG_MEMMGT
    BEMemInit();
#endif
#ifdef TRACKER
    {
        unsigned trmem_flags;

        trmem_flags = _TRMEM_ALLOC_SIZE_0 | _TRMEM_OUT_OF_MEMORY;
        if( CppGetEnv( "TRQUIET" ) == NULL ) {
            trmem_flags |= _TRMEM_CLOSE_CHECK_FREE;
        }
        trackerHdl = _trmem_open( malloc, free, NULL, NULL, NULL,printLine,
                                  trmem_flags );
    }
#endif
    DbgStmt( deferredFreeList = NULL );
    cleanupList = NULL;
    permList = NULL;
    addPerm( 0 );
}

static void cmemFini(           // COMPLETION
    INITFINI* defn )            // - definition
{
    defn = defn;
    RingFree( &permList );
#ifndef NDEBUG
    RingFree( &deferredFreeList );
#endif
#ifdef USE_CG_MEMMGT
    BEMemFini();
#endif
#ifdef TRACKER
#ifndef NDEBUG
    if( PragDbgToggle.dump_memory ) {
        _trmem_prt_list( trackerHdl );
    }
    if( _trmem_close( trackerHdl ) != 0
     && ! CompFlags.compile_failed ) {
        // we can't print an error message since we have no more memory
        __trap();
    }
#endif
#endif
}


INITDEFN( memmgr, cmemInit, cmemFini )


static void cleanupInit(        // INITIALIZATION
    INITFINI* defn )            // - definition
{
    defn = defn;
    cleanupList = NULL;
#if 0
    BEMemInit();
#endif
}


static void cleanupFini(        // COMPLETION
    INITFINI* defn )            // - definition
{
    defn = defn;
    RingFree( &cleanupList );
}

INITDEFN( mem_cleanup, cleanupInit, cleanupFini )

⌨️ 快捷键说明

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