// IfsSequinReaper.bcpl - Sequin - SWAPPABLE
// Copyright Xerox Corporation 1979, 1980

// Last modified by Wobber, April 1, 1981  10:40 AM

get "IfsSequin.decl";

external
[
//outgoing procedures
SequinReaper;

//incoming procedures
Block; CloseFH; Dequeue;
DoubleIncrement; Free; FreePointer;
ScanVPBIPage; SequinDestroy;
SetTimer; TimerHasExpired; Umin; Unqueue;

//incoming statics
haltFlag; leafEnabled; scb; sysZone;
]


//----------------------------------------------------------------------------
let SequinReaper() be
//----------------------------------------------------------------------------
[
// See if we can reap some VPBIs.
if scb>>SCB.activityWord ne 0 then ScanReaperQueues();

// This cleans up dead sequins.
let sequin = scb>>SCB.sequinQ.head;
until sequin eq 0 do
   [
   let nextSequin = sequin>>Sequin.link;
   let timerCount = sequin>>Sequin.timerCount;
   let haltTimerCount = sequin>>Sequin.haltTimerCount;
   switchon sequin>>Sequin.state into
      [
      case openState:
         unless timerCount eq 0 do endcase;
         timerCount = sequin>>Sequin.connTimeout;
         sequin>>Sequin.state = timedOutState;  // fall through
      case timedOutState:
         unless sequin>>Sequin.brokenLeaf do endcase;
      default:
         timerCount = Umin(brokenConnTimeout, timerCount);
         endcase;
      ]
   test haltTimerCount eq 0
      ifso if haltFlag % not leafEnabled then timerCount = 0;
      ifnot sequin>>Sequin.haltTimerCount = haltTimerCount - 1;
   test timerCount eq 0
      ifso SequinDestroy(sequin);
      ifnot sequin>>Sequin.timerCount = timerCount - 1;

   if sequin>>Sequin.state eq destroyedState & sequin>>Sequin.lock eq 0 &
    sequin>>Sequin.allocateSequence eq sequin>>Sequin.ackedState.reaped &
     sequin>>Sequin.receiveSequence eq sequin>>Sequin.inputState.reaped then
         [
         // Reap the sequin.
            [
            let fh = sequin>>Sequin.fhQ.head; if fh eq 0 break;
            CloseFH(sequin, fh);
            ] repeat
         Unqueue(lv scb>>SCB.sequinQ, sequin);
         FreePointer(lv sequin>>Sequin.unam); Free(sysZone, sequin);
         ]
   sequin = nextSequin;
   ]
DoubleIncrement(lv scb>>SCB.reaperCycles);
]

//----------------------------------------------------------------------------
and ScanReaperQueues() be
//----------------------------------------------------------------------------
[
let ancientScan = scb>>SCB.ancientScan;
scb>>SCB.ancientScan = false;
scb>>SCB.normalScan =
 ScanVPageQ(lv scb>>SCB.inputAllocInfo, ancientScan) %
  ScanVPageQ(lv scb>>SCB.outputAllocInfo, ancientScan);
if ancientScan then DoubleIncrement(lv scb>>SCB.ancientScans);
if scb>>SCB.normalScan then DoubleIncrement(lv scb>>SCB.normalScans);
]

//----------------------------------------------------------------------------
and ScanVPageQ(alloc, ancientScan) = valof
//----------------------------------------------------------------------------
[
let vPage = nil; let linkPage = nil;
let ancientHead = alloc>>AllocInfo.ancientQ.head;
let ancientTail = alloc>>AllocInfo.ancientQ.tail;
test ancientScan & ancientHead ne 0
   ifnot linkPage = (ancientHead ne 0? ancientTail, 0);
   ifso
      [
      //Scan the ancientQ here.
      vPage = ancientHead; linkPage = 0;
         [
         let nextVPage = ScanVPBIPage(vPage, alloc, lv linkPage);
         if vPage eq ancientTail then break; vPage = nextVPage;
         ] repeat
      if linkPage eq 0 then alloc>>AllocInfo.ancientQ.head = 0;
      ]

// Return false if nothing to scan on vPageQ.
vPage = alloc>>AllocInfo.vPageQ.head;
if alloc>>AllocInfo.vPageQ.tail eq 0 %
 (vPage eq alloc>>AllocInfo.vPageQ.tail &
  alloc>>AllocInfo.nextVPBI eq 0) then resultis false;

// Now scan the vPageQ. 
alloc>>AllocInfo.vPageQ.head = 0;
   [ //Loop to scan queue.
   let nextVPage = ScanVPBIPage(vPage, alloc, lv linkPage);
   if nextVPage eq 0 break; vPage = nextVPage;
   ] repeatuntil vPage eq alloc>>AllocInfo.nextVPage
alloc>>AllocInfo.vPageQ.head = vPage;
resultis true;
]