cvvirt.c

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

C
290
字号
/****************************************************************************
*
*                            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!
*
****************************************************************************/


#include <string.h>
#include <limits.h>
#include "cvinfo.h"

#define PAGE_BITS       12
#define DIR_BITS        4
#define PAGE_SIZE       (1U<<PAGE_BITS)
#define DIR_SIZE        (1UL<<DIR_BITS)

#define GET_DIR( v )    ((v) >> (DIR_BITS+PAGE_BITS))
#define GET_PAGE( v )   (((v) >> PAGE_BITS) & (DIR_SIZE-1))
#define GET_OFFSET( v ) ((v) & (PAGE_SIZE-1))

typedef struct {
    unsigned_16         time_stamp;
    unsigned_16         len;
    unsigned_8          data[1];        /* variable sized */
} loaded_block;

typedef struct virt_page {
    loaded_block        *block;
    unsigned_16         offset;
} virt_page;


static unsigned         TimeStamp;

dip_status VMInit( imp_image_handle *ii, unsigned long size )
{
    ii->vm_dir_num = BLOCK_FACTOR( size, DIR_SIZE*PAGE_SIZE );
    ii->virt = DCAlloc( ii->vm_dir_num * sizeof( ii->virt ) );
    if( ii->virt == NULL ) {
        DCStatus( DS_ERR|DS_NO_MEM );
        return( DS_ERR|DS_NO_MEM );
    }
    memset( ii->virt, 0, ii->vm_dir_num * sizeof( ii->virt ) );
    return( DS_OK );
}

void VMFini( imp_image_handle *ii )
{
    int         i;
    int         j;
    virt_page   *pg;

    if( ii->virt != NULL ) {
        for( i = ii->vm_dir_num-1; i >= 0; --i ) {
            if( ii->virt[i] != NULL ) {
                for( j = DIR_SIZE-1; j >= 0; --j ) {
                    pg = ii->virt[i][j];
                    if( pg != NULL && pg->offset == 0 ) {
                        DCFree( pg );
                    }
                }
                DCFree( ii->virt[i] );
            }
        }
        DCFree( ii->virt );
        ii->virt = NULL;
    }
}

static unsigned KillPages( imp_image_handle *ii, unsigned i, unsigned j )
{
    unsigned            idx;
    unsigned            num_pages;
    virt_page           *pg;

    pg = ii->virt[i][j];
    num_pages = pg->block->len / PAGE_SIZE;
    for( idx = 0; idx < num_pages; ++idx ) {
        if( j >= DIR_SIZE ) {
            ++i;
            j = 0;
        }
        ii->virt[i][j] = NULL;
        ++j;
    }
    DCFree( pg );
    return( num_pages * PAGE_SIZE );
}

static int InitPageDir( imp_image_handle *ii, unsigned dir_idx )
{
    ii->virt[dir_idx] = DCAlloc( sizeof( virt_page * ) * DIR_SIZE );
    if( ii->virt[dir_idx] == NULL ) {
        DCStatus( DS_ERR|DS_NO_MEM );
        return( 0 );
    }
    memset( ii->virt[dir_idx], 0, sizeof( virt_page * ) * DIR_SIZE );
    return( 1 );
}

void *VMBlock( imp_image_handle *ii, virt_mem start, unsigned len )
{
    unsigned            dir_idx;
    unsigned            pg_idx;
    unsigned            tmp_idx;
    int                 i;
    int                 j;
    unsigned            num_pages;
    virt_mem            pg_start;
    virt_page           *pg;
    virt_page           *zero;
    loaded_block        *block;

    dir_idx = GET_DIR( start );
    if( ii->virt[dir_idx] == NULL ) {
        if( !InitPageDir( ii, dir_idx ) ) return( NULL );
    }
    pg_idx = GET_PAGE( start );
    len += start % PAGE_SIZE;
    pg_start = start & ~(virt_mem)(PAGE_SIZE-1);
    pg = ii->virt[dir_idx][pg_idx];
    if( pg == NULL || (pg->block->len - pg->offset) < len ) {
        /* unloaded previously loaded block */
        if( pg != NULL ) {
            tmp_idx = dir_idx;
            /* find first page of the block */
            i = pg_idx;
            for( ;; ) {
                ii->virt[tmp_idx][i] = NULL;
                if( pg->offset == 0 ) break;
                if( i == 0 ) {
                    --tmp_idx;
                    i = DIR_SIZE;
                }
                --i;
                --pg;
            }
            DCFree( pg );
        }
        num_pages = BLOCK_FACTOR( len, PAGE_SIZE );
        pg = DCAlloc( num_pages * (sizeof(*pg)+PAGE_SIZE) + sizeof(loaded_block)-1 );
        if( pg == NULL ) {
            DCStatus( DS_ERR|DS_NO_MEM );
            return( NULL );
        }
        /* set up new page table entries */
        block = (loaded_block *)&pg[num_pages];
        tmp_idx = dir_idx;
        for( j = pg_idx, i = 0; i < num_pages; ++j, ++i ) {
            pg[i].block = block;
            pg[i].offset = i * PAGE_SIZE;
            if( j >= DIR_SIZE ) {
                ++tmp_idx;
                j = 0;
            }
            if( ii->virt[tmp_idx] == NULL ) {
                if( !InitPageDir( ii, tmp_idx ) ) {
                    /* unwind the setup already done */
                    num_pages = i;
                    for( i = 0; i < num_pages; ++i, ++pg_idx ) {
                        if( pg_idx >= DIR_SIZE ) {
                            ++dir_idx;
                            pg_idx = 0;
                        }
                        ii->virt[dir_idx][pg_idx] = NULL;
                    }
                    DCFree( pg );
                    return( NULL );
                }
            }
            if( ii->virt[tmp_idx][j] != NULL ) {
                /*
                    We just ran into another allocated block, so we have
                    to kill all the pages mapped in by it. We know that
                    if the page pointer is non-NULL, it will be offset==0
                    since KillPages will clean out the others.
                */
                KillPages( ii, tmp_idx, j );
            }
            ii->virt[tmp_idx][j] = &pg[i];
        }
        /* read in new block */
        len = num_pages * PAGE_SIZE;
        block->len = len;
        pg_start += ii->bias;
        if( DCSeek( ii->sym_file, pg_start, DIG_ORG ) != pg_start ) {
            DCStatus( DS_ERR|DS_FSEEK_FAILED );
            return( NULL );
        }
        /* last block might be a short read */
        if( DCRead( ii->sym_file, pg->block->data, len ) == (unsigned)-1 ) {
            DCStatus( DS_ERR|DS_FREAD_FAILED );
            return( NULL );
        }
        pg = ii->virt[dir_idx][pg_idx];
    }
    ++TimeStamp;
    if( TimeStamp == 0 ) {
        /* deal with wrap-around */
        for( ii = ImageList; ii != NULL; ii = ii->next_image ) {
            if( ii->virt != NULL ) {
                for( i = ii->vm_dir_num-1; i >= 0; --i ) {
                    if( ii->virt[i] != NULL ) {
                        for( j = DIR_SIZE-1; j >= 0; --j ) {
                            zero = ii->virt[i][j];
                            if( zero != NULL ) {
                                zero->block->time_stamp = 0;
                            }
                        }
                    }
                }
            }
        }
        ++TimeStamp;
    }
    pg->block->time_stamp = TimeStamp;
    return( &pg->block->data[ (start & (PAGE_SIZE - 1)) + pg->offset ] );
}

void *VMRecord( imp_image_handle *ii, virt_mem rec )
{
    s_common    *p;

    p = VMBlock( ii, rec, sizeof( *p ) );
    if( p != NULL ) {
        p = VMBlock( ii, rec, p->length + sizeof( p->length ) );
    }
    return( p );
}

unsigned VMShrink()
{
    int                 i;
    int                 j;
    unsigned            kill_time;
    unsigned            kill_i;
    unsigned            kill_j;
    virt_page           *pg;
    imp_image_handle    *ii;

    kill_time = UINT_MAX;
    kill_i = 0;
    kill_j = 0;
    for( ii = ImageList; ii != NULL; ii = ii->next_image ) {
        if( ii->virt != NULL ) {
            for( i = ii->vm_dir_num-1; i >= 0; --i ) {
                if( ii->virt[i] != NULL ) {
                    for( j = DIR_SIZE-1; j >= 0; --j ) {
                        pg = ii->virt[i][j];
                        if( pg != NULL && pg->offset == 0 ) {
                            if( kill_time > pg->block->time_stamp ) {
                                kill_time = pg->block->time_stamp;
                                kill_i = i;
                                kill_j = j;
                            }
                        }
                    }
                }
            }
        }
    }
    if( kill_time == UINT_MAX ) return( 0 );
    return( KillPages( ii, kill_i, kill_j ) );
}

⌨️ 快捷键说明

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