Subject: tmpfile Virtual Memory Facility (New - #154)
Index:	usr.lib/libvmf 2.11BSD

Description:
	Excerpted from the documentation:

"Since 2.11BSD is not a virtual memory operating system, a user level
"virtual memory" system can be of great utility to programs with
large address space requirements. This library provides a standard set
of routines for managing large virtual memory spaces.  It supports
creation of multiple concurrent virtual spaces, mapping of virtual
pages into real memory, a lock/unlock mechanism, and a capability to
clear specified virtual pages.

The virtual memory scheme supports any number (subject to open file
limitations) of virtual "spaces", each of which is made up of up to 512
segments (pages), each of which is 512 words (16 bit shorts) long.
The 512 ints (1024 chars) of a segment can be used for any purpose.

At any time during the lifetime of a process that uses the virtual 
memory facility, some number of segments will be in real memory, but
typically most will be "swapped out" to a file.  When the calling program 
knows the real memory address of a segment, the segment may be viewed
and accessed as an array of 512 integers or as an array of 1024
characters."

Repeat-By:
	Observation?  These are a set of routines i've had for some time,
	they've proved quite useful, For example an editor written using 
	these routines is able to handle 30k line files quite easily (something
	'vi' gives up on a long time ago).

Fix:
	This package will be required for the new 'ld' (link loader)
	which will handle longer symbol names.  I am releasing this
	now to allow for installation and experimentation time.
	
	'ld' was within about 1kb of not running at all it (more than 56kb 
	of data space) even with the old 8 character limit on symbols - it 
	was obvious something had to be done to allow the new 32 character 
	symbols.  These routines are that "something".
	
	I have a version of 'ld' working with these routines (but still with 
	the 8 character symbol format) - there is (as you would expect) a 
	speed penalty associated with not having the entire symbol table
	resident in memory.  Using 10 'pages' of memory (10kb instead of
	28kb), the speed penalty is between 10 and 14% on kernel linking 
	and less (almost not noticeable) for smaller programs.

	Save this article to a temporary file (/tmp/foo) and cut where 
	indicated.

	Then:
		1) sh /tmp/foo
		2) cd /usr/src/usr.lib/libvmf
		3) make
		4) make install
		5) make clean
		6) patch -p0 < /tmp/vmf.patch

	This will install the library (libvmf.a) in /usr/lib, the
	man page in chapter 3 (/usr/man/cat3/vmf.0) and the include
	file (vmf.h) in both /usr/include and /usr/src/include.

	Also, step 6 will modify the necessary Makefiles so that libvmf.a
	will be included in any future rebuilding of the system.

	You may wish to format and print the (more) detailed documentation
	which is included.  This document was written using the 'ms'
	macros and may be formatted with "nroff -ms vmlib.ms".

	Note:  These routines do _not_ handle the crossing between pages.
	       If the items stored in 'virtual space' span page boundaries
	       it is the program's responsibilty to map the next page.  
	       Using data structures which divide evenly into the page
	       size (1024 bytes) makes life easier but is not required.

=========================cut here============================
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	/usr/src/usr.lib/libvmf
#	/usr/include/vmf.h
#	/usr/src/include/vmf.h
#	/tmp/vmf.patch
# This archive created: Thu Oct 21 21:27:25 1993
export PATH; PATH=/bin:/usr/bin:$PATH
if test ! -d '/usr/src/usr.lib/libvmf'
then
	mkdir '/usr/src/usr.lib/libvmf'
fi
cd '/usr/src/usr.lib/libvmf'
if test -f 'makefile'
then
	echo shar: "will not over-write existing file 'makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'makefile'
XOBJECTS = vmf.o
X
Xall:  genlib genlib_p vmf.0
X
XCFLAGS = -O
X
Xall:   genlib genlib_p
X
Xvmf.0:	vmf.3
X	nroff -man vmf.3 > vmf.0
X
Xinstall:
X	install -c -m 644 genlib /usr/lib/libvmf.a
X	ranlib /usr/lib/libvmf.a
X	install -c -m 644 genlib_p /usr/lib/libvmf_p.a
X	ranlib /usr/lib/libvmf_p.a
X	install -c -m 444 vmf.0 /usr/man/cat3/vmf.0
X
Xclean:
X	rm -f ${OBJECTS} profiled/${OBJECTS} genlib genlib_p vmf.0
X
X.c.o:
X	${CC} -p ${CFLAGS} -c $*.c
X	-ld -X -r $*.o
X	mv a.out profiled/$*.o
X	${CC} ${CFLAGS} -c $*.c
X	-ld -X -r $*.o
X	mv a.out $*.o
X
Xgenlib genlib_p: ${OBJECTS}
X	@echo "building profiled genlib"
X	@cd profiled; ar cru ../genlib_p ${OBJECTS}
X	@echo "buiding normal genlib"
X	@ar cru genlib ${OBJECTS}
SHAR_EOF
chmod 644 'makefile'
fi
if test -f 'vmf.c'
then
	echo shar: "will not over-write existing file 'vmf.c'"
else
sed 's/^X//' << \SHAR_EOF > 'vmf.c'
X/*      Program Name:   vmf.c
X *      Author:  S.M. Schultz
X *
X *      -----------   Modification History   ------------
X *      Version Date            Reason For Modification
X *      1.0     1JAN80          1. Initial release.
X *      2.0     31Mar83         2. Cleanup.
X *	2.1	19Oct87		3. Experiment increasing number of segments.
X *	2.2	03Dec90		4. Merged error.c into this because it had
X *				   been reduced to two write() statements.
X *	3.0	08Sep93		5. Polish it up for use in 'ld.c' (2.11BSD).
X *				   Release into the Public Domain.
X *      --------------------------------------------------              
X*/
X
X#include <vmf.h>
X#include <errno.h>
X#include <stdio.h>
X#include <sys/file.h>
X
X/*
X * Choose ONE and only one of the following swap policies
X */
X/* #define LRU                  /* Least Recently Used */
X/* #define PERC 3               /* Percolation */
X#define LRS                     /* Least Recently Swapped */
X
X#ifndef DEBUG
X#define debugseg(s,m)           /* do nothing */
X#else
Xstatic void debugseg();
X#endif
X
X/*
X * This is vfm.c, the file of virtual memory management primitives.
X * Call vminit first to get the in memory segments set up.
X * Then call vmopen for each virtual space to be used.
X * Normal transactions against segments are handled via vmmapseg.
X * At wrapup time, call vmflush if any modified segments are
X * assigned to permanent files.
X */
X
X#define NOSEGNO (-1)            /* can never match a segment number */
X
X	static	struct dlink seghead[1];
X	long	nswaps, nmapsegs;      /* statistics */
X	extern	int	read(), write(), errno;
X	static	int	swap();
X	static	void	promote(), vmerror();
X
X/*
X * vminit --- initialize virtual memory system with 'n' in-memory segments
X */
X
Xint
Xvminit(n)
X	int	n;
X	{
X	register struct vseg *s;
X        static struct vseg *segs;
X
X	segs = (struct vseg *)calloc(n, sizeof (struct vseg));
X	if	(!segs)
X		{
X		errno = ENOMEM;
X		return(-1);
X		}
X        seghead[0].fwd = seghead[0].back = seghead; /* selfpoint */
X
X	for     (s = segs; s < &segs[n] ; s++)
X		{
X		s->s_link.fwd = seghead;
X		s->s_link.back = seghead[0].back;
X		s->s_link.back->fwd = s->s_link.fwd->back = (struct dlink *)s;
X		s->s_segno = NOSEGNO;
X		s->s_vspace = NULL;
X		s->s_lock_count = 0;            /* vmunlocked */
X		s->s_flags = 0;                 /* not DIRTY */
X		}
X	return(0);
X	}
X
X/*
X * vmmapseg --- convert segment number to real memory address
X */
X
Xstruct vseg *
Xvmmapseg(vspace, segno)
X	struct 	vspace *vspace;
X	u_short segno;
X	{
X	register struct vseg *s;
X
X	nmapsegs++;
X
X	if	(segno >= vspace->v_maxsegno || segno < 0)
X		{
X#ifdef DEBUG
X		fprintf(stderr,"vmmapseg vspace0%o segno%d\n", vspace, segno);
X#endif
X		vmerror("vmmapseg: bad segno");
X		}
X
X	/* look for segment in memory */
X	for	(s = (struct vseg *)seghead[0].fwd;
X		 s->s_segno != segno || s->s_vspace != vspace;
X	    	 s = (struct vseg *)s->s_link.fwd)
X		{
X		if	(s == (struct vseg *)seghead)
X			{     /* not in memory */
X			int status;
X
X			for (s = (struct vseg *)s->s_link.back; s->s_lock_count != 0; 
X					s = (struct vseg *)s->s_link.back)
X				{
X				if (s == (struct vseg *)seghead)
X					vmerror("Too many locked segs!");
X				debugseg(s, "back skip");
X				}
X			debugseg(s, "dump on");
X			if	(s->s_flags & S_DIRTY)
X				if	(swap(s, write) != 0)
X					{
X					fprintf(stderr,
X						"write swap, v=%d fd=%d\n",
X						s->s_vspace,s->s_vspace->v_fd);
X					exit(-2);
X					}
X			s->s_vspace = vspace;
X			s->s_segno = segno;
X			s->s_flags &= ~S_DIRTY;
X			status = swap(s, read);
X			if	(status == -2)
X				{
X				fprintf(stderr, "can't read swap file");
X				exit(-2);
X				}
X			else if (status == -1)
X				(void)vmclrseg(s);
X#ifdef LRS                              /* Least Recently Swapped */
X			promote(s);
X#endif
X			break;
X			}
X		debugseg(s, "forward skip");
X		}
X#ifdef PERC
X	{       /* percolate just-referenced segment up list */
X	register struct dlink *neighbor, *target;
X	int count;
X
X	s->fwd->back = s->back;         /* delete */
X	s->back->fwd = s->fwd;
X
X	count = PERC;                   /* upward mobility */
X	for	(target = s; target != seghead && count-- > 0; )
X		target = target->back;
X	neighbor = target->fwd;
X	s->back = target;               /* reinsert */
X	s->fwd = neighbor;
X	target->fwd = neighbor->back = s;
X	}
X#endif
X#ifdef LRU                              /* Least Recently Used */
X	promote(s);
X#endif
X	debugseg(s, "vmmapseg returns");
X	return(s);
X	}
X
X/*
X * swap --- swap a segment in or out
X *      (called only from this file)
X */
X
Xstatic int
Xswap(seg, iofunc)           /* used only from this file */
X	register struct vseg *seg;
X	int (*iofunc)();
X	{
X	off_t file_address;
X	register struct vspace *v;
X
X	v = seg->s_vspace;
X	nswaps++;
X	file_address = seg->s_segno;
X	file_address *= (BYTESPERSEG);
X	file_address += v->v_foffset;
X#ifdef SWAPTRACE
X	printf("fd%d blk%d\tswap %s\n", v->v_fd, file_address,
X		iofunc == read ? "in" : "out");
X#endif
X	if	(lseek(v->v_fd, file_address, L_SET) == -1L)
X		return(-2);
X
X	switch	((*iofunc)(v->v_fd, seg->s_cinfo, BYTESPERSEG)) 
X		{
X		case BYTESPERSEG:
X			return(0);
X		case 0:
X			return(-1);
X		default:
X			return(-2);
X		}
X	}
X
Xvoid
Xvmclrseg(seg)
X	register struct vseg *seg;
X	{
X
X	(void)bzero(seg->s_cinfo, BYTESPERSEG);
X	vmmodify(seg);
X	}
X
X/*
X * vmlock --- vmlock a segment into real memory
X */
X
Xvoid
Xvmlock(seg)
X	register struct vseg *seg;
X	{
X
X	seg->s_lock_count++;
X	if	(seg->s_lock_count < 0)
X		vmerror("vmlock: overflow");
X	}
X
X/*
X * vmunlock --- unlock a segment
X */
X
Xvoid
Xvmunlock(seg)
X	register struct vseg *seg;
X	{
X
X        --seg->s_lock_count;
X	if	(seg->s_lock_count < 0)
X		vmerror("vmlock: underflow");
X	}
X
X/*
X * vmmodify --- declare a segment to have been modified
X */
X
Xvoid
Xvmmodify(seg)
Xregister struct vseg *seg;
X	{
X
X	VMMODIFY(seg);
X	debugseg(seg, "vmmodify");
X	}
X
X/*
X * vmflush --- flush out virtual space buffers
X */
X
Xvoid
Xvmflush()
X	{
X	register struct vseg *s;
X
X	for	(s = (struct vseg *)seghead[0].fwd; s != (struct vseg *)seghead;
X		 s = (struct vseg *)s->s_link.fwd)
X		if	(s->s_flags & S_DIRTY)
X			swap(s, write);
X	}
X
X/*
X * debugseg --- output debugging information about a seg in mem
X */
X#ifdef DEBUG
Xstatic void
Xdebugseg(s, msg)
X	char 	*msg;
X	register struct	vseg *s;
X	{
X	fprintf(stderr, "seg%o vspace%o segno%d flags%o vmlock%d %s\r\n",
X		s, s->s_vspace, s->s_segno, s->s_flags, s->s_lock_count, msg);
X	}
X#endif
X
X/*
X * vmopen --- open a virtual space associated with a file
X */
X
Xint
Xvmopen(vs, filename)
X	register struct vspace *vs;
X	char *filename;
X	{
X	register int	fd;
X	char	junk[32];
X
X	if	(!filename)
X		{
X		strcpy(junk, "/tmp/vmXXXXXX");
X		fd = mkstemp(junk);
X		unlink(junk);
X		}
X	else
X		fd = open(filename, O_RDWR|O_CREAT, 0664);
X
X	if	(fd != -1)
X		{
X		vs->v_fd = fd;
X		vs->v_foffset = 0;
X		vs->v_maxsegno = MAXSEGNO;
X		}
X	return(fd);
X	}
X
X/*
X * vmclose --- closes a virtual space associated with a file
X * invalidates all segments associated with that file
X */
X
Xvoid
Xvmclose(vs)
X	register struct vspace *vs;
X	{
X	register struct vseg *s;
X
X	vmflush();
X	/* invalidate all segments associated with that file */
X	for	(s = (struct vseg *)seghead[0].fwd; s != (struct vseg *)seghead;
X		 s = (struct vseg *)s->s_link.fwd) 
X		{
X		if	(s->s_vspace == vs) 
X			{
X			s->s_segno = NOSEGNO;
X			s->s_vspace = NULL;
X			s->s_lock_count = 0;            /* vmunlocked */
X			s->s_flags &= ~S_DIRTY;
X			}
X		}
X	close(vs->v_fd);
X	}
X
X/*
X * promote --- put a segment at the top of the list
X */
X
Xstatic void
Xpromote(s)
X	register struct vseg *s;
X	{
X
X        s->s_link.fwd->back = s->s_link.back;         /* delete */
X	s->s_link.back->fwd = s->s_link.fwd;
X
X	s->s_link.fwd = seghead[0].fwd;   /* insert at top of totem pole */
X	s->s_link.back = seghead;
X	seghead[0].fwd = s->s_link.fwd->back = (struct dlink *)s;
X	}
X
X/*
X * vmerror --- print error message and commit suicide
X *      Message should always make clear where called from.
X *	Example:	vmerror("In floogle: can't happen!");
X */
X
Xstatic void
Xvmerror(msg)
X	char *msg;
X	{
X	fprintf(stderr, "%s\n", msg);
X	abort();	/* terminate process with core dump */
X	}
SHAR_EOF
chmod 644 'vmf.c'
fi
if test -f 'vmf.3'
then
	echo shar: "will not over-write existing file 'vmf.3'"
else
sed 's/^X//' << \SHAR_EOF > 'vmf.3'
X.\" No copyright (1993) - Steven M. Schultz (sms@wlv.iipo.gtegsc.com)
X.\" @(#)vmf.3	3.0 (2.11BSD) 9/24/93
X.\"
X.TH VMF 3 "September 24, 1993"
X.UC 6
X.SH NAME
Xvminit, vmopen, vmclose, vmmapseg, vmmodify, vmlock, vmunlock, vmclrseg, vmflush, \- disk based virtual memory routines
X.SH SYNOPSIS
X.nf
X.PP
X.ft B
X#include <vmf.h>
X.PP
X.ft B
Xstruct vspace {
X	int     v_fd;           /* file for swapping */
X	off_t   v_foffset;      /* offset for computing file addresses */
X	int     v_maxsegno;     /* number of segments in this space */
X	};
X.PP
X.ft B
Xstruct	vseg {                    /* structure of a segment in memory */
X	struct	dlink	s_link;		/* for linking into lru list */
X	int	s_segno;        	/* segment number */
X	struct	vspace	*s_vspace;      /* which virtual space */
X	int	s_lock_count;
X	int     s_flags;
X	union
X		{
X		int	_winfo[WORDSPERSEG];	/* the actual segment */
X		char	_cinfo[BYTESPERSEG];
X		} v_un;
X	};
X#define	s_winfo	v_un._winfo
X#define	s_cinfo	v_un._cinfo
X.PP
X.ft B
Xint	vminit(nseg);
X	int nseg;
X.PP
X.ft B
Xint	vmopen(space, filename);
X	struct vspace *space;
X	char	*filename;
X.PP
X.ft B
Xstruct	vseg	*vmmapseg(space, segno);
X	struct	vspace	*space;
X	int	segno;
X.PP
X.ft B
Xvoid	vmlock(seg);
X	struct	vseg *seg;
X.PP
X.ft B
Xvoid	vmunlock(seg);
X	struct	vseg *seg;
X.PP
X.ft B
Xvoid	vmclrseg(seg);
X	struct	vseg *seg;
X.PP
X.ft B
Xvoid	vmmodify(seg);
X.PP
X.ft B
Xvoid	vmflush();
X.PP
X.ft B
Xvoid	vmclose(space);
X	struct	vspace *space;
X.fi
X.bp
X.SH DESCRIPTION
XThis library provides a standard set
Xof routines for managing large virtual memory spaces.  It supports
Xcreation of multiple concurrent virtual spaces, mapping of virtual
Xpages into real memory, a lock/unlock mechanism, and a capability to
Xclear specified virtual pages.
X.PP
X.IR vminit\ -
XThis routine initializes the virtual memory system by setting up the
Xpool of in-memory segment buffers.  The argument to this function is
Xthe number of memory segments to allocate (typically 4 to 8 but can be 
Xhigher as long as memory can be malloc'd).
XIt must be called before any
Xother "libvmf" routine is called.
X.PP
X.IR vmopen\ -
XFor each virtual space that a program uses, the program must 
Xallocate an instance of the space structure ('struct vspace').  
XThis routine is used to initialize
Xa virtual space structure using the specified address of a
Xspace structure and the name of the file that will serve as 
Xswap file for the space.  If the second argument is \fBNULL\fP
Xan invisible temporary file is used rather than a named (permanent)
Xfile.
X.PP
X.IR vmclose\ -
XThis routine is used to close the UNIX file descriptor associated
Xwith the swap file for a virtual space.  Any modified in-memory segments
Xbelonging to the specified address space are flushed to the paging file.
X.PP
X.IR vmmapseg\ -
XThis routine is the primary interface to the virtual memory mechanism.
XIt is executed with a specified virtual space address and a segment
Xnumber (between 0 and 511), and returns a pointer to an in-memory
Xpage containing the specified segment.
X.PP
X.IR vmmodify\ -
XWhenever a program modifies the data of a segment, it is the program's
Xresponsibility to inform the virtual memory system of the modification.
XThis function is also available as a macro
X(\fBVMMODIFY\fP) for use in-line.
X.PP
X.IR vmlock\ -
XThis routine increments the lock count of the specified segment buffer.
XA buffer with a nonzero lock count is
X.I locked
Xand cannot be swapped out.
X.PP
X.IR vmunlock\ -
XThis routine decrements the lock count of the specified buffer.  It is
Xa serious error to decrement the count below zero (lock underflow).
X.PP
X.IR vmclrseg\ -
XThis routine clears the user data area (page) of the specified segment buffer.
X.IR vmflush\ -
XThis routine simply swaps out all segments that are marked as
Xmodified.
X.SH BUGS
XNot as transparent (or as fast) as a larger hardware address space.
X.PP
XThere is no automatic segment crossing capability, the application must
Xcheck if a
X.I virtual address
Xcrosses page/segment boundaries and perform a
X.I vmmapseg
Xcall.
X.SH SEE ALSO
XThere is a nroff document (using the \-ms macros) in the \fIlibvmf\fP source 
Xdirectory which goes into more details about the \fBvm\fP functions.
SHAR_EOF
chmod 644 'vmf.3'
fi
if test -f 'vmlib.ms'
then
	echo shar: "will not over-write existing file 'vmlib.ms'"
else
sed 's/^X//' << \SHAR_EOF > 'vmlib.ms'
X.NH 1
XVMF -- Virtual Memory Facility
X.NH 2
XIntroduction
X.PP
XSince 2.11BSD is not a virtual memory operating system, a user level
X"virtual memory" system can be of great utility to programs with
Xlarge address space requirements. This library provides a standard set
Xof routines for managing large virtual memory spaces.  It supports
Xcreation of multiple concurrent virtual spaces, mapping of virtual
Xpages into real memory, a lock/unlock mechanism, and a capability to
Xclear specified virtual pages.
X.NH 3
XConcepts
X.PP
XThe virtual memory scheme supports any number (subject to open file
Xlimitations) of virtual
X.I spaces,
Xeach of which is made up of up to 512
X.I segments
X(pages), each of which is 512 words (16 bit shorts) long.
XThe 512 ints (1024 chars) of a segment can be used for any purpose.
X.PP
XEach space may be temporary or permanent, in the sense that it is or
Xis not forgotten when the program ends.  Between program invocations,
Xeach permanent space resides in a named file.  The most common (by
Xfar) type is temporary using a file which is unlinked immediately
Xafter opening the virtual address space.
X.PP
XAt any time during the lifetime of a process that uses the virtual 
Xmemory facility, some number of segments will be in real memory, but
Xtypically most will be "swapped out" to a file.
XWhen the calling program knows
Xthe real memory address of a segment, the segment may be viewed
Xand accessed as an array of 512 integers or as an array of 1024
Xcharacters.
X.NH 3
XData Structures
X.PP
XTwo structures are associated with the virtual memory scheme: the
Xspace structure and the segment buffer structure.
X.IP Space\ Structure 4
X.sp
XOne instance of the space structure must be allocated by the user for
Xeach space to be used.  Spaces are identified by the address of their
Xspace structures.  Included in the structure is the UNIX file descriptor
Xof the "swap" file to be used for the space, the offset (in bytes)
Xinto the file at which the room allocated for the virtual space begins
X(currently this is always zero and is reserved for future use),
Xand the number of segments in the space (currently always 512).  The
Xuser must never be concerned with any element of the space structure.
X.IP Segment\ Buffer\ Structure 4
X.sp
XThe virtual memory system includes a pool of buffers for holding
Xsegments while they reside in real memory.
X.sp
XThe segment buffer structure (see 'struct seg' definition below)
Xincludes: a double link, the segment number (in range [0, 511]),
Xthe address of the virtual space structure instance for the virtual
Xspace of which the segment is a member, a lock count, a "modified"
Xflag, and an array of 512 shorts (1024 bytes) for the segment itself.  This
Xarray represents the virtual page which is accessed directly by
Xthe user.
X.NH 2
XDefined Constants and Global Variables
X.PP
XThe following defined symbolic constants are specified as either
Xcalling parameters or returned values of the routines in the "dtlib"
Xfacility.
X.IP MAXSEGNO 18
XSpecifies the maximum number of segments (pages) in a virtual space.
X.IP WORDSPERSEG 18
XSpecifies the number of words in a segment.
X.IP BYTESPERSEG 18
XSpecifies the number of bytes in a segment.  This is always a power of 2.
X.IP LOG2BPS 18
XThe base 2 logarithm of BYTESPERSEG.
X.PP
XThere are several global variables defined by the "vmlib" facility that an
Xapplications programmer may examine. 
X.IP nswaps 18
XThis is a 32 bit value which gives the number of pages swapped to or from
Xthe paging file.
X.IP nmapsegs 18
XThis 32 bit value holds the number of calls made to map a segment into
Xmemory via \fIvmmapseg\fP.
X.PP
XThe following
Xdefined "C" Language structures are specified as calling parameters
Xand/or returned values of the routines in the "vmlib" facility.
X.PP
X.nf
Xstruct vspace {
X	int     v_fd;           /* file for swapping */
X	off_t   v_foffset;      /* offset for computing file addresses */
X	int     v_maxsegno;     /* number of segments in this space */
X	};
X
Xstruct dlink {                  /* general double link structure */
X	struct dlink *fwd;      /* forward link */
X	struct dlink *back;     /* back link */
X	};
X
Xstruct	vseg {                    /* structure of a segment in memory */
X	struct	dlink	s_link;		/* for linking into lru list */
X	int	s_segno;        	/* segment number */
X	struct	vspace	*s_vspace;      /* which virtual space */
X	int	s_lock_count;
X	int     s_flags;
X	union
X		{
X		int	_winfo[WORDSPERSEG];	/* the actual segment */
X		char	_cinfo[BYTESPERSEG];
X		} v_un;
X	};
X
X#define	s_winfo	v_un._winfo
X#define	s_cinfo	v_un._cinfo
X.fi
X.NH 2
XRoutine Synopsis
X.PP
XBelow are listed the names of each function
Xin the "vmlib" facility along with a brief synopsis
Xof what each routine does.
X.IP vminit 14
XThis routine initializes the virtual memory system by setting up the
Xpool of in-memory segment buffers.  The argument to this function is
Xthe number (typically 4 to 8 but can be higher as long as memory
Xcan be malloc'd).
XIt must be called before any
Xother "vmlib" facility routine is called.
X.IP vmopen 14
XFor each virtual space that a program uses, the program must 
Xallocate an instance of the space structure (see definition 
Xof 'struct vspace' above).  This routine is used to initialize
Xa virtual space structure using the specified address of a
Xspace structure and the name of the file that will serve as 
Xswap file for the space.  If the second argument is \fBNULL\fP
Xan invisible temporary file is used rather than a named (permanent)
Xfile.
X.IP vmclose 14
XThis routine is used to close the UNIX file descriptor associated
Xwith the swap file for a virtual space.  Any modified in-memory segments
Xbelonging to the specified address space are flushed to the paging file.
X.IP vmmapseg 14
XThis routine is the primary interface to the virtual memory mechanism.
XIt is executed with a specified virtual space address and a segment
Xnumber ( in range [0, 511]), and returns a pointer to an in-memory
Xpage containing the specified segment.
X.IP vmmodify 14
XWhenever a program modifies the data of a segment, it is the program's
Xresponsibility to inform the virtual memory system of the modification.
XThis routine flags the specified segment as modified and should be
Xexecuted before any future execution of 'vmmapseg' that could overlay
Xthe modified buffer.  This function is also available as a macro
X(\fBVMMODIFY\fP) for use in-line.  The macro form is actually preferred
Xsince only a single bit is being set in a word.
X.IP vmlock 14
XThis routine increments the lock count of the specified segment buffer.
XA buffer with a nonzero lock count is
X.I locked
Xand cannot be overlayed.  The utility of this feature to the user is
Xthat a locked segment buffer will stay at the same real memory address
Xuntil unlocked, hence real memory pointers into or to it can remain
Xvalid.  Overuse of this feature will result in not being able to page
Xany new segments into memory from the paging file.
X.IP vmunlock 14
XThis routine decrements the lock count of the specified buffer.  It is
Xa serious error to decrement the count below zero (lock underflow).
X.IP vmclrseg 14
XThis routine clears the user data area (page) of the specified segment buffer.
X.IP vmflush 14
XThis routine simply swaps out all segments that are marked as
X"modified".  It may be called at any time and is always called when
X\fIvmclose\fP is called.
X.bp
X.NH 2
XDetailed Description of Virtual Memory Functions
X.NH 3
Xvminit -- Initialize Virtual Memory Interface
X.NH 4
X.PP
XThe "vminit" routine initializes the virtual memory system by setting up the
Xpool of in-memory segment buffers.  It must be called before any
Xother "vmlib" facility routine is called.
X.NH 4
XCALLING SEQUENCE
X.PP
X.in +8
X.nf
Xstatus = vminit(nseg)
X
Xint nseg;
Xint status;
X.fi
X.in -8
X.IP status
XThe return value will be \-1 and \fIerrno\fP will be set to ENOMEM
Xif memory for
Xthe specified number of segments can not be allocated.
X.IP nseg
XThis is the number of in-memory segments to allocate.  These are shared
Xbetween all virtual spaces opened.  Each segment is 1kb plus overhead,
Xso the number of segments should be chosen with care (if all data could
Xbe held in memory we wouldn't need a virtual memory system after all).
XTypical number of segments is between 4 and 8 although some applications
Xsuch as \fBld\fP(1) use 12 or more.
X.NH 3
Xvmopen -- Open a Virtual Space
X.NH 4
X.PP
XFor each virtual space that a program uses, the program must 
Xallocate an instance of the space structure (see definition 
Xof 'struct vspace' above).  The "vmopen" routine is used to initialize
Xa virtual space structure using the specified address of a
Xspace structure and the name of the file that will serve as 
Xswap file for the space.  If the filename is NULL then an invisible
Xtemporary file created in /tmp will be used and the address space
Xwill be vanish when the program exits or calls \fIvmclose\fP.
X.NH 4
XCALLING SEQUENCE
X.PP
X.in +8
X.nf
Xstatus = vmopen(vsptr,filename)
X
Xstruct vspace   *vsptr;
Xchar *filename;
Xint status;
X.fi
X.in -8
X.IP status
XIndicates success if 0, an error if \-1.  An error is caused by failure
Xto create (or open for update) the specified file.  The global \fBerrno\fP
Xwill be set if \-1 is returned by \fIvmopen\fP.
X.NH 3
Xvmclose -- Close a Virtual Space
X.NH 4
X.PP
XClose the UNIX file descriptor associated with the swap 
Xfile for a virtual space.  Modified segments belonging to the specified
Xvirtual space are flushed.
X.NH 4
XCALLING SEQUENCE
X.PP
X.in +8
X.nf
Xvoid vmclose(vsptr)
X
Xstruct vspace   *vsptr;
X.fi
X.in -8
X.IP vsptr
XThe address of the virtual space structure to be closed.  No status is
Xreturned.
X.NH 3
Xvmmapseg -- Map a Virtual Segment into Real Memory
X.NH 4
X.PP
XThe "vmmapseg" routine is the primary interface to the virtual memory mechanism.
XIt is executed with a specified virtual space address and a segment
Xnumber ( in range [0, 511]), and returns the real memory address
Xof a buffer guaranteed to contain the segment requested.  The address 
Xreturned is that of the 'struct vseg' not that of the data portion.  It
Xis up to the program to refer to the 's_cinfo' or 's_winfo' member 
Xto refer to the byte or word oriented data respectively.
X.NH 4
XCALLING SEQUENCE
X.PP
X.in +8
X.nf
Xsegptr = vmmapseg(vsptr,segno)
X
Xstruct vspace *vsptr;
Xint segno;
Xstruct vseg *segptr;
X.fi
X.in -8
X.NH 4
X.IP vsptr
XSpecifies the address of a virtual space structure allocated by
Xthe calling program.  A previous vmopen call using this structure
Xmust have been performed before calling \fIvmmapseg\fP.
X.IP segno
XSpecifies the segment i.e., virtual page, number to be mapped into
Xreal physical memory.  The value must be in the range [0 to MAXSEGNO-1].
XThere are two macros (defined in \fIvmf.h\fP) which are useful in
Xcalculating segment numbers: \fBVSEG\fP and \fBVOFF\fP.
X.IP segptr
XThe address of a virtual seg structure which contains the virtual
Xspace segment associated with segno.  The data is referred to with
Xthe 's_cinfo' or 's_winfo' structure members:  segptr->s_cinfo
Xor segptr->s_winfo respectively.
X.PP
XCurrently this routine aborts the program on an error condition.
X.NH 3
Xvmmodify -- Mark a Segment as Modified
X.NH 4
X.PP
XWhenever the user program modifies any segment, it is the program's
Xresponsibility to inform the virtual memory system of the modification.
XThe "vmmodify" routine flags the specified segment as modified and should be
Xexecuted before any future execution of 'vmmapseg' that could reuse
Xthe modified buffer.  Note that a locked segment buffer cannot be reused,
Xuntil it is unlocked.  A macro form of this routine exists, \fBVMMODIFY\fP
Xmay be used to mark a segment as modified.
X.NH 4
XCALLING SEQUENCE
X.PP
X.in +8
X.nf
Xvoid vmmodify(segptr)
X
Xstruct vseg *segptr;
X.fi
X.in -8
X.IP segptr
XSpecifies the address of a seg structure associated with a current
Xincore virtual memory segment which has been modified.
X.NH 3
Xvmlock -- Lock a Virtual Segment into Real Memory
X.NH 4
X.PP
XIncrement the lock count of the specified segment buffer.
XA buffer with a nonzero lock count is
X.I locked
Xand cannot be reused/swapped-out.  The utility of this feature to the user is
Xthat a locked segment buffer will stay at the same real memory address
Xuntil unlocked, hence real memory pointers into or to it can remain
Xvalid.  Overuse of \fIvmlock\fP will cause errors in \fIvmmapseg\fP
Xwhen no segments are available to satisfy swap in/out requests.
X.NH 4
XCALLING SEQUENCE
X.PP
X.in +8
X.nf
Xvoid vmlock(segptr1)
X
Xstruct vseg      *segptr;
X.fi
X.in -8
X.NH 4
X.IP segptr
XSpecifies the address of a seg structure associated with a current
Xincore virtual memory segment.  No information is returned.
X.NH 3
Xvmunlock -- Unlock a Previously Locked Virtual Memory Segment
X.NH 4
X.PP
XDecrement the lock count of the specified buffer.  It is a serious error
Xto decrement the count below zero, this typically means that the segment
Xwas never locked in the first place.
X.NH 4
XCALLING SEQUENCE
X.PP
X.in +8
X.nf
Xvoid vmunlock(segptr)
X
Xstruct vseg      *segptr;
X.fi
X.in -8
X.NH 4
X.IP segptr1
XSpecifies the address of a seg structure associated with a current
Xincore virtual memory segment.  No information is returned from this
Xroutine.
X.NH 3
Xvmclrseg -- Clear a Virtual Memory Segment to Zeros
X.NH 4
X.PP
XClear the data area of the specified segement buffer.  No information is
Xreturned by this function.
X.NH 4
XCALLING SEQUENCE
X.PP
X.in +8
X.nf
Xvoid vmclrseg(segptr)
X
Xstruct vseg      *segptr
X.fi
X.in -8
X.NH 4
X.IP segptr
XSpecifies the address of a seg structure associated with a current
Xincore virtual memory segment.  The data portion (segptr->s_cinfo)
Xis cleared by a call to \fIbzero\fP(3).
X.NH 3
Xvmflush -- Flush Virtual Memory Cache to Swap File
X.NH 4
X.PP
XSwap out all segments that are marked as
X"modified". It may be called just prior to program termination
Xif there are any permanent spaces that have been modified but 
Xnormally a program will simply call \fIvmclose\fP which takes care
Xof flushing modified pages as part of its normal duties.
X.NH 4
XCALLING SEQUENCE
X.PP
X.in +8
X.nf
Xvoid vmflush()
X.fi
X.in -8
SHAR_EOF
chmod 644 'vmlib.ms'
fi
if test ! -d 'profiled'
then
	mkdir 'profiled'
fi
cd 'profiled'
chmod 751 .
cd ..
chmod 755 .
cd ..
if test -f '/usr/include/vmf.h'
then
	echo shar: "will not over-write existing file '/usr/include/vmf.h'"
else
sed 's/^X//' << \SHAR_EOF > '/usr/include/vmf.h'
X/*      Program Name:   vmf.h
X *      Author:  S.M. Schultz
X *
X *      -----------   Modification History   ------------
X *      Version Date            Reason For Modification
X *      1.0     01Jan80         1. Initial release.
X *      2.0     31Mar83         2. Cleanup.
X *	3.0	08Sep93		3. Change v_foffset to off_t instead of int.
X *	3.1	21Oct93		4. Create union member of structure to 
X *				   make 'int' or 'char' access to data easy.
X *				   Define segment+offset and modified macros.
X *				   Place into the public domain.
X *      --------------------------------------------------              
X*/
X
X#include <sys/types.h>
X
X#define MAXSEGNO	512	/* max number of segments in a space */
X#define BYTESPERSEG     1024	/* must be power of two! */
X#define	LOG2BPS		10	/* log2(BYTESPERSEG) */
X#define WORDSPERSEG     (BYTESPERSEG/sizeof (int))
X
Xstruct vspace {
X	int     v_fd;           /* file for swapping */
X	off_t   v_foffset;      /* offset for computing file addresses */
X	int     v_maxsegno;     /* number of segments in this space */
X	};
X
Xstruct dlink {                  /* general double link structure */
X	struct dlink *fwd;      /* forward link */
X	struct dlink *back;     /* back link */
X	};
X
Xstruct	vseg {                    /* structure of a segment in memory */
X	struct	dlink	s_link;		/* for linking into lru list */
X	int	s_segno;        	/* segment number */
X	struct	vspace	*s_vspace;      /* which virtual space */
X	int	s_lock_count;
X	int     s_flags;
X	union
X		{
X		int	_winfo[WORDSPERSEG];	/* the actual segment */
X		char	_cinfo[BYTESPERSEG];
X		} v_un;
X	};
X
X#define	s_winfo	v_un._winfo
X#define	s_cinfo	v_un._cinfo
X
X/* masks for s_flags */
X#define S_DIRTY 01              	/* segment has been modified */
X
X	long	nswaps;         	/* number of swaps */
X	long	nmapsegs;       	/* number of mapseg calls */
X
X	int	vminit(), vmopen();
X	struct	vseg	*vmmapseg();
X	void	vmlock(), vmunlock(), vmclrseg(), vmmodify();
X	void	vmflush(), vmclose();
X
Xtypedef	long	VADDR;
X#define	VMMODIFY(seg) (seg->s_flags |= S_DIRTY)
X#define	VSEG(va) ((short)(va >> LOG2BPS))
X#define	VOFF(va) ((u_short)va % BYTESPERSEG)
SHAR_EOF
chmod 644 '/usr/include/vmf.h'
fi
if test -f '/usr/src/include/vmf.h'
then
	echo shar: "will not over-write existing file '/usr/src/include/vmf.h'"
else
sed 's/^X//' << \SHAR_EOF > '/usr/src/include/vmf.h'
X/*      Program Name:   vmf.h
X *      Author:  S.M. Schultz
X *
X *      -----------   Modification History   ------------
X *      Version Date            Reason For Modification
X *      1.0     01Jan80         1. Initial release.
X *      2.0     31Mar83         2. Cleanup.
X *	3.0	08Sep93		3. Change v_foffset to off_t instead of int.
X *	3.1	21Oct93		4. Create union member of structure to 
X *				   make 'int' or 'char' access to data easy.
X *				   Define segment+offset and modified macros.
X *				   Place into the public domain.
X *      --------------------------------------------------              
X*/
X
X#include <sys/types.h>
X
X#define MAXSEGNO	512	/* max number of segments in a space */
X#define BYTESPERSEG     1024	/* must be power of two! */
X#define	LOG2BPS		10	/* log2(BYTESPERSEG) */
X#define WORDSPERSEG     (BYTESPERSEG/sizeof (int))
X
Xstruct vspace {
X	int     v_fd;           /* file for swapping */
X	off_t   v_foffset;      /* offset for computing file addresses */
X	int     v_maxsegno;     /* number of segments in this space */
X	};
X
Xstruct dlink {                  /* general double link structure */
X	struct dlink *fwd;      /* forward link */
X	struct dlink *back;     /* back link */
X	};
X
Xstruct	vseg {                    /* structure of a segment in memory */
X	struct	dlink	s_link;		/* for linking into lru list */
X	int	s_segno;        	/* segment number */
X	struct	vspace	*s_vspace;      /* which virtual space */
X	int	s_lock_count;
X	int     s_flags;
X	union
X		{
X		int	_winfo[WORDSPERSEG];	/* the actual segment */
X		char	_cinfo[BYTESPERSEG];
X		} v_un;
X	};
X
X#define	s_winfo	v_un._winfo
X#define	s_cinfo	v_un._cinfo
X
X/* masks for s_flags */
X#define S_DIRTY 01              	/* segment has been modified */
X
X	long	nswaps;         	/* number of swaps */
X	long	nmapsegs;       	/* number of mapseg calls */
X
X	int	vminit(), vmopen();
X	struct	vseg	*vmmapseg();
X	void	vmlock(), vmunlock(), vmclrseg(), vmmodify();
X	void	vmflush(), vmclose();
X
Xtypedef	long	VADDR;
X#define	VMMODIFY(seg) (seg->s_flags |= S_DIRTY)
X#define	VSEG(va) ((short)(va >> LOG2BPS))
X#define	VOFF(va) ((u_short)va % BYTESPERSEG)
SHAR_EOF
chmod 644 '/usr/src/include/vmf.h'
fi
if test -f '/tmp/vmf.patch'
then
	echo shar: "will not over-write existing file '/tmp/vmf.patch'"
else
sed 's/^X//' << \SHAR_EOF > '/tmp/vmf.patch'
X*** /usr/src/usr.lib/Makefile.old	Mon Jan 18 09:37:45 1993
X--- /usr/src/usr.lib/Makefile	Thu Oct 21 20:47:49 1993
X***************
X*** 3,9 ****
X  # All rights reserved.  The Berkeley software License Agreement
X  # specifies the terms and conditions for redistribution.
X  #
X! #	@(#)Makefile	5.10 (Berkeley) 6/7/86
X  #
X  DESTDIR=
X  CFLAGS=	-O
X--- 3,9 ----
X  # All rights reserved.  The Berkeley software License Agreement
X  # specifies the terms and conditions for redistribution.
X  #
X! #	@(#)Makefile	5.11 (2.11BSD GTE) 10/21/93
X  #
X  DESTDIR=
X  CFLAGS=	-O
X***************
X*** 14,28 ****
X  # master tags file (/usr/lib/tags); the Fortran libraries should
X  # be on this list, but we don't control them....
X  #
X! TAGSDIR=libcurses libdbm libln libm libmp libpc libtermlib libutil
X  
X  # Programs that live in subdirectories, and have makefiles of their own.
X  #
X! # 2.10BSD XXX - Libpc isn't important till someone - if ever - ports
X  # the 4.3BSD version of ucb/pascal.
X  #
X  SUBDIR=	learn lib2648 libF77 libI77 libU77 libcurses libdbm libln \
X! 	libom libmp libplot libtermlib liby lpr me sendmail libutil
X  
X  # Shell scripts that need only be installed and are never removed.
X  #
X--- 14,28 ----
X  # master tags file (/usr/lib/tags); the Fortran libraries should
X  # be on this list, but we don't control them....
X  #
X! TAGSDIR=libcurses libdbm libln libm libmp libpc libtermlib libutil libvmf
X  
X  # Programs that live in subdirectories, and have makefiles of their own.
X  #
X! # 2.11BSD XXX - Libpc isn't important till someone - if ever - ports
X  # the 4.3BSD version of ucb/pascal.
X  #
X  SUBDIR=	learn lib2648 libF77 libI77 libU77 libcurses libdbm libln \
X! 	libom libmp libplot libtermlib liby lpr me sendmail libutil libvmf
X  
X  # Shell scripts that need only be installed and are never removed.
X  #
SHAR_EOF
chmod 640 '/tmp/vmf.patch'
fi
exit 0
#	End of shell archive
