// IfsSequinUtil.bcpl - Sequin Utilities // Copyright Xerox Corporation 1979, 1980, 1981 // Last modified by November 25, 1981 2:29 PM by Taft get ecOutputVecFull, ecOutOfSequence, ecVPBIBackChain from "IfsLeafErrors.decl"; get "IfsLeaf.decl"; get "IfsSequin.decl"; external [ //outgoing procedures FindLockedSequin; NextLockedSequin; SequinAllocate; SequinFromPBI; SequinInput; SequinKickReaper; SequinPut; SequinStartOutput; SequinReadPBI; SequinReleasePBI; SequinRetransmit; SequinUnlockPBI; LockSequin; UnlockSequin; //incoming procedures SysAllocate; Dequeue; Enqueue; IFSError; Max; MultEq; SetPupDPort; GetVPBI; MoveBlock; ReadVPBI; ReleaseVPBI; ShortenVPBI; UnlockVPBI; SequenceCompare; //incoming statics scb; socLeaf; ] //---------------------------------------------------------------------------- let SequinAllocate(sequin) = valof //---------------------------------------------------------------------------- [ if sequin>>Sequin.retransmitting resultis 0; if Max(1, sequin>>Sequin.allocated) - (sequin>>Sequin.allocateSequence - sequin>>Sequin.ackedState.current) le 0 % sequin>>Sequin.freeOutputSlot eq maxOutputVPBIs then resultis 0; let vpbi = GetVPBI(lv scb>>SCB.outputAllocInfo); if vpbi eq 0 resultis 0; vpbi>>VPBI.output = true; resultis lv vpbi>>VPBI.pbi; ] //---------------------------------------------------------------------------- and SequinPut(sequin, pbi) be //---------------------------------------------------------------------------- [ let vpbi = pbi - pbiOffset; let vpbiID = vpbi>>VPBI.vpbiID; let pbiID = lv vpbi>>VPBI.pbi.pup.id; vpbi>>VPBI.sequin = sequin; ShortenVPBI(vpbi); // This optimizes VPBI page packing. let sequence = sequin>>Sequin.allocateSequence; // 16-bit sequence number. sequin>>Sequin.allocateSequence = sequence + 1; sequin>>Sequin.ancientVPBIs = vpbi>>VPBI.ancient; vpbi>>VPBI.backChain = sequin>>Sequin.lastPutVPBIID; vpbi>>VPBI.sequence = sequence; sequin>>Sequin.lastPutVPBIID = vpbiID; pbiID>>SequinID.sendSequence = sequence; pbiID>>SequinID.control = sequin>>Sequin.control; pbi>>PBI.queue = lv scb>>SCB.returnPBIQ; pbi>>PBI.socket = socLeaf; SetPupDPort(pbi, lv sequin>>Sequin.port); // Now put the vpbiID into the sequin output vector. let freeSlot = sequin>>Sequin.freeOutputSlot; if freeSlot eq maxOutputVPBIs then IFSError(ecOutputVecFull); sequin>>Sequin.outputVec↑freeSlot = vpbiID; sequin>>Sequin.freeOutputSlot = freeSlot + 1; UnlockVPBI(vpbi); SequinStartOutput(sequin); ] //---------------------------------------------------------------------------- and SequinStartOutput(sequin) be //---------------------------------------------------------------------------- [ manifest linkOffset = offset Sequin.outputLink/16; if sequin>>Sequin.outputLink eq -1 then [ Enqueue(lv scb>>SCB.outputSequinQ, sequin + linkOffset); LockSequin(sequin); ] ] //---------------------------------------------------------------------------- and SequinInput(sequin, pbi) be //---------------------------------------------------------------------------- [ if sequin>>Sequin.freeInputSlot eq maxInputVPBIs then return; //Drop on floor! let vpbi = GetVPBI(lv scb>>SCB.inputAllocInfo); vpbi>>VPBI.backChain = sequin>>Sequin.lastInputVPBIID; vpbi>>VPBI.sequin = sequin; sequin>>Sequin.lastInputVPBIID = vpbi>>VPBI.vpbiID; vpbi>>VPBI.sequence = sequin>>Sequin.receiveSequence; sequin>>Sequin.receiveSequence = sequin>>Sequin.receiveSequence + 1; MoveBlock(lv vpbi>>VPBI.pbi, pbi, lenPBIOverhead + pbi>>PBI.pup.length rshift 1); ShortenVPBI(vpbi); let freeSlot = sequin>>Sequin.freeInputSlot; sequin>>Sequin.inputVec↑freeSlot = vpbi>>VPBI.vpbiID; sequin>>Sequin.freeInputSlot = freeSlot + 1; UnlockVPBI(vpbi); if sequin>>Sequin.inputLink eq -1 then [ manifest linkOffset = offset Sequin.inputLink/16; Enqueue(lv scb>>SCB.inputSequinQ, sequin + linkOffset); LockSequin(sequin); ] ] //---------------------------------------------------------------------------- and SequinReadPBI(vpbiID, dirty, inCore, sequence; numargs na) = valof //---------------------------------------------------------------------------- [ let vpbi = ReadVPBI(vpbiID,(dirty? dirtyPage,cleanPage) + (inCoreOp & inCore)) if vpbi eq 0 resultis 0; unless na ls 4 do if sequence ne vpbi>>VPBI.sequence then IFSError(ecOutOfSequence); resultis lv vpbi>>VPBI.pbi; ] //---------------------------------------------------------------------------- and SequinReleasePBI(pbi) be //---------------------------------------------------------------------------- [ let vpbi = pbi - pbiOffset; let sequin = vpbi>>VPBI.sequin; if sequin ne 0 then SequinKickReaper(sequin); ReleaseVPBI(vpbi); UnlockVPBI(vpbi); ] //---------------------------------------------------------------------------- and SequinUnlockPBI(pbi) be UnlockVPBI(pbi - pbiOffset) //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- and SequinFromPBI(pbi) = (pbi - pbiOffset)>>VPBI.sequin //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- and SequinRetransmit(sequin) = valof //---------------------------------------------------------------------------- [ let sequence = sequin>>Sequin.sendSequence; let vecLength = sequence - sequin>>Sequin.ackedState.current; if vecLength eq 0 resultis 0; let id = sequin>>Sequin.lastSendVPBIID; let retransmitVec = SysAllocate(vecLength); let vecIndex = 0; [ // Scan the backward chain here. sequence = sequence - 1; if vecIndex ge vecLength then IFSError(ecVPBIBackChain); retransmitVec!vecIndex = id; vecIndex = vecIndex + 1; switchon SequenceCompare(sequence, sequin>>Sequin.ackedState.current) into [ case duplicate: vecIndex = vecIndex + sequence - sequin>>Sequin.ackedState.current; case equal: break; case outOfRange: IFSError(ecVPBIBackChain); ] let vpbi = ReadVPBI(id, cleanPage, true); //Read with no lock. if sequence ne vpbi>>VPBI.sequence then IFSError(ecOutOfSequence); id = vpbi>>VPBI.backChain; ] repeat sequin>>Sequin.retransmitVec = retransmitVec; sequin>>Sequin.retransmitIndex = vecIndex; resultis retransmitVec; ] //---------------------------------------------------------------------------- and FindLockedSequin(port) = valof //---------------------------------------------------------------------------- [ let sequin = 0; sequin = NextLockedSequin(sequin) repeatuntil sequin eq 0 % MultEq(lv sequin>>Sequin.port, port, lenPort) resultis sequin; ] //---------------------------------------------------------------------------- and NextLockedSequin(sequin) = valof //---------------------------------------------------------------------------- [ test sequin eq 0 ifso sequin = scb>>SCB.sequinQ.head; ifnot [ UnlockSequin(sequin); sequin = sequin>>Sequin.link; ] if sequin ne 0 then LockSequin(sequin); resultis sequin; ] //---------------------------------------------------------------------------- and LockSequin(sequin) be sequin>>Sequin.lock = sequin>>Sequin.lock + 1 //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- and UnlockSequin(sequin) be sequin>>Sequin.lock = sequin>>Sequin.lock - 1 //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- and SequinKickReaper(sequin) be //---------------------------------------------------------------------------- [ if sequin>>Sequin.ancientVPBIs then scb>>SCB.ancientScan = true; scb>>SCB.normalScan = true; ]