// IfsSequinFeed.bcpl - Sequin feed context - SWAPPABLE
// Copyright Xerox Corporation 1979

// Last modified by Wobber, February 9, 1981  2:03 PM

get "IfsSequin.decl";

external
[
//outgoing procedures
SequinFeedCtx;

//incoming procedures
Allocate; Block; CompletePup; Dequeue; FreePointer;
LeafFinish; MoveBlock; SequinFromPBI; SequinReadPBI; SequinRetransmit; 
SequinUnlockPBI; UnlockSequin; Unqueue; Zero;

//incoming statics
scb; sysZone;
]

//----------------------------------------------------------------------------
let SequinFeedCtx() be
//----------------------------------------------------------------------------
[
manifest linkOffset = offset Sequin.outputLink/16;
until scb>>SCB.haltFlag do
   [
   let link = scb>>SCB.outputSequinQ.head;
   while link ne 0 do
      [ // loop through active output sequin queue
         [ // empty return queue
         let pbi = Dequeue(lv scb>>SCB.returnPBIQ);
         if pbi eq 0 break;
         let sequin = SequinFromPBI(pbi); SequinUnlockPBI(pbi);
         sequin>>Sequin.unreturnedPBIs = sequin>>Sequin.unreturnedPBIs - 1;
         ] repeat
      let sequin = link - linkOffset; link = sequin>>Sequin.outputLink;
      if sequin>>Sequin.state eq destroyedState then
         [
         Zero(lv sequin>>Sequin.outputVec, maxOutputVPBIs);
         sequin>>Sequin.retransmitting = false;
         FreePointer(lv sequin>>Sequin.retransmitVec);
         sequin>>Sequin.freeOutputSlot = 0;
         ]
      if SendPBIs(sequin) then loop;
      if sequin>>Sequin.unreturnedPBIs eq 0 then
         [
         Unqueue(lv scb>>SCB.outputSequinQ, sequin+linkOffset);
         sequin>>Sequin.outputLink = -1; UnlockSequin(sequin);
         ]
      ]
   Block();
   ]
LeafFinish();
]

//----------------------------------------------------------------------------
and SendPBIs(sequin) = valof
//----------------------------------------------------------------------------
[
// Send a pup from the argument sequin and continue to send all which
//  happen to be in locked down vPages.  Return false if nothing to send,
//   return true otherwise.

let doneOne = false; let pbi = 0;
   [ //  Giant repeat loop
   test sequin>>Sequin.retransmitting;

      // Retransmit branch...fetch top of retransmit vector...
      //  ...form retransmit vector if necessary.
      //
      ifso
         [
         let retransmitVec = sequin>>Sequin.retransmitVec;
         if retransmitVec eq 0 then
            [
            // Form the retransmit VPBI vector.
            // Don't start retransmission if outstanding output VPBIs.
            if sequin>>Sequin.unreturnedPBIs ne 0 then resultis true;
            retransmitVec = SequinRetransmit(sequin);
            ]

         // Test for retransmit completion.
         //
         let vecIndex = sequin>>Sequin.retransmitIndex - 1;
         if vecIndex ls 0 then
            [
            FreePointer(lv sequin>>Sequin.retransmitVec);
            sequin>>Sequin.retransmitting = false;
            // Note that a HandleAcks could be done here.
            loop;  // Retry using output branch.
            ]

         // Read in the VPBI at the top of the retransmit vector.
         //
         pbi = SequinReadPBI(retransmitVec!vecIndex, false, doneOne);
         if pbi eq 0 break;
         sequin>>Sequin.retransmitIndex = vecIndex;
         ]

      // Output branch....fetch top of output vector.
      //
      ifnot
         [
         let vpbiID = sequin>>Sequin.outputVec↑0; if vpbiID eq 0 break;
         let sequence = sequin>>Sequin.sendSequence;
         pbi = SequinReadPBI(vpbiID, false, doneOne, sequence);
         if pbi eq 0 break;
         // We will init vec!maxOutputVPBIs to 0 so that the following works.
         MoveBlock(lv sequin>>Sequin.outputVec, lv sequin>>Sequin.outputVec↑1,
          maxOutputVPBIs);
         sequin>>Sequin.freeOutputSlot = sequin>>Sequin.freeOutputSlot - 1;
         sequin>>Sequin.sendSequence = sequence + 1;
         sequin>>Sequin.lastSendVPBIID = vpbiID;
         ]

   // Branches merge here ... send the pup.
   let pbiID = lv pbi>>PBI.pup.id;
   pbiID>>SequinID.allocate =
    sequin>>Sequin.allocate - sequin>>Sequin.freeInputSlot;
   pbiID>>SequinID.receiveSequence = sequin>>Sequin.receiveSequence;
   sequin>>Sequin.unreturnedPBIs = sequin>>Sequin.unreturnedPBIs + 1;
   CompletePup(pbi, typeLeaf); doneOne = true;
   ] repeat
resultis doneOne
]