{Begin SubSec Page Mapped Files}
{Title Page Mapped Files}
{Text

{note The PMAP package was written by R. M. Kaplan and L. M. Masinter.}

{Tag PageMapping}

{index *BEGIN* page mapped files}

This facility allows paged access to files.  It manages a set of paging buffers as a least-recently-used queue, with each buffer being a full-page block.  Facilities are provided for allocating and deallocating buffers, locking down pages, mapping a given page of the file into core, and getting the in-core location to which a given word of the file has been mapped.  Any number of files can be mapped in at one time.


Note:  Interlisp-D implements the page-mapping primitives of Interlisp-10 with some notable differences that might require major reworking of programs that rely on these facilities.  The major difference is that an Interlisp-D page contains 256 16-bit words, rather than the 512 36-bit words of Interlisp-10.  A given page number or file address for {fn MAPPAGE} or {fn MAPWORD} will correspond to a very different number of bits from the beginning of the file, and {fn WORDCONTENTS} and {fn SETWORDCONTENTS} move smaller amounts of information.  A second difference is that buffers are completely integrated into the Interlisp-D storage management system so that a page is guaranteed to be locked down as long as the user holds a pointer to it.  The functions {fn LOCKMAP} and {fn UNLOCKMAP} are therefore unnecessary, but for compatibility are defined with dummy definitions.



The following scenario illustrates the use of these facilities:  The user first opens the file (or files) that he wants to access by page-mapping using any of the ordinary file-opening functions.  Then, to examine a particular word in one of the files, the user simply gives the word number and the file's name to the function {fn MAPWORD}, which returns a pointer to the in-core location that that word is mapped to (i.e. the address as an unboxed number).  When he has finished processing, the user simply closes the file (e.g. using {fn CLOSEF}) and the buffers are automatically unmapped.






The basic functions are:



{FnDef {FnName ADDMAPBUFFER} {FnArgs TEMP ERRORFLG}
{Text
Initially, a single buffer is allocated, so that page-mapping may be done without further initialization.  More buffers can be allocated by {fn ADDMAPBUFFER}, which may help to avoid thrashing. {fn ADDMAPBUFFER} attempts to allocate a single new buffer, and returns non-{lisp NIL} if successful.  If there is not enough space to allocate a new buffer, then if {arg ERRORFLG} is {lisp NIL}, {fn ADDMAPBUFFER} simply returns {lisp NIL}.  Otherwise, {fn ADDMAPBUFFER} causes an error {lisp UNABLE TO ALLOCATE PMAP BUFFER}{index UNABLE TO ALLOCATE PMAP BUFFER Error}.

If {arg TEMP}={lisp T}, the buffers are allocated on a "temporary" basis:  allocation takes place via a {fn RESETSAVE} whose restoration form will de-allocate the buffers.
}}



{FnDef {FnName MAPBUFFERCOUNT} {FnArgs ONLYUNLOCKED}
{Text
Returns the number of buffers currently allocated.  If {arg ONLYUNLOCKED}={lisp T}, counts only unlocked buffers; otherwise, counts all buffers.  Thus, to insure that at least 3 (unlocked) buffers are allocated, the user could perform {lisp (while (LESSP (MAPBUFFERCOUNT T) 3) do (ADDMAPBUFFER NIL T))}.
}}



{FnDef {FnName MAPPAGE} {FnArgs PAGE# FILE {anonarg}}
{Text
The primitive function for mapping in pages from {arg FILE} into the queue of buffers.  {arg PAGE#} is a page number in {arg FILE}.  The value of {fn MAPPAGE} is a pointer to the word in memory at which the first word of the page is located, which will always be at a page-boundary.

If {arg FILE} is {lisp NIL}, the value of {var DEFAULTMAPFILE}{index DEFAULTMAPFILE Var} is used.

{fn MAPPAGE} searches the buffers to see if the given page for the  given file has already been mapped in.  If so, it returns the core address to which it was previously mapped.  Otherwise, it replaces the previous contents of the least-recently-used buffer with the specified file page.  It is important to note that the contents of a given core buffer are not guaranteed across calls to {fn MAPPAGE}, unless the page has been locked down via {fn LOCKMAP}.  {fn MAPPAGE} compiles open, and in the case where the desired page is already in the buffer it is quite efficient.

{fn MAPPAGE} will allocate an additional buffer if no unlocked buffers are available (and the desired page is not already mapped in).
 

In Interlisp-10, {arg FILE} may also be a fork handle (i.e. a value of {fn SUBSYS}, {PageRef Fn SUBSYS}), in which case the specified page from that fork will be mapped in.
}}


{Begin Note}
Date: 18 Dec 1978 4:02 pm (Monday)
From: Masinter

I also left out of the documentation for the new PMAP stuff that if you mappage
with "file"=777777Q and "page"=-1 that you will get a blank page. If you use the
same "file" later (i.e. the EQ large integer) then you will get the same page.
{End Note}



{FnDef {FnName MAPWORD} {FnArgs FILEADR FILE}
{Text
Like {fn MAPPAGE}, except that it allows the specification of a word-address in {arg FILE}, not just a page number.  {fn MAPWORD} determines what page that address is on, maps that page into a buffer (using {fn MAPPAGE}), and returns a pointer into the middle of the buffer where the indicated word appears.  The rest of the words on the same file page appear at the appropriate word offsets from the value returned by {fn MAPWORD}.
}}



{FnDef {FnName WORDOFFSET} {FnArgs PTR N}
{Text
If {arg PTR} is a pointer into a buffer as returned by {fn MAPPAGE} or {fn MAPWORD}, {fn WORDOFFSET} returns a pointer to the {arg N}th following word.  {fn WORDOFFSET} compiles open.
}}



{FnDef {FnName WORDCONTENTS} {FnArgs PTR}
{Text
Returns the contents of the word at {arg PTR} as an integer.
For example, {lisp (WORDCONTENTS (MAPWORD 10 {arg FILE}))} will return the value stored in word 10 of a (binary) file.  {fn WORDCONTENTS} compiles open.
}}



{FnDef {FnName SETWORDCONTENTS} {FnArgs PTR N}
{Text
Sets the contents of the word pointed to by {arg PTR} to be the number {arg N}. Interpreted, {fn SETWORDCONTENTS} checks that {arg PTR} actually is a pointer as returned by {fn MAPPAGE} or {fn MAPWORD}.
{fn SETWORDCONTENTS} compiles open with no error checks.
}}



{FnDef {FnName CLEARMAP} {FnArgs FILE PAGES RELEASE}
{Text
{arg FILE} specifies a file or fork as for {fn MAPPAGE}, or it is {lisp T}.
{arg PAGES} is a single page number or a list of page numbers.
{fn CLEARMAP} unmaps any of those pages that are currently mapped in, making those buffers available for other mappings.  {arg FILE}={lisp T} means all files; {arg PAGES}={lisp NIL} means all pages.  Thus {lisp (CLEARMAP T)} will completely clear the buffers.

Note that {fn CLEARMAP} unmaps any pages, whether or not they are currently locked, i.e., {fn CLEARMAP} takes precedence over {fn LOCKMAP}.


If {arg RELEASE}={lisp T}, then not only will the buffers containing the specified pages be unmapped, but the buffers themselves will be released, i.e. returned to the Interlisp storage manager.
}}



{FnDef {FnName LOCKMAP} {FnArgs PTR}
{Text
For those situations in which a program needs prolonged access to a particular file page, {fn LOCKMAP} can be used to prevent {fn MAPPAGE} from shifting or unmapping the contents of the given core page.  {arg PTR} is a pointer into a mapped page (i.e. a value of {fn MAPWORD} or {fn MAPPAGE}).  {fn LOCKMAP} locks the indicated page in core until a corresponding {fn UNLOCKMAP} has been performed.  If a page has been locked twice, it must be unlocked twice before it is available for reuse.  Returns {arg PTR}.
}}



{FnDef {FnName UNLOCKMAP} {FnArgs PTR}
{Text
{arg PTR} is a pointer into a mapped page.  {fn UNLOCKMAP} removes the most recent lock for that page.

{note {fn UNLOCKMAP} removes the most recent lock for that page if {arg FLG}={lisp NIL}, and all locks if {arg FLG}={lisp T}.}
}}


{index *END* page mapped files}

}{End SubSec Page Mapped Files}