virtmem.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 674 行 · 第 1/2 页
C
674 行
/****************************************************************************
*
* 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: Virtual memory support implementation.
*
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include "drpriv.h"
/*
* this virtual memory system has been set up in such a way that when
* running under a 32-bit operating system with effective paging, the
* vm read routines can be replaced with a simple pointer dereference,
* and the vm alloc can be replaced with a call to dwralloc
*/
/* the following structures are for virtual memory allocation */
typedef struct {
char *mem;
unsigned_8 sect:4; // the type of section this page is in
unsigned_8 refd:1; // true if page not referenced
unsigned_8 inmem:1; // true if page in memory
} page_entry;
/* the page_entrys are referenced by an array of pointers, something like
PageTab --> 0 1 2 3 4 5 6 ... <-- array elements are pointers
| | | | | | |
v v v v v v v
1 1 1 1 1 1 1 <- array elements are page_entrys
2 2 2 2 2 2 2 these arrays are referred to as "branches",
3 3 3 3 3 3 3 and the individual elements are called "leaves".
in other words, it is effectively a dynamically allocated 2 dimensional array.
All virtual memory locations are split into 4K pages.
a virtual memory address is split into three parts:
offset leaf id branch id
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 12 bits | 4 bits| 16 bits |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
low order word high order word.
the leaf id chooses which element of the branch is the correct seg_table.
Note that the branch id can only reach about 16200 due to only being able
to allocate < 64k hunks of memory.
*/
// this structure is used for picking the high order word off a long
#ifdef __BIG_ENDIAN__
typedef struct wordpick {
unsigned_16 high;
unsigned_16 low;
} wordpick;
#else
typedef struct wordpick {
unsigned_16 low;
unsigned_16 high;
} wordpick;
#endif
// this is used instead of the virt_mem type inside this module, since it is
// desirable to be able to get the high order word without having to do a
// 16-bit shift. MAKE SURE THAT VIRT_MEM IS THE SAME SIZE AS THIS STRUCTURE!
typedef union {
unsigned_32 l;
wordpick w;
} virt_struct;
#define OFFSET_SHIFT 12
#define MAX_NODE_SIZE (1U << OFFSET_SHIFT)
#define MAX_LEAFS 16 // maximum # of leafs per branch
#define SEG_LIMIT 16200 // maximum # of 4K pages.
/* find the node for MEM_ADDR or FILE_ADDR */
#define NODE( stg ) (&PageTab[ stg.w.high ][ stg.w.low >> OFFSET_SHIFT ])
#define OFFSET_MASK (MAX_NODE_SIZE - 1)
#define NODE_OFF( stg ) ( stg.w.low & OFFSET_MASK )
static page_entry **PageTab = NULL;
static unsigned_16 NumBranches = 15;
// start with branch # 1 so an address of zero can be illegal.
static unsigned_16 CurrBranch = 1;
static unsigned_16 NextLeaf = 0; // next leaf # to be allocated.
static unsigned_16 SwapBranch = 1; // next branch # to be swapped.
static unsigned_16 SwapLeaf = 0; // next leaf # to be swapped
static bool DontSwap = TRUE; // TRUE if we can't swap now.
static unsigned_16 PageCount;
extern void DWRVMInit( void )
/***************************/
// Allocate space for the branch pointers.
{
PageTab = DWRALLOC( NumBranches * sizeof( page_entry * ) );
memset( PageTab, 0, NumBranches * sizeof( page_entry * ) );
PageTab[1] = DWRALLOC( sizeof( page_entry ) * MAX_LEAFS );
memset( PageTab[1], 0, sizeof( page_entry ) * MAX_LEAFS );
DontSwap = FALSE;
PageCount = 0;
}
extern void DWRVMReset( void )
/****************************/
// Reset VM state without having to destroy/init
// NOTE: This will ensure that allocations start from the lowest VM
// address again, without actually freeing the memory that we have
// allocated. Any existing memory will be reused.
{
CurrBranch = 1;
NextLeaf = 0;
}
static void GetMoreBranches( void )
/*********************************/
// make a larger array to hold branch pointers in.
{
page_entry **branches;
unsigned alloc_size;
alloc_size = NumBranches * sizeof( page_entry * );
NumBranches = NumBranches * 2; // double the # of pointers.
if( NumBranches > SEG_LIMIT ) {
DWREXCEPT( DREXCEP_OUT_OF_VM );
}
branches = DWRALLOC( alloc_size * 2 );
memcpy( branches, PageTab, alloc_size );
memset( (char *)branches + alloc_size, 0, alloc_size ); // null pointers
DWRFREE( PageTab );
PageTab = branches;
}
static virt_struct GetPage( dr_section sect )
/*******************************************/
{
page_entry *entry;
unsigned alloc_size;
virt_struct vmem;
if( NextLeaf >= MAX_LEAFS ) {
DontSwap = TRUE;
NextLeaf = 0;
CurrBranch++;
if( CurrBranch >= NumBranches ) {
GetMoreBranches();
}
alloc_size = sizeof( page_entry ) * MAX_LEAFS;
entry = DWRALLOC( alloc_size );
PageTab[ CurrBranch ] = entry;
memset( entry, 0, alloc_size ); //set all flags FALSE.
DontSwap = FALSE;
} else {
entry = &PageTab[ CurrBranch ][ NextLeaf ];
}
entry->sect = sect;
vmem.w.high = CurrBranch;
vmem.w.low = NextLeaf << OFFSET_SHIFT;
NextLeaf++;
return( vmem );
}
extern dr_handle DWRVMAlloc( unsigned long size, int sect )
/*********************************************************/
{
virt_struct ret;
ret.l = 0; // assume 0 not a valid vm address
if( size > 0 ) {
ret = GetPage( sect );
while( size > MAX_NODE_SIZE ) {
size -= MAX_NODE_SIZE;
GetPage( sect );
}
}
return( ret.l );
}
extern void DWRVMFree( dr_handle hdl )
/************************************/
{
hdl = hdl;
}
extern int DRSwap( void )
/***********************/
// this uses the second-chance cyclic algorithm for page replacement.
// NOTE: this tends to degenerate into FIFO under very tight memory
// requirements, which is rather bad for the current usage. Any better ideas?
{
unsigned_16 startbranch;
unsigned_16 startleaf;
page_entry *entry;
bool passtwo;
if( DontSwap ) return( FALSE );
passtwo = FALSE;
startbranch = SwapBranch;
startleaf = SwapLeaf;
for( ;; ) {
SwapLeaf++;
if( SwapLeaf >= MAX_LEAFS ) {
SwapLeaf = 0;
SwapBranch++;
if( SwapBranch > CurrBranch ) {
SwapBranch = 1;
}
}
entry = &PageTab[SwapBranch][SwapLeaf];
if( entry != NULL ) {
if( entry->refd ) {
entry->refd = 0;
} else if( entry->inmem ) {
DWRFREE( entry->mem );
PageCount--;
entry->inmem = 0;
return( TRUE );
}
}
if( SwapLeaf == startleaf && SwapBranch == startbranch ) {
if( passtwo ) break; // nothing to swap;
passtwo = TRUE;
}
}
return( FALSE );
}
extern void DWRVMDestroy( void )
/******************************/
/* this frees all virtual memory */
{
unsigned branch;
unsigned leaf;
page_entry *entry;
DontSwap = TRUE;
if( PageTab == NULL ) return;
for( branch = 1; branch < NumBranches; branch++ ) {
entry = PageTab[ branch ];
if( entry != NULL ) {
for( leaf = 0; leaf < MAX_LEAFS; leaf++ ) {
if( entry->inmem ) {
DWRFREE( entry->mem );
}
entry++;
}
DWRFREE( PageTab[branch] );
}
}
DWRFREE( PageTab );
}
static void ReadPage( page_entry * node, virt_struct vm )
/*******************************************************/
/* read a page in from the dwarf file */
{
unsigned long size;
unsigned long base;
unsigned long offset;
dr_section sect;
sect = node->sect;
size = DWRCurrNode->sections[sect].size;
base = DWRCurrNode->sections[sect].base;
offset = (vm.l - base) & ~((unsigned long)OFFSET_MASK);
size -= offset;
if( size > MAX_NODE_SIZE ) {
size = MAX_NODE_SIZE;
}
node->mem = DWRALLOC( size );
node->inmem = TRUE;
++PageCount;
DWRSEEK( DWRCurrNode->file, sect, offset );
DWRREAD( DWRCurrNode->file, sect, node->mem, size );
}
extern void DWRVMSwap( dr_handle base, unsigned_32 size, int *ret )
/*****************************************************************/
// Swap out base for length size
// If memory was freed set *ret
{
volatile virt_struct vm; // cg bug workaround
page_entry *entry;
int ret_val;
vm.l = base;
ret_val = FALSE;
if( size > 0 ) {
for( ;; ) {
entry = NODE( vm );
entry->refd = 0;
if( entry->inmem ) {
--PageCount;
DWRFREE( entry->mem );
entry->inmem = 0;
ret_val = TRUE;
}
if( size <= MAX_NODE_SIZE ) break;
size -= MAX_NODE_SIZE;
vm.l += MAX_NODE_SIZE;
}
}
if( ret_val == TRUE ) {
*ret = ret_val;
}
}
extern int DWRVMSectDone( dr_handle base, unsigned_32 size )
/**********************************************************/
{
int ret;
DWRVMSwap( base, size, &ret );
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?