home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DOS/V Power Report 1997 March
/
VPR9703A.ISO
/
VPR_DATA
/
DOGA
/
SOURCES
/
REND.LZH
/
READER
/
VIRTUAL.C
< prev
next >
Wrap
C/C++ Source or Header
|
1995-11-08
|
10KB
|
526 lines
/*
* 仮想記憶処理関数
*
* 1989.12.16
* Copyright T.Kobayashi
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define NDEBUG
#include <assert.h>
#if defined(VIRTUAL) && defined(ONDEMANDMALLOC)
#error "both VIRTUAL and ONDEMANDMALLOC are defined"
#endif
#ifdef VIRTUAL
#define EMSDEBUG
#ifdef EMS
#include <signal.h>
#include "..\ems\ems.h"
#endif
#include "reader.h"
#define PAGE_NOT_ALLOC 1
#define FILE_CANT_OPEN 2
#define FILE_OUT_ERROR 3
#define ID_ERROR 4
#define BUS_ERROR 5
#define ALLOC_DATA_ID 12345
/*#define PAGE_UNIT (2*1024)*/
#define PAGE_UNIT (16384)
#define segseek( seg ) fseek( virfp, (long)((seg)-1) * (long)PAGE_UNIT, 0 )
#define NO_USE -1
#define PAGE_SIZE ( sizeof( PAGE ) + PAGE_UNIT + 2 * sizeof( MMA ) )
/* メモリ管理領域 */
typedef struct {
short id ;
long size ;
}
MMA ;
/* ページ管理構造体 */
typedef struct _PAGE {
char *membuf; /* メインメモリ上の位置 */
short access ; /* アクセス頻度 */
short lock ; /* ページロック */
unsigned short segment ; /* セグメント番号 */
}
PAGE ;
static PAGE *page ; /* ページ管理領域 */
static int pages ; /* ページ数 */
static FILE *virfp ; /* 仮想記憶ファイルポインタ */
static Pointer nextbuf ; /* 次のアドレス */
static unsigned int lastseg ; /* 最新のアクセスセグメント */
static PAGE *lastpage ; /* 最新のアクセスページ */
/* By Taka2 */
#ifdef EMS
static int emshandle = 0;
static int emsmax;
#endif
/*
proto -s virtual.c > temp
*/
static void newseg( void );
static PAGE *segload( unsigned int );
static void inc_access( PAGE* );
static void virtualerror( int );
#ifdef EMS
void free_ems(void)
{
if (emshandle > 0) {
_ems_DeallocatePages(emshandle);
emshandle = 0;
}
}
void free_ems_exit(void)
{
free_ems();
exit(1);
}
#endif
#ifdef V70
static int flag = FALSE ;
#endif
/* 仮想記憶の初期化 */
void virinit( filename )
char *filename ; /* 仮想記憶ファイル名 */
{
int i ;
#ifndef V70
static int flag = FALSE ;
#endif
char far * pageframe;
assert( virtualmode );
assert( flag == FALSE );
#ifdef EMS
if (toupper(filename[0]) == 'E'
&& toupper(filename[1]) == 'M'
&& toupper(filename[2]) == 'S'
&& filename[3] == '\0') {
if (_ems_check() == FALSE) {
virtualerror( FILE_CANT_OPEN );
}
atexit(free_ems);
signal(SIGABRT, free_ems_exit);
signal(SIGBREAK, free_ems_exit);
signal(SIGINT, free_ems_exit);
pageframe = _ems_GetPageFrame();
emsmax = _ems_GetUnallocatedPage();
emshandle = _ems_AllocatePages(emsmax);
pages = 4;
fprintf( stderr, "EMS領域を %d ページ確保します。\n", emsmax );
page = memalloc( pages * sizeof( PAGE ) );
for( i = 0 ; i < pages ; ++i )
{
page[i].membuf = pageframe + 16384 * i;
page[i].access = NO_USE ;
page[i].lock = 0 ;
}
nextbuf = 0L ;
lastseg = 0xFFFF ;
lastpage = NULL ;
newseg();
} else {
#endif
flag = TRUE ;
virfp = fopen( filename, "w+b" );
if ( virfp == NULL )
virtualerror( FILE_CANT_OPEN );
pages = (int)( memallsize() / (long)PAGE_SIZE ) ;
if ( pages <= 3 )
virtualerror( PAGE_NOT_ALLOC );
fprintf( stderr, "仮想記憶領域を %d ページ確保します。\n", pages );
page = memalloc( pages * sizeof( PAGE ) );
for( i = 0 ; i < pages ; ++i )
{
page[i].membuf = memalloc( PAGE_UNIT );
page[i].access = NO_USE ;
page[i].lock = 0 ;
}
nextbuf = 0L ;
lastseg = 0xFFFF ;
lastpage = NULL ;
newseg();
#ifdef EMS
}
#endif
}
/* 仮想記憶領域の確保 */
Pointer viralloc( size )
int size ;
{
Pointer p ;
unsigned int off ;
MMA *h ;
assert( nextbuf != 0 );
assert( 0 < size && size < PAGE_UNIT );
assert( ( size % 2 ) == 0 );
off = (unsigned int)( nextbuf & 0xFFFF );
if ( off + size + sizeof( MMA ) > PAGE_UNIT )
newseg();
/* メモリ管理領域の設定 */
p = nextbuf ;
nextbuf += size + sizeof( MMA ) ;
h = pointer( p );
h->id = ALLOC_DATA_ID ;
h->size = (long)size ;
return( p + sizeof( MMA ) );
}
/* 配列の確保 */
Pointer viraryalloc( count, size )
int count, size ;
{
int i ;
Pointer ret ;
assert( count > 0 );
ret = viralloc( size );
for( i = 1 ; i < count ; ++i )
{
viralloc( size );
}
return( ret );
}
/* 配列の次の要素を得る */
Pointer virarynext( p, size )
REGISTER Pointer p ;
REGISTER int size ;
{
REGISTER unsigned int off ;
off = (int)( p & 0xFFFFL );
off += size ;
assert( off < PAGE_UNIT );
if ( off + size + sizeof( MMA ) > PAGE_UNIT )
return( ( p & 0xFFFF0000L ) + 0x10000L + (long)sizeof( MMA ) );
else
return( p + size + (long)sizeof( MMA ) );
}
/* 新しいセグメントの確保 */
static void newseg()
{
unsigned int seg ;
#ifdef EMS
if (emshandle > 0) {
seg = (unsigned int)( nextbuf >> 16 ) + 1 ;
if (seg > emsmax) {
virtualerror( FILE_OUT_ERROR );
}
nextbuf = (Pointer)seg << 16 ;
} else {
#endif
seg = (unsigned int)( nextbuf >> 16 ) + 1 ;
segseek( seg );
fwrite( page->membuf, 1, PAGE_UNIT, virfp );
nextbuf = (Pointer)seg << 16 ;
#ifdef EMS
}
#endif
}
/* セグメントのロード */
static PAGE *segload( seg )
REGISTER unsigned int seg ;
{
REGISTER int i, access ;
REGISTER PAGE *p, *ret ;
/* メインメモリ上にあるかどうか */
ret = NULL ;
access = pages ;
p = page ;
for( i = 0 ; i < pages ; ++i )
{
if ( p->access >= 0 && seg == p->segment )
{
ret = p ;
break ;
}
p ++ ;
}
if ( ret != NULL )
{
assert( ret->access < pages );
inc_access( ret );
ret->access = 0 ;
return( ret );
}
/* メインメモリ上にない場合 */
access = 0 ;
p = page ;
for( i = 0 ; i < pages ; ++i )
{
if ( p->access == NO_USE )
{
ret = p ;
break ;
}
#ifdef EMS
}
if (i == pages)
for (p = &(page[0]), i = 0; i < pages; ++i) {
#endif
if ( p->lock == 0 && p->access > access )
{
access = p->access ;
ret = p ;
}
p ++ ;
}
/* メインメモリから追い出す */
if ( i == pages )
{
assert( 0 < access && access <= pages );
#ifdef EMS
if (emshandle > 0) {
#ifdef EMSDEBUG
printf("Map %3d<-%4d\n", ret-page, seg - 1);
#endif
_ems_MapHandlePage(emshandle, ret-page, seg - 1);
inc_access( ret );
} else {
#endif
/* fprintf( stderr, "swap %3d -> %3d\xd", ret->segment, seg );*/
segseek( ret->segment );
fwrite( ret->membuf, 1, PAGE_UNIT, virfp );
inc_access( ret );
segseek( seg );
fread( ret->membuf, 1, PAGE_UNIT, virfp );
#ifdef EMS
}
#endif
}
else /* 使っていないページがある */
{
#ifdef EMS
#ifdef EMSDEBUG
printf("Map %3d<-%4d\n", ret-page, seg - 1);
#endif
if (emshandle > 0) {
_ems_MapHandlePage(emshandle, ret-page, seg - 1);
}
#endif
inc_access( NULL );
}
/* メインメモリにロード */
ret->access = 0 ;
ret->segment = seg ;
#ifdef EMS
if ( emshandle == 0 && ferror( virfp ) )
virtualerror( FILE_OUT_ERROR );
#else
if ( ferror( virfp ) )
virtualerror( FILE_OUT_ERROR );
#endif
return( ret );
}
/* アクセス頻度の更新 */
static void inc_access( p )
REGISTER PAGE *p ;
{
REGISTER PAGE *pp ;
REGISTER int access, i ;
if ( p != NULL )
access = p->access ;
else
access = pages ;
pp = page ;
for( i = 0 ; i < pages ; ++i )
{
if ( pp->access >= 0 && pp->access < access )
pp->access ++ ;
pp ++ ;
}
}
/* マーク */
Pointer virmark()
{
return( nextbuf );
}
/* メモリの解放 */
void virrelease( mark )
Pointer mark ;
{
assert( mark <= nextbuf );
nextbuf = mark ;
}
/* 使用領域サイズを返す */
long virsize()
{
long seg, off ;
seg = nextbuf >> 16 ;
off = nextbuf & 0xFFFF ;
return( ( seg - 1 ) * (long)PAGE_UNIT + off );
}
/* ページをロックする */
int virlock()
{
if ( ! virtualmode )
return( 0 );
#if 0
#ifdef EMSDEBUG
printf("Page lock %d->%d\n", lastpage - page, lastpage->lock+1);
#endif
#endif
lastpage->lock ++ ;
return( lastpage - page );
}
/* ページロックを解除する */
void virunlock( no )
int no ;
{
if ( ! virtualmode )
return ;
#if 0
#ifdef EMSDEBUG
printf("Page unlock %d->%d\n", no, page[no].lock - 1);
#endif
#endif
assert( page[no].lock > 0 );
page[no].lock -- ;
}
/* 実アドレスを得る */
void *virpointer( vp )
REGISTER Pointer vp ;
{
REGISTER unsigned int seg, off ;
if ( ! virtualmode )
return( (void*)vp );
if ( vp == 0 )
return( NULL );
if (vp > ((long)pages<<16)) {
printf("vp = %08lx\n", vp);
return vp;
}
seg = (unsigned int)( vp >> 16 );
off = (unsigned int)( vp & 0xFFFF );
assert( vp < nextbuf );
assert( off < PAGE_UNIT );
if ( lastseg == seg )
return( lastpage->membuf + off );
lastpage = segload( seg );
lastseg = seg ;
return( lastpage->membuf + off );
}
/* 領域のチェック */
int vircheck( top, refer, flag )
Pointer top ;
Pointer refer ;
int flag ;
{
MMA *h ;
if ( ! virtualmode )
return( memcheck( (char*)top, (char*)refer, flag ) );
assert( flag == 0 );
h = pointer( refer );
h -- ;
if ( h->id != ALLOC_DATA_ID )
{
virtualerror( ID_ERROR );
return( FALSE );
}
return( TRUE );
}
#ifdef V70
static exitflag = FALSE ;
#endif
/* エラーメッセージ出力 */
static void virtualerror( n )
int n ;
{
#ifndef V70
static exitflag = FALSE ;
#endif
char *msg ;
switch( n )
{
case PAGE_NOT_ALLOC :
msg = "ページ領域を確保できませんでした。" ;
exitflag = TRUE ;
break ;
case FILE_CANT_OPEN :
msg = "仮想記憶ファイルがオープンできませんでした。" ;
exitflag = TRUE ;
break ;
case FILE_OUT_ERROR :
#ifdef EMS
if (emshandle > 0) {
msg = "EMSのページが足りません。" ;
} else {
msg = "仮想記憶ファイル出力でエラーが発生しました。" ;
}
#else
msg = "仮想記憶ファイル出力でエラーが発生しました。" ;
#endif
perror( "" );
exitflag = TRUE ;
break ;
case ID_ERROR :
msg = "メモリ管理領域が破壊されました。" ;
break ;
case BUS_ERROR :
msg = "不正なアドレスを参照しようとしています。" ;
break ;
}
fprintf( stderr, "\n\7%s\n\n", msg );
if ( exitflag )
exit( 1 );
}
#endif /* VIRTUAL */