-- VMMgr>ProjectionImpl.mesa  (last edited by Levin on August 3, 1982 4:05 pm)
-- The routines in this module are only called from within the SpaceImpl monitor.  Thus, the database accessed by this module need not be protected by a local monitor because it is already protected by the SpaceImpl monitor.

DIRECTORY
   CachedRegion USING [Apply, Desc, Insert, State, Outcome],
   CachedSpace USING [Level],
   Projection USING [],
   STLeaf USING [alive, ProjectionState],
   STree USING [Delete, Desc, Get, Insert, Key, PDesc, Update],
   VM USING [PageNumber, PageCount],
   VMMPrograms USING [];

ProjectionImpl: PROGRAM [countVM: VM.PageCount]  -- (not a monitor)
   IMPORTS CachedRegion, STree
   EXPORTS Projection, VMMPrograms =

BEGIN

Bug: ERROR[type: BugType] = CODE;  -- not to be caught by client.
BugType: TYPE = {funnyLevel, funnyOutcome, mergeAtZero};

DeleteSwapUnits: PUBLIC PROCEDURE [pageMember: VM.PageNumber] =
   BEGIN
   projDesc: projection STree.Desc;
   [] ← STree.Get[LOOPHOLE[LONG[@projDesc], STree.PDesc], [projection[pageMember]] ];
   IF projDesc.hasSwapUnits THEN
      { projDesc.hasSwapUnits ← FALSE;
         STree.Update[LOOPHOLE[LONG[@projDesc], STree.PDesc]]  };
   END;

ForceOut: PUBLIC PROCEDURE [pageMember: VM.PageNumber] =
   BEGIN
   desc: CachedRegion.Desc;
   outcome: CachedRegion.Outcome = CachedRegion.Apply[pageMember,
	 [ifMissing: report, ifCheckedOut: wait, afterForking: , vp: get[andResetDDirty: TRUE, pDescResult: @desc]]].outcome;
   WITH outcome SELECT FROM
      ok =>
	 IF desc.dDirty THEN
	   BEGIN OPEN desc;
	   projDesc: projection STree.Desc ← [projection[  -- transform a CachedRegion.Desc into an projection STLeaf.Desc:
	      page: interval.page,
	      level: level,
	      state: IF state IN STLeaf.ProjectionState THEN state
		    ELSE --state IN CachedRegion.Alive-- STLeaf.alive,  -- (in a projection desc, we only know that the region is some flavor of alive.)
	      levelMapped: levelMapped,
	      writeProtected: writeProtected,
	      hasSwapUnits: hasSwapUnits,
	      needsLogging: needsLogging]];
	   STree.Update[LOOPHOLE[LONG[@projDesc], STree.PDesc]]
	   END;
      regionDMissing => NULL;
      ENDCASE => ERROR Bug[funnyOutcome];
   END;

Get: PUBLIC PROCEDURE [pageMember: VM.PageNumber] RETURNS [desc: CachedRegion.Desc] =
   BEGIN
   projDesc: projection STree.Desc;
   keyNext: STree.Key;
   descVictim: CachedRegion.Desc;
   outcome: CachedRegion.Outcome = CachedRegion.Apply[pageMember,
	 [ifMissing: report, ifCheckedOut: wait, afterForking: , vp: get[andResetDDirty: FALSE, pDescResult: @desc]]].outcome;
   WITH outcome SELECT FROM
	 ok => NULL;  -- descriptor is in the cache, just return .it
      regionDMissing =>
	 -- Otherwise, fetch descriptor from hierarchy and cache it..
	 BEGIN
	 keyNext ← STree.Get[LOOPHOLE[LONG[@projDesc], STree.PDesc], [projection[pageMember]]];
	 BEGIN OPEN projDesc;
	   desc ← [  -- transform an projection STLeaf.Desc into a CachedRegion.Desc:
	      interval: [page, keyNext.pageP-page],
	      level: level,
	      dPinned: FALSE,
	      dTemperature: ,  -- don't care
	      dDirty:  FALSE,
	      state: state,  -- i.e. outAlive.
	      levelMapped: levelMapped,
	      beingFlushed: FALSE,
	      writeProtected: writeProtected,
	      hasSwapUnits: hasSwapUnits,
	      needsLogging: needsLogging];
	   END;
	 descVictim ← CachedRegion.Insert[desc];
	 IF descVictim.dDirty THEN
	   BEGIN OPEN descVictim;
	   projDesc ← [projection[  -- transform a CachedRegion.Desc into an projection STLeaf.Desc:
	      page: interval.page,
	      level: level,
	      state: IF state IN STLeaf.ProjectionState THEN state
		    ELSE --state IN CachedRegion.Alive-- STLeaf.alive,  -- (in a projection desc, we only know that the region is some flavor of alive.)
	      levelMapped: levelMapped,
	      writeProtected: writeProtected,
	      hasSwapUnits: hasSwapUnits,
	      needsLogging: needsLogging]];
	   STree.Update[LOOPHOLE[LONG[@projDesc], STree.PDesc]]
	   END
	 END;
      ENDCASE => ERROR Bug[funnyOutcome];
   END;

Merge: PUBLIC PROCEDURE [pageNext: VM.PageNumber] =
   BEGIN
   projDesc: projection STree.Desc;
   IF pageNext=0 THEN ERROR Bug[mergeAtZero];
   -- Unconditionally "resurrect" a dead region: conservative approach to avoid propagating deadness
   [] ← STree.Get[LOOPHOLE[LONG[@projDesc], STree.PDesc], [projection[pageNext-1]]];
   IF projDesc.state=outDead THEN
      { projDesc.state ← outAlive;
         STree.Update[LOOPHOLE[LONG[@projDesc], STree.PDesc]] };
   -- Do the merge:  (depends on the fact that the size of a projection STree.Desc is implicit)
   STree.Delete[[projection[pageNext]]];
   END;

Split: PUBLIC PROCEDURE [pageNext: VM.PageNumber] =
   BEGIN
   projDesc: projection STree.Desc;
   IF pageNext~=countVM THEN
      BEGIN
      -- Depends on the fact that the size of a projection STree.Desc is implicit
      [] ← STree.Get[LOOPHOLE[LONG[@projDesc], STree.PDesc], [projection[pageNext]]];
      IF projDesc.page~=pageNext THEN
	 { projDesc.page ← pageNext;
	    STree.Insert[LOOPHOLE[LONG[@projDesc], STree.PDesc]] };
      END;
   END;

Touch: PUBLIC PROCEDURE [pageMember: VM.PageNumber] =
   { [] ← Get[pageMember] };

TranslateLevel: PUBLIC PROCEDURE [pageMember: VM.PageNumber, delta: INTEGER] =
   BEGIN
   projDesc: projection STree.Desc;
   [] ← STree.Get[LOOPHOLE[LONG[@projDesc], STree.PDesc], [projection[pageMember]]];
   IF ~(projDesc.level+delta IN CachedSpace.Level) THEN ERROR Bug[funnyLevel];
   projDesc.level ← projDesc.level+delta;
   STree.Update[LOOPHOLE[LONG[@projDesc], STree.PDesc]]
   END;

END.


LOG

May 24, 1978  10:13 AM	McJones	Created file.
June 23, 1978  10:57 AM	McJones	Split didn't check for pageNext=countVM.
August 2, 1978  9:27 AM	McJones	Updated to new CachedRegion interface.
August 4, 1978  2:19 PM	McJones	Added beingRemapped.
August 29, 1978  7:32 PM	McJones	Cleared dDirty before calling CachedRegion.Insert.
August 21, 1979  4:33 PM	Knutsen	Made compatible with new CachedRegion.Desc.
September 28, 1979  3:57 PM	Knutsen	Made compatible with new CachedRegion.Desc.
February 25, 1980  6:01 PM	Knutsen	Added DeleteSwapUnits.  Named the ERRORs.
June 16, 1980  4:57 PM	Gobbel	Made compatible with new CachedRegion.Desc.
July 30, 1980  2:52 PM	Knutsen	Made compatible with new CachedRegion.Desc.
September 16, 1980  9:48 AM	Knutsen	DeleteSwapUnits failed if no existing swap units.
August 3, 1982 4:05 pm	Levin	Correct all occurrences of ~IN.