
#include	"sysdef.h"

/*	EDPAGR.C	work file paging			*/
/*								*/
/*	01-Oct-84  11:03:13  Brian Nelson			*/
/*								*/
/*	Copyright Notice					*/
/*								*/
/*								*/
/*	C version Copyright (C) 1984 Change Software, Inc.	*/
/*	Copyright (C) 1978 1979 1980 1981 1982 1983 1984 by	*/
/*		      Change Software, Inc.			*/
/*								*/
/*								*/
/*	This software is furnished under a license and may	*/
/*	be  used  and  copied  only in accordance with the	*/
/*	terms of such license and with  the  inclusion  of	*/
/*	the  above copyright notice.  This software or any	*/
/*	other copies thereof may not be provided or other-	*/
/*	wise made available to any other person.  No title	*/
/*	to and ownership of the software is hereby  trans-	*/
/*	ferred.							*/
/*								*/

#include	"scerrd.h"
#include	"tempio.h"

/*	the following things should be evaluated by the C preprocessor	*/
/*	but the DECUS C compiler can't do it				*/
/*									*/
/*	#define	PAGE_SIZE	1024					*/
/*	#define	TEXT_SIZE	512					*/
/*	#define	BUF_COUNT	4					*/
/*	#define	CLUSTER_SIZE	PAGE_SIZE/TEXT_SIZE			*/
/*	#define	TEXT_COUNT	BUF_COUNT*CLUSTER_SIZE			*/



#if	VAXVMS
#define	_MIN_BUF_COUNT	32
#define	_MAX_BUF_COUNT	256
#define	_MAX_PAGE_SIZE	0170000
#define	_CLUSTER_SIZE	4
#else
#define	_MIN_BUF_COUNT	4
#define	_MAX_BUF_COUNT	16
#define	_MAX_PAGE_SIZE	0070000
#define	_CLUSTER_SIZE	2
#endif

#define	then
#define	_TEXT_SIZE	512
#define	_PAGE_SIZE	_TEXT_SIZE*_CLUSTER_SIZE
#define	_MAX_TEXT_COUNT	_MAX_BUF_COUNT*_CLUSTER_SIZE

static	char	*text_pointer[_MAX_TEXT_COUNT] ;
static	char	*buf_pointer[_MAX_BUF_COUNT] ;
static	int	buf_res[_MAX_BUF_COUNT] ;
static	int	buf_mod[_MAX_BUF_COUNT] ;
static	int	access_count[_MAX_BUF_COUNT] ;
static	int	least_access ;
static	int	last_page ;
static	int	total_count ;
static	int	page_size ;
static	int	buf_count ;
static	int	cluster_size ;




/*	The pager will make the assumption that BUF_POOL is contiguous	*/
/*	in memory  since the cleanest  way to handle the fact that the	*/
/*	page size  is greater than the buffer size to return a pointer	*/
/*	to place in the pool where the 512 byte buffer should be.	*/


char		*base_address ;
static	int	all_buf_count ;
static	int	dopageing = 1 ;

int	vir_pagecount = 0 ;
extern	struct	stats	tempstat ;




/*	PAGEINIT()							*/
/*									*/
/*	Called from INITTEMP() to setup the cacheing data structures	*/
/*	ALLBUFFER() is called with min and max arguements in 512 byte	*/
/*	units, and returns the buffer count in 512 byte units.		*/

pageinit()
{
	register int i ;
	extern char *allbuffer() ;

	base_address = allbuffer(&all_buf_count ,
				 _MIN_BUF_COUNT*_CLUSTER_SIZE ,
				 _MAX_BUF_COUNT*_CLUSTER_SIZE ) ;
	if ( (all_buf_count=all_buf_count/_CLUSTER_SIZE) == 0 ) then return(0) ;
	vir_pagecount = all_buf_count * _CLUSTER_SIZE ;
	dopageing = 1 ;
	for ( i=0; i<vir_pagecount; i++ )
		text_pointer[i] = base_address + (i*_TEXT_SIZE) ;
	for ( i=0; i<all_buf_count; i++ ) {
		buf_pointer[i] =  base_address + (i*_PAGE_SIZE) ;
		buf_res[i] = 0 ;
		buf_mod[i] = 0 ;
		access_count[i] = 0 ;
		}
	least_access = 0 ;
	last_page = 0 ;
	total_count = 0 ;
	page_size = _PAGE_SIZE ;
	cluster_size = _CLUSTER_SIZE ;
	buf_count = all_buf_count ;
	
	return(1) ;
}


/*	PAGEOFF()							*/
/*									*/
/*	Disable all cacheing of the work file buckets to effect a fast	*/
/*	IFL of the input file.  This can ONLY be used from IFL() since	*/
/*	it does not flush any cached pages to disk.			*/

pageoff(win)
int win ;
{
	if ( win != 0 ) then return(1) ;
	dopageing = 0 ;
	if ( (page_size = _PAGE_SIZE * all_buf_count) > _MAX_PAGE_SIZE )
	  then page_size = _MAX_PAGE_SIZE ;
	cluster_size = page_size / _TEXT_SIZE ;
	buf_count = 1 ;
	buf_res[0] = 0 ;
	buf_mod[0] = 0 ;
	access_count[0] = 0 ;
}



/*	PAEGON()							*/
/*									*/
/*	Called from IFL() to reset the cacher to work normally		*/

pageon(win)
int win ;
{
	if ( win != 0 ) then return(1) ;
	if ( dopageing == 0 )
	  then	{
		dopageing = 1 ;
		if ( buf_res[0] && buf_mod[0] )
		  then	{
			mapcache() ;
			puttblock(buf_pointer[0],page_size,buf_res[0],win) ;
			unmapcache() ;
			last_page = buf_res[0] + cluster_size - 1 ;
			}
		buf_mod[0] = 0 ;
		buf_res[0] = 0 ;
		access_count[0] = 0 ;
		page_size = _PAGE_SIZE ;
		cluster_size = _CLUSTER_SIZE ;
		buf_count = all_buf_count ;
		}
}		




gettemp(buf,vbn,win)
register char *buf ;
int vbn ,win ;
{
	register int i ;
	extern char *bufcontrol() ;

	if (win != 0) return(gettblock(buf,_TEXT_SIZE,vbn,win)) ;
	mapcache(win) ;
#if	RSX
	blkmov(buf,bufcontrol(vbn,0,win)) ;
#else
	scopy(buf,bufcontrol(vbn,0,win),_TEXT_SIZE) ;
#endif
	unmapcache(win) ;
	return(1) ;
}


puttemp(buf,vbn,win)
register char *buf ;
int vbn,win ;
{
	register int i ;
	extern char *bufcontrol() ;
	if (win != 0) return(puttblock(buf,_TEXT_SIZE,vbn,win)) ;
	mapcache(win) ;
#if	RSX
	blkmov(bufcontrol(vbn,1,win),buf) ;
#else
	scopy(bufcontrol(vbn,1,win),buf,_TEXT_SIZE) ;
#endif
	unmapcache(win) ;
	return(1) ;
}





char *bufcontrol(vbn,direction,win)

int vbn,direction,win ;

{
	register int buf,block,temp ;
	int offset,status ;

	status = sys_normal ;
	vbn-- ;
	offset = vbn % cluster_size ;
	block  = vbn - offset + 1 ;
	for ( buf=0; buf < buf_count && block != buf_res[buf]; buf++ ) ;
	if ( buf >= buf_count )
	  then	{			/* a page fault has occurred	*/
		least_access = 32767 ;
		temp = 0 ;
		for ( buf=0; buf < buf_count; buf++ ) {
			if ( access_count[buf] <= least_access )
			  then	{
				least_access = access_count[buf] ;
				temp = buf ;
				}
			}
		buf = temp ;
		if ( buf_mod[buf] && (temp=buf_res[buf]) )
		  then	{
			if (temp > last_page)
			  then last_page = temp+cluster_size-1 ;
			status=puttblock(buf_pointer[buf],page_size,temp,win) ;
			tempstat.w_faults++ ;
	    		}
		if ( block <= last_page)
		  then	{
			status=gettblock(buf_pointer[buf],page_size,block,win) ;
			tempstat.r_faults++ ;
			}
		buf_res[buf] = block ;
		buf_mod[buf] = 0 ;
		}
	  else	tempstat.hits++ ;

	access_count[buf] = ++total_count ;
	if ( direction ) then buf_mod[buf] = 1 ;
	if ( status != sys_normal )
	  then	tederror("I/O error on the workfile") ;
	return( text_pointer[buf*cluster_size+offset] ) ;
}

