-- Swapper>SwapperControl.mesa  (last edited by Levin on September 15, 1982 8:50 pm)

DIRECTORY
  CachedRegion USING [age, Apply, Outcome, pagefault, pageTop],
  CachedRegionInternal USING [FindUnreferenced],
  Environment USING [PageCount, PageNumber],
  MStore USING [AwaitBelowThreshold, SetThreshold],
  PageFault USING [AwaitPageFault],
  Process USING [DisableAborts, GetPriority, Priority, SetPriority, SetTimeout],
  ProcessPriorities USING [priorityPageFaultHigh],
  Runtime USING [CallDebugger],
  StoragePrograms USING [],
  SwapperException USING [Report],
  SwapperPrograms USING [
    CachedRegionImplB, CachedSpaceImpl, PageFaultImpl, InitializeSwapBuffer,
    SwapperExceptionImpl, SwapTaskImpl];

SwapperControl: MONITOR --just so we can use a CONDITION as a mechanism for yielding control--
  IMPORTS
    CachedRegion, CachedRegionInternal, MStore, PageFault, Process, Runtime,
    SwapperException, SwapperPrograms
  EXPORTS StoragePrograms =

BEGIN

InitializeSwapper: PUBLIC PROCEDURE [pMapLogDesc: LONG POINTER TO UNSPECIFIED] =
  BEGIN
  throwAway: PROCESS;
  priorityPrev: Process.Priority;
  -- CachedRegionImplA is started by PilotControl (see StoragePrograms).
  -- MStoreImpl is started by PilotControl (see StoragePrograms).
  -- SimpleSpaceImpl is started by PilotControl (see StoragePrograms).
  -- ResidentMemoryImpl is started by PilotControl (see StoragePrograms).
  -- ResidentHeapImpl is started by PilotControl (see StoragePrograms).
  START SwapperPrograms.CachedSpaceImpl[];
  START SwapperPrograms.CachedRegionImplB[pMapLogDesc];
  SwapperPrograms.InitializeSwapBuffer[];  -- (CachedSpaceImpl must be started first.)
  START SwapperPrograms.PageFaultImpl[];
  START SwapperPrograms.SwapTaskImpl[];
  START SwapperPrograms.SwapperExceptionImpl[];
  Process.DisableAborts[@aShortTime];
  Process.SetTimeout[condition: @aShortTime, ticks: 1];
  priorityPrev ← Process.GetPriority[];
  Process.SetPriority[ProcessPriorities.priorityPageFaultHigh];
  throwAway ← FORK PageFaultProcess[];  -- (no profit in detaching.)
  Process.SetPriority[priorityPrev];
  -- (ReplacementProcess is forked by PilotControl.)
  END;

PageFaultProcess: PROCEDURE =
  BEGIN
  page: Environment.PageNumber;
  outcome: CachedRegion.Outcome;
  DO
    page ← PageFault.AwaitPageFault[];  -- wait for a page fault.
    -- Start region coming in.  Faulting process will be restarted by PageTransferProcess
    -- when it is in.
    outcome ← CachedRegion.Apply[page, CachedRegion.pagefault].outcome;
    WITH outcome SELECT FROM
      ok => NULL;
      regionDMissing, spaceDMissing, error =>
        -- I can't do it, pass the buck to the VM Helper.
        SwapperException.Report[page, CachedRegion.pagefault, outcome];
      ENDCASE => ERROR;
    ENDLOOP;
  END;

aShortTime: CONDITION;  -- used to yield control to VM Helper, and to yield control if everyone is being referenced.

ReplacementProcess: PUBLIC ENTRY PROCEDURE [threshold: Environment.PageCount] =
  BEGIN
  deadlockPasses: CARDINAL = 1000;  -- meant to be about 60 sec of trying.
  swapUnitsAgedInCycle: CARDINAL;  -- just for instrumentation.
  page, pageNext: Environment.PageNumber;
  newCycle, allReferenced: BOOLEAN;
  outcome: CachedRegion.Outcome;
  passes: CARDINAL ← 0;
  MStore.SetThreshold[threshold];
  DO --make a pass through memory..
    FOR page ← FIRST[Environment.PageNumber], pageNext WHILE page<CachedRegion.pageTop DO
      IF (newCycle ← MStore.AwaitBelowThreshold[].newCycle) THEN  -- wait until memory gets short
        {passes ← 0; swapUnitsAgedInCycle ← 0};
      [allReferenced, page] ← CachedRegionInternal.FindUnreferenced[newCycle, page];
      IF allReferenced THEN WAIT aShortTime;
      [outcome, pageNext] ← CachedRegion.Apply[page, CachedRegion.age];  -- swaps out region if not referenced; else marks it not referenced.
      swapUnitsAgedInCycle ← SUCC[swapUnitsAgedInCycle];
      SELECT outcome.kind FROM
        ok => NULL;
        spaceDMissing => {
          SwapperException.Report[page, CachedRegion.age, outcome];
          IF passes >= 2 THEN WAIT aShortTime;
          };  -- if we're having trouble, allow VM Helper a chance to make progress.
        ENDCASE => ERROR;
      ENDLOOP;
    IF (passes ← SUCC[passes]) >= deadlockPasses THEN
    Runtime.CallDebugger["No regions to swap out!"];
    ENDLOOP; --end of one pass through memory.
  END;

END.


LOG

(For earlier log entries, see Pilot 3.0 archive version.)
January 31, 1980  1:03 PM	Knutsen/McJones	Add Region Cache parameters/switch to InitializeSwapper starting interface.
February 21, 1980  6:53 PM	Knutsen	Implement Region Cache parameters.  Don't START MStoreImpl (now started by PilotControl).
March 20, 1980  12:50 PM	Knutsen	Made ReplacementProcess detect deadlocks.
April 15, 1980  12:05 PM	Knutsen	Various components started early by PilotControl.
December 1, 1980  12:55 PM	Knutsen	Only use Process.mumble during initialization.  Yield to VMHelper if having trouble. Use FindUnreferenced.
January 19, 1981  4:14 PM	Knutsen	Set process priorities.
September 15, 1982 8:50 pm	Levin	PageFault.Await => PageFault.AwaitPageFault.