DIRECTORY Basics USING [LongNumber], BufferDefs USING [defaultDataWordsPerSystemBuffer, BufferAccessHandle, BufferAccessObject, BufferFunction, BufferType, Buffer, PupBuffer, OisBuffer, SppBuffer, BufferObject, Queue, QueueObject, wordsPerNonVarientBufferOverhead], CommFlags USING [doDebug, doStats], CommUtilDefs USING [AllocateBuffers, FreeBuffers, AllocateIocb, FreeIocb, GetReturnFrame, MaybeShorten], DriverDefs USING [Glitch, GetGiantVector, Network], DriverTypes USING [bufferSeal, bufferPoolSeal, queueSeal], PrincOpsUtils USING [BITAND, LowHalf], OISCP USING [], OISCPTypes USING [BufferBody, wordPerPktHeader, wordsPerLevel2SppHeader], Process USING [InitializeCondition, MsecToTicks], PupDefs USING [], StatsDefs USING [StatBump, StatIncr], ProcessorFace USING [GetClockPulses, microsecondsPerHundredPulses]; BufferMgr: MONITOR IMPORTS CommUtilDefs, DriverDefs, PrincOpsUtils, Process, StatsDefs, ProcessorFace EXPORTS BufferDefs, DriverDefs, OISCP, PupDefs SHARES BufferDefs = BEGIN OPEN BufferDefs, DriverDefs; Network: PUBLIC TYPE = DriverDefs.Network; accessHandleChainHead: BufferDefs.BufferAccessHandle _ NIL; systemAccessHandle: PUBLIC BufferDefs.BufferAccessHandle _ NIL; systemFreeQueueNotEmpty: CONDITION; systemBufferQueue: Queue; systemDataWordsPerBuffer: CARDINAL _ MAX[defaultDataWordsPerSystemBuffer, 271]; -- The 271 ensures that the raw buffers are big enough to hold a maximum-size ARPA IP packet (576 bytes plus 8 bytes of encapsulation). The constant was determined empirically; its computation is to disgusting to describe cleanly. systemBufferSize: CARDINAL _ 0; useCount: CARDINAL _ 0; wordsPerIocb: CARDINAL _ 0; totalSendAndReceiveBuffers: CARDINAL _ 0; totalSendAndReceiveBuffersInUse: CARDINAL _ 0; totalReserveBuffers: CARDINAL _ 0; inactivePools: CARDINAL _ 0; enqueue: PROCEDURE [Queue, Buffer] _ Enqueue; rawOverhead: CARDINAL = BufferDefs.wordsPerNonVarientBufferOverhead; oisOverhead: CARDINAL = rawOverhead + OISCPTypes.wordPerPktHeader; sppOisOverhead: CARDINAL = oisOverhead + OISCPTypes.wordsPerLevel2SppHeader; pupOverhead: CARDINAL = SIZE[pupWords pup BufferDefs.BufferObject] + 1; overhead: CARDINAL = MAX[ pupOverhead, oisOverhead, sppOisOverhead]; QueueSealBroken: PUBLIC ERROR = CODE; PoolSealBroken: PUBLIC ERROR = CODE; BufferSealBroken: PUBLIC ERROR = CODE; FreeQueueNotInitialized: PUBLIC ERROR = CODE; BufferPoolNotInitialized: PUBLIC ERROR = CODE; QueueScrambled: PUBLIC ERROR = CODE; CantResetWhileActive: PUBLIC ERROR = CODE; SystemBufferSizeConfused: PUBLIC ERROR = CODE; DontKnowHowToAllocateBuffer: PUBLIC ERROR = CODE; AdjustBufferSize: PUBLIC ENTRY PROCEDURE [bufferSize: CARDINAL] = BEGIN IF useCount # 0 THEN Glitch[CantResetWhileActive]; IF bufferSize # 0 THEN systemDataWordsPerBuffer _ bufferSize; systemBufferSize _ 0; END; GetBufferSize: PUBLIC PROCEDURE RETURNS [bufferSize: CARDINAL] = BEGIN RETURN[systemDataWordsPerBuffer]; END; GetWordsPerIocb: PUBLIC PROCEDURE RETURNS [CARDINAL] = BEGIN RETURN[wordsPerIocb]; END; SetWordsPerIocb: PUBLIC PROCEDURE [new: CARDINAL] = BEGIN wordsPerIocb _ new; END; MakeBufferPool: PUBLIC ENTRY PROCEDURE [ total: CARDINAL, -- number of new buffer that will actually be created send: CARDINAL, receive: CARDINAL, reserve: CARDINAL, forSystemUse: BOOLEAN] -- as opposed to for socket use RETURNS [p: BufferAccessHandle] = BEGIN b: Buffer; x: --SHORT--POINTER TO BufferObject = NIL; i: CARDINAL; newSystemBufferSize: CARDINAL; IF NOT forSystemUse THEN BEGIN totalSendAndReceiveBuffers _ totalSendAndReceiveBuffers + send + receive; END; totalReserveBuffers _ totalReserveBuffers + reserve; useCount _ useCount + 1; p _ NEW[BufferAccessObject]; p.seal _ DriverTypes.bufferPoolSeal; p.active _ TRUE; p.madeForSystem _ forSystemUse; p.filler _ 0; p.total _ total; p.sendInUse _ p.receiveInUse _ p.recovered _ 0; p.send _ send; p.receive _ receive; p.reserve _ reserve; p.next _ accessHandleChainHead; accessHandleChainHead _ p; IF CommFlags.doDebug THEN DriverDefs.GetGiantVector[].firstBufferAccessHandle _ accessHandleChainHead; Process.InitializeCondition[ CommUtilDefs.MaybeShorten[@p.bufferAvailable], Process.MsecToTicks[10000]]; IF p.total = 0 THEN BEGIN p.firstBuffer _ LOOPHOLE[p]; RETURN; END; p.wordsPerBuffer _ systemDataWordsPerBuffer + overhead + 2 + 4 + 3; UNTIL PrincOpsUtils.BITAND[p.wordsPerBuffer, 3] = 0 DO p.wordsPerBuffer _ p.wordsPerBuffer + 1; ENDLOOP; newSystemBufferSize _ p.wordsPerBuffer - (@x.encapsulation - LOOPHOLE[x, POINTER]); IF systemBufferSize = 0 THEN systemBufferSize _ newSystemBufferSize ELSE IF newSystemBufferSize # systemBufferSize THEN Glitch[SystemBufferSizeConfused]; p.firstBuffer _ CommUtilDefs.AllocateBuffers[p.wordsPerBuffer*total + 3]; DO c: CARDINAL _ LOOPHOLE[PrincOpsUtils.LowHalf[@p.firstBuffer.encapsulation]]; IF PrincOpsUtils.BITAND[c, 3] = 3 THEN EXIT; p.firstBuffer _ p.firstBuffer + 1; ENDLOOP; b _ p.firstBuffer; FOR i IN [0..total) DO b.iocbChain _ NIL; b.allNets _ b.bypassZeroNet _ FALSE; b.type _ raw; b.pupLength _ b.length _ 0; b.pupType _ last; b.queue _ NIL; b.pool _ p; b.next _ NIL; IF CommFlags.doDebug THEN b.seal _ DriverTypes.bufferSeal; b.requeueProcedure _ ReturnFreeBuffer; Enqueue[systemBufferQueue, b]; b _ b + p.wordsPerBuffer; ENDLOOP; IF wordsPerIocb # 0 THEN BEGIN b _ p.firstBuffer; FOR i IN [0..total) DO b.iocbChain _ CommUtilDefs.AllocateIocb[wordsPerIocb]; b _ b + p.wordsPerBuffer; ENDLOOP; END; END; DestroyBufferPoolLocked: PROCEDURE [p: BufferAccessHandle] = BEGIN IF CommFlags.doDebug THEN BEGIN b: Buffer _ p.firstBuffer; FOR i: CARDINAL IN [0..p.total) DO IF b.queue # NIL THEN Glitch[QueueScrambled]; b _ b + p.wordsPerBuffer; ENDLOOP; END; IF p.total # 0 THEN BEGIN b: Buffer _ p.firstBuffer; FOR i: CARDINAL IN [0..p.total) DO IF b.iocbChain # NIL THEN CommUtilDefs.FreeIocb[b.iocbChain]; b _ b + p.wordsPerBuffer; ENDLOOP; CommUtilDefs.FreeBuffers[p.firstBuffer, p.wordsPerBuffer*p.total + 3]; END; IF NOT p.madeForSystem THEN totalSendAndReceiveBuffers _ totalSendAndReceiveBuffers - (p.send + p.receive - p.total); p.firstBuffer _ NIL; IF accessHandleChainHead=p THEN BEGIN accessHandleChainHead _ p.next; IF CommFlags.doDebug THEN DriverDefs.GetGiantVector[].firstBufferAccessHandle _ accessHandleChainHead; END ELSE BEGIN prev: BufferDefs.BufferAccessHandle _ accessHandleChainHead; WHILE (prev#NIL) AND (prev.next#p) DO prev _ prev.next; ENDLOOP; IF prev=NIL THEN ERROR; prev.next _ p.next; END; p.next _ NIL; useCount _ useCount - 1; IF (inactivePools _ inactivePools - 1) = 0 AND enqueue = EnqueueActiveBuffersOnly THEN BEGIN IF CommFlags.doStats THEN StatsDefs.StatBump[statRecyclingZombieBuffersTime, LOOPHOLE[((ProcessorFace.GetClockPulses[]-startReCyclingTime+50)/100)*ProcessorFace.microsecondsPerHundredPulses, Basics.LongNumber].lowbits]; enqueue _ Enqueue; END; END; startReCyclingTime: LONG CARDINAL --Pulses--; FreeBufferPool: PUBLIC ENTRY PROCEDURE [p: BufferAccessHandle] = BEGIN b: Buffer _ p.firstBuffer; IF CommFlags.doDebug AND (useCount = 0 OR p = NIL) THEN Glitch[FreeQueueNotInitialized]; IF CommFlags.doDebug AND p.seal # DriverTypes.bufferPoolSeal THEN Glitch[PoolSealBroken]; IF CommFlags.doDebug AND p.firstBuffer = NIL THEN Glitch[BufferPoolNotInitialized]; IF NOT p.madeForSystem THEN BEGIN WHILE p.sendInUse>0 DO WAIT systemFreeQueueNotEmpty; -- any short CV will do ENDLOOP; END; p.active _ FALSE; inactivePools _ inactivePools + 1; totalReserveBuffers _ totalReserveBuffers - p.reserve; p.recovered _ 0; FOR i: CARDINAL IN [0..p.total) DO IF b.queue = systemBufferQueue THEN BEGIN p.recovered _ p.recovered + 1; IF NOT p.madeForSystem THEN totalSendAndReceiveBuffers _ totalSendAndReceiveBuffers - 1; IF ExtractFromQueue[systemBufferQueue, b] # b THEN Glitch[QueueScrambled]; END; b _ b + p.wordsPerBuffer; ENDLOOP; IF p.recovered = p.total THEN DestroyBufferPoolLocked[p] -- all buffers recovered, so destroy pool. ELSE BEGIN IF CommFlags.doStats AND enqueue # EnqueueActiveBuffersOnly THEN startReCyclingTime _ ProcessorFace.GetClockPulses[]; enqueue _ EnqueueActiveBuffersOnly; -- continue trying to recover buffers END; END; EnqueueActiveBuffersOnly: PROCEDURE [q: Queue, b: Buffer] = BEGIN aH: BufferAccessHandle = b.pool; IF aH.active THEN Enqueue[q, b] ELSE BEGIN IF b = NIL OR b.queue # NIL THEN Glitch[QueueScrambled]; IF CommFlags.doDebug AND q.seal # DriverTypes.queueSeal THEN Glitch[QueueSealBroken]; IF CommFlags.doDebug AND b.seal # DriverTypes.bufferSeal THEN Glitch[BufferSealBroken]; b.next _ NIL; aH.recovered _ aH.recovered + 1; IF NOT aH.madeForSystem THEN totalSendAndReceiveBuffers _ totalSendAndReceiveBuffers - 1; IF aH.recovered = aH.total THEN DestroyBufferPoolLocked[aH]; END; END; DataWordsPerPupBuffer: PUBLIC SAFE PROCEDURE RETURNS [CARDINAL] = CHECKED BEGIN RETURN[systemDataWordsPerBuffer + (overhead - pupOverhead)]; END; DataWordsPerRawBuffer: PUBLIC PROCEDURE RETURNS [CARDINAL] = BEGIN RETURN[systemDataWordsPerBuffer + (overhead - rawOverhead)]; END; DataWordsPerOisBuffer: PUBLIC PROCEDURE RETURNS [CARDINAL] = BEGIN RETURN[systemDataWordsPerBuffer + (overhead - oisOverhead)]; END; DataWordsPerSppBuffer: PUBLIC PROCEDURE RETURNS [CARDINAL] = BEGIN RETURN[systemDataWordsPerBuffer + (overhead - sppOisOverhead)]; END; SendAndReceiveBuffersInFreeQueue: PROCEDURE RETURNS [CARDINAL] = INLINE BEGIN RETURN[ IF totalSendAndReceiveBuffersInUse >= totalSendAndReceiveBuffers THEN 0 ELSE totalSendAndReceiveBuffers - totalSendAndReceiveBuffersInUse]; END; GetInputBuffer: PUBLIC ENTRY PROCEDURE [tryToWaitForBuffer: BOOLEAN] RETURNS [b: Buffer _ NIL] = BEGIN IF CommFlags.doDebug AND useCount = 0 THEN Glitch[FreeQueueNotInitialized]; FOR i: CARDINAL IN [0..2) DO IF systemBufferQueue.length > 0 THEN BEGIN b _ Dequeue[systemBufferQueue]; b.currentOwner _ systemAccessHandle; b.bufFunc _ systemUse; b.length _ systemBufferSize; b.type _ raw; IF CommFlags.doDebug THEN b.debug _ CommUtilDefs.GetReturnFrame[].accesslink; RETURN; END; IF (~tryToWaitForBuffer) OR (i > 0) THEN RETURN; WAIT systemFreeQueueNotEmpty; ENDLOOP; END; FillInBufferTypeInformation: PROCEDURE [ b: Buffer, bufType: BufferType, bufFunc: BufferFunction] = INLINE BEGIN b.bufFunc _ bufFunc; SELECT bufType FROM oisSpp => BEGIN sppBuf: LONG POINTER TO spp OISCPTypes.BufferBody = LOOPHOLE[b+rawOverhead]; sppBuf.systemPacket _ sppBuf.sendAck _ sppBuf.attention _ sppBuf.endOfMessage _ FALSE; bufType _ ois; END; pup => b.pupType _ data; ENDCASE => NULL; b.type _ bufType; END; GetFreeBuffer: PUBLIC ENTRY PROCEDURE [ bufType: BufferType, aH: BufferAccessHandle, bufFunc: BufferFunction] RETURNS [b: Buffer] = BEGIN ENABLE UNWIND => NULL; IF CommFlags.doDebug AND useCount = 0 THEN Glitch[FreeQueueNotInitialized]; IF CommFlags.doDebug AND aH.seal # DriverTypes.bufferPoolSeal THEN Glitch[PoolSealBroken]; IF CommFlags.doDebug AND aH.firstBuffer = NIL THEN Glitch[BufferPoolNotInitialized]; IF aH = systemAccessHandle THEN BEGIN IF CommFlags.doDebug AND bufFunc # systemUse THEN Glitch[DontKnowHowToAllocateBuffer]; IF CommFlags.doStats AND ~systemBufferQueue.length > totalReserveBuffers + SendAndReceiveBuffersInFreeQueue[] THEN StatsDefs.StatIncr[statBufferWaits]; UNTIL systemBufferQueue.length > totalReserveBuffers + SendAndReceiveBuffersInFreeQueue[] DO WAIT systemFreeQueueNotEmpty; ENDLOOP; END ELSE BEGIN sendOrReceiveInUse: LONG POINTER TO CARDINAL; sendOrReceive: CARDINAL; SELECT bufFunc FROM send => BEGIN sendOrReceiveInUse _ @aH.sendInUse; sendOrReceive _ aH.send; END; receive => BEGIN sendOrReceiveInUse _ @aH.receiveInUse; sendOrReceive _ aH.receive; END; ENDCASE => Glitch[DontKnowHowToAllocateBuffer]; IF CommFlags.doStats AND (~sendOrReceiveInUse^ < sendOrReceive OR systemBufferQueue.length = 0) THEN StatsDefs.StatIncr[statBufferWaits]; UNTIL (sendOrReceiveInUse^ < sendOrReceive) DO WAIT aH.bufferAvailable; ENDLOOP; sendOrReceiveInUse^ _ sendOrReceiveInUse^ + 1; totalSendAndReceiveBuffersInUse _ totalSendAndReceiveBuffersInUse + 1; UNTIL (systemBufferQueue.length > 0) DO WAIT systemFreeQueueNotEmpty; ENDLOOP; END; b _ Dequeue[systemBufferQueue]; IF CommFlags.doDebug AND b = NIL THEN Glitch[QueueScrambled]; FillInBufferTypeInformation[b, bufType, bufFunc]; b.currentOwner _ aH; IF CommFlags.doDebug THEN b.debug _ CommUtilDefs.GetReturnFrame[].accesslink; END; MaybeGetFreeBuffer: PUBLIC ENTRY PROCEDURE [ bufType: BufferType, aH: BufferAccessHandle, bufFunc: BufferFunction] RETURNS [b: Buffer] = BEGIN IF CommFlags.doDebug AND useCount = 0 THEN Glitch[FreeQueueNotInitialized]; IF CommFlags.doDebug AND aH.seal # DriverTypes.bufferPoolSeal THEN Glitch[PoolSealBroken]; IF CommFlags.doDebug AND aH.firstBuffer = NIL THEN Glitch[BufferPoolNotInitialized]; IF aH = systemAccessHandle THEN BEGIN IF ~systemBufferQueue.length > SendAndReceiveBuffersInFreeQueue[] THEN BEGIN b _ NIL; IF CommFlags.doStats THEN StatsDefs.StatIncr[statBufferWaits]; RETURN; END; IF CommFlags.doDebug AND bufFunc # systemUse THEN Glitch[DontKnowHowToAllocateBuffer]; END ELSE BEGIN sendOrReceiveInUse: LONG POINTER TO CARDINAL; sendOrReceive: CARDINAL; SELECT bufFunc FROM send => BEGIN sendOrReceiveInUse _ @aH.sendInUse; sendOrReceive _ aH.send; END; receive => BEGIN sendOrReceiveInUse _ @aH.receiveInUse; sendOrReceive _ aH.receive; END; ENDCASE => Glitch[DontKnowHowToAllocateBuffer]; IF (~sendOrReceiveInUse^ < sendOrReceive) OR (systemBufferQueue.length = 0) THEN BEGIN b _ NIL; IF CommFlags.doStats THEN StatsDefs.StatIncr[statBufferWaits]; RETURN; END; sendOrReceiveInUse^ _ sendOrReceiveInUse^ + 1; totalSendAndReceiveBuffersInUse _ totalSendAndReceiveBuffersInUse + 1; END; IF (b _ Dequeue[systemBufferQueue]) = NIL THEN Glitch[QueueScrambled]; FillInBufferTypeInformation[b, bufType, bufFunc]; b.currentOwner _ aH; IF CommFlags.doDebug THEN b.debug _ CommUtilDefs.GetReturnFrame[].accesslink; END; CreditReceiveOisBuffer: PUBLIC ENTRY PROCEDURE [ aH: BufferAccessHandle, b: OisBuffer] RETURNS [gotCreadit: BOOLEAN] = BEGIN IF CommFlags.doDebug AND (aH = NIL OR aH.firstBuffer = NIL) THEN Glitch[BufferPoolNotInitialized]; IF CommFlags.doDebug AND aH.seal # DriverTypes.bufferPoolSeal THEN Glitch[PoolSealBroken]; IF (gotCreadit _ aH.receiveInUse < aH.receive) THEN BEGIN aH.receiveInUse _ aH.receiveInUse + 1; totalSendAndReceiveBuffersInUse _ totalSendAndReceiveBuffersInUse + 1; b.currentOwner _ aH; b.bufFunc _ receive; END ELSE IF CommFlags.doStats THEN StatsDefs.StatIncr[statBufferWaits]; END; NILNetwork: PROCEDURE RETURNS [Network] = INLINE {RETURN[NIL]}; ReturnFreePupBuffer: PUBLIC PROCEDURE [PupBuffer] = LOOPHOLE[ReturnFreeBuffer]; ReturnFreeOisBuffer: PUBLIC PROCEDURE [OisBuffer] = LOOPHOLE[ReturnFreeBuffer]; ReturnFreeSppBuffer: PUBLIC PROCEDURE [SppBuffer] = LOOPHOLE[ReturnFreeBuffer]; ReturnFreeBuffer: PUBLIC ENTRY PROCEDURE [b: Buffer] = BEGIN aH: BufferAccessHandle = b.currentOwner; IF CommFlags.doDebug AND useCount = 0 THEN Glitch[FreeQueueNotInitialized]; IF CommFlags.doDebug AND aH.firstBuffer = NIL THEN Glitch[BufferPoolNotInitialized]; b.requeueProcedure _ ReturnFreeBuffer; b.network _ NILNetwork[]; -- because of mokelumne compiler bug IF aH # systemAccessHandle THEN BEGIN SELECT b.bufFunc FROM send => aH.sendInUse _ aH.sendInUse - 1; receive => aH.receiveInUse _ aH.receiveInUse - 1; ENDCASE => Glitch[DontKnowHowToAllocateBuffer]; totalSendAndReceiveBuffersInUse _ totalSendAndReceiveBuffersInUse - 1; BROADCAST aH.bufferAvailable; END; enqueue[systemBufferQueue, b]; BROADCAST systemFreeQueueNotEmpty; END; BuffersLeft: PUBLIC ENTRY PROCEDURE [aH: BufferAccessHandle] RETURNS [left: CARDINAL] = BEGIN IF CommFlags.doDebug AND useCount = 0 THEN Glitch[FreeQueueNotInitialized]; IF CommFlags.doDebug AND aH.seal # DriverTypes.bufferPoolSeal THEN Glitch[PoolSealBroken]; IF CommFlags.doDebug AND aH.firstBuffer = NIL THEN Glitch[BufferPoolNotInitialized]; IF aH = systemAccessHandle THEN BEGIN reserved: CARDINAL = SendAndReceiveBuffersInFreeQueue[] + totalReserveBuffers; IF CommFlags.doDebug AND useCount = 0 THEN Glitch[FreeQueueNotInitialized]; left _ systemBufferQueue.length; left _ (IF left > reserved THEN left - reserved ELSE 0); END ELSE BEGIN left _ aH.send + aH.receive - aH.sendInUse - aH.receiveInUse; END; END; SendBuffersLeft: PUBLIC ENTRY PROCEDURE [aH: BufferAccessHandle] RETURNS [CARDINAL] = BEGIN IF CommFlags.doDebug AND useCount = 0 THEN Glitch[FreeQueueNotInitialized]; IF CommFlags.doDebug AND aH.seal # DriverTypes.bufferPoolSeal THEN Glitch[PoolSealBroken]; IF CommFlags.doDebug AND aH.firstBuffer = NIL THEN Glitch[BufferPoolNotInitialized]; RETURN[aH.send - aH.sendInUse]; END; -- SendBufferLeftInPool ReceiveBuffersLeft: PUBLIC ENTRY PROCEDURE [aH: BufferAccessHandle] RETURNS [CARDINAL] = BEGIN IF CommFlags.doDebug AND useCount = 0 THEN Glitch[FreeQueueNotInitialized]; IF CommFlags.doDebug AND aH.seal # DriverTypes.bufferPoolSeal THEN Glitch[PoolSealBroken]; IF CommFlags.doDebug AND aH.firstBuffer = NIL THEN Glitch[BufferPoolNotInitialized]; RETURN[aH.receive - aH.receiveInUse]; END; -- ReceiveBufferLeftInPool EnumerateBuffersInPool: PUBLIC PROCEDURE [ pool: BufferAccessHandle, proc: PROCEDURE [Buffer]] = BEGIN b: BufferDefs.Buffer; IF CommFlags.doDebug AND useCount = 0 THEN Glitch[FreeQueueNotInitialized]; b _ pool.firstBuffer; IF CommFlags.doDebug AND pool.seal # DriverTypes.bufferPoolSeal THEN Glitch[PoolSealBroken]; FOR i: CARDINAL IN [0..pool.total) DO proc[b]; b _ b + pool.wordsPerBuffer; ENDLOOP; END; -- EnumerateBuffersInPool GetFreePupBuffer: PUBLIC PROCEDURE RETURNS [PupBuffer] = BEGIN RETURN[ LOOPHOLE[GetFreeBuffer[pup, systemAccessHandle, systemUse], PupBuffer]]; END; GetClumpOfPupBuffers: PUBLIC ENTRY PROCEDURE [ q: Queue, n: CARDINAL, wait: BOOLEAN] = BEGIN ENABLE UNWIND => NULL; IF CommFlags.doDebug AND useCount = 0 THEN Glitch[FreeQueueNotInitialized]; IF CommFlags.doDebug AND q.seal # DriverTypes.queueSeal THEN Glitch[QueueSealBroken]; UNTIL systemBufferQueue.length > n + SendAndReceiveBuffersInFreeQueue[] + totalReserveBuffers DO IF ~wait THEN RETURN; WAIT systemFreeQueueNotEmpty; ENDLOOP; THROUGH [0..n) DO b: PupBuffer _ DequeuePup[systemBufferQueue]; b.type _ pup; b.pupType _ data; IF CommFlags.doDebug THEN b.debug _ CommUtilDefs.GetReturnFrame[].accesslink; EnqueuePup[q, b]; ENDLOOP; END; QueueInitialize: PUBLIC PROCEDURE [q: Queue] = BEGIN q^ _ [length: 0, first: NIL, last: NIL, seal: DriverTypes.queueSeal]; END; QueueCleanup: PUBLIC PROCEDURE [q: Queue] = BEGIN b: Buffer; UNTIL (b _ Dequeue[q]) = NIL DO ReturnFreeBuffer[b]; ENDLOOP; END; ExtractPupFromQueue: PUBLIC PROCEDURE [Queue, PupBuffer] RETURNS [PupBuffer] = LOOPHOLE[ExtractFromQueue]; ExtractOisFromQueue: PUBLIC PROCEDURE [Queue, OisBuffer] RETURNS [OisBuffer] = LOOPHOLE[ExtractFromQueue]; ExtractSppFromQueue: PUBLIC PROCEDURE [Queue, SppBuffer] RETURNS [SppBuffer] = LOOPHOLE[ExtractFromQueue]; ExtractFromQueue: PUBLIC PROCEDURE [q: Queue, b: Buffer] RETURNS [Buffer] = BEGIN previousB, currentB: Buffer; IF q = NIL THEN Glitch[QueueScrambled]; IF CommFlags.doDebug AND q.seal # DriverTypes.queueSeal THEN Glitch[QueueSealBroken]; IF CommFlags.doDebug AND b.seal # DriverTypes.bufferSeal THEN Glitch[BufferSealBroken]; previousB _ NIL; currentB _ q.first; UNTIL currentB = b DO IF currentB = NIL THEN EXIT; previousB _ currentB; currentB _ currentB.next; ENDLOOP; IF currentB # NIL THEN BEGIN IF CommFlags.doDebug AND currentB.seal # DriverTypes.bufferSeal THEN Glitch[BufferSealBroken]; IF currentB = q.first THEN q.first _ currentB.next; IF currentB = q.last THEN q.last _ previousB; IF previousB # NIL THEN previousB.next _ currentB.next; q.length _ q.length - 1; currentB.queue _ NIL; currentB.next _ NIL; IF CommFlags.doStats THEN StatsDefs.StatIncr[statXqueue]; END ELSE IF CommFlags.doStats THEN StatsDefs.StatIncr[statXqueueNIL]; RETURN[currentB]; END; EnqueuePup: PUBLIC PROCEDURE [Queue, PupBuffer] = LOOPHOLE[Enqueue]; EnqueueOis: PUBLIC PROCEDURE [Queue, OisBuffer] = LOOPHOLE[Enqueue]; EnqueueSpp: PUBLIC PROCEDURE [Queue, SppBuffer] = LOOPHOLE[Enqueue]; Enqueue: PUBLIC PROCEDURE [q: Queue, b: Buffer] = BEGIN IF q = NIL OR b = NIL OR b.queue # NIL THEN Glitch[QueueScrambled]; IF CommFlags.doDebug AND q.seal # DriverTypes.queueSeal THEN Glitch[QueueSealBroken]; IF CommFlags.doDebug AND b.seal # DriverTypes.bufferSeal THEN Glitch[BufferSealBroken]; IF CommFlags.doDebug AND q.length # 0 AND (q.first = NIL OR q.last = NIL) THEN Glitch[QueueScrambled]; IF CommFlags.doDebug AND q.length > 256 THEN Glitch[QueueScrambled]; b.next _ NIL; IF CommFlags.doStats THEN StatsDefs.StatIncr[statEnqueue]; IF q.first = NIL THEN q.first _ b ELSE q.last^.next _ b; q.last _ b; b.queue _ q; q.length _ q.length + 1; END; -- Enqueue DequeuePup: PUBLIC PROCEDURE [Queue] RETURNS [PupBuffer] = LOOPHOLE[Dequeue]; DequeueOis: PUBLIC PROCEDURE [Queue] RETURNS [OisBuffer] = LOOPHOLE[Dequeue]; DequeueSpp: PUBLIC PROCEDURE [Queue] RETURNS [SppBuffer] = LOOPHOLE[Dequeue]; Dequeue: PUBLIC PROCEDURE [q: Queue] RETURNS [b: Buffer] = BEGIN IF q = NIL THEN Glitch[QueueScrambled]; IF CommFlags.doDebug AND q.seal # DriverTypes.queueSeal THEN Glitch[QueueSealBroken]; IF (b _ q.first) = NIL THEN BEGIN IF CommFlags.doDebug AND q.length # 0 THEN Glitch[QueueScrambled]; IF CommFlags.doStats THEN StatsDefs.StatIncr[statDequeueNIL]; RETURN; END; IF (q.first _ q.first.next) = NIL THEN q.last _ NIL; IF CommFlags.doDebug AND q.length > 256 THEN Glitch[QueueScrambled]; q.length _ q.length - 1; IF CommFlags.doStats THEN StatsDefs.StatIncr[statDequeue]; IF b.queue # q THEN Glitch[QueueScrambled]; b.queue _ NIL; b.next _ NIL; IF CommFlags.doDebug AND b.seal # DriverTypes.bufferSeal THEN Glitch[BufferSealBroken]; IF CommFlags.doDebug AND q.length # 0 AND (q.first = NIL OR q.last = NIL) THEN Glitch[QueueScrambled]; END; -- Dequeue systemBufferQueue _ NEW[QueueObject]; QueueInitialize[systemBufferQueue]; Process.InitializeCondition[ CommUtilDefs.MaybeShorten[@systemFreeQueueNotEmpty], Process.MsecToTicks[ 1000]]; IF CommFlags.doDebug THEN BEGIN GetGiantVector[].firstBuffer _ NIL; GetGiantVector[].freeQueue _ systemBufferQueue; END; END. *BufferMgr.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. BLyon on: March 19, 1981 12:37 PM HGM on: March 17, 1981 6:32 PM Garlick on: January 26, 1981 1:52 PM Levin, August 9, 1983 9:27 am Taft, February 4, 1984 2:37:41 pm PST Russ Atkinson (RRA) February 2, 1985 3:49:15 pm PST EXPORTed TYPEs monitor protected data the raw buffer data length that drivers need to know (includes encapsulation words) Buffers and IOCB locations must be rounded up for alignment constraints. Alto SLA Microcode needs IOCB/LCB to be EVEN. D0 Ethernet/Xwire Microcode needs IOCB to be Quad word aligned, and first data word to be (almost?) QUAD word aligned. size of a buffer without any data 1 extra for pup checksum for the Glitches Cold Procedures NB: wordsPerBuffer and wordsPerIocb MUST be QuadWord multiples number of send type buffer that can be allocated from this pool (could be greater than total) number of receive type buffer that can be allocated from this pool (could be greater than total) number of send type buffer that can be allocated from this pool (could be greater than total) insert this accessObject into the linked list of known accessObjects kludgy, but lets us do sanity check for nil values 2 for checksum, 4 for end test, 3 for round down systemBufferSize is a little bigger because of the quad word allignment This determines the buffer alignment: see DriverTypes.Encapsulation this does NOT align each individual iocb remove this accessObject from the linked list of known accessObjects Heap.FreeNode[p: p]; before conversion to REFs. (ADB). since sends are asynchronous, don't free the pool until they are completed Cool Procedures This is not an ENTRY procedure because we assume that systemBufferPool can have its parameters set only once. This is not an ENTRY procedure because we assume that systemBufferPool can have its parameters set only once. This is not an ENTRY procedure because we assume that systemBufferPool can have its parameters set only once. This is not an ENTRY procedure because we assume that systemBufferPool can have its parameters set only once. Hot Procedures This routine is only used by device drivers to get buffers to read things into. NB: b.length is setup for the size of the buffer, including ALL of the encapsulation. All device drivers except for the XWire must fudge things themsleves, since they do not use all of the encapsulation field. since the drivers only use the buffers for a short time, no access control is used in their allocation; a filled buffer will be subject to usual access control when it is delivered; therefore if we have a buffer the drivers can have it. Get free buffer, but don't wait if there is none NB: These will return the last buffer, use with caution credits may be used to avoid copying buffers Note: we do some "initialization" of things here since there are several ways to get buffers from the freeQueue. This is ugly, but there isn't any way to make things work without it, if 2 PROCESSes are waiting for buffers. Get free buffer, but don't wait if there is none NB: These will return the last buffer, use with caution Queue Manipulation Routines Put all buffers back onto buffer pool's freeQueue remove this buffer from the queue initialization systemAccessHandle _ MakeBufferPool[total: 0, send: 0, receive: 0, reserve: 0, forSystemUse: TRUE]; Κ‰˜codešœ™Kšœ Οmœ1™™>K˜š œžœžœž œ˜(KšœžœŸ8˜IKšœžœ˜Kšœ`™`Kšœ žœ˜Kšœc™cKšœ žœ˜Kšœ`™`šœžœŸ ˜7Kšžœ˜!—Kšž˜K˜ KšœŸ žœžœžœ˜*Kšœžœ˜ Kšœžœ˜šžœžœž˜Kšž˜K˜IKšžœ˜—K˜4K˜Kšœžœ˜K˜$Kšœ žœ˜K˜K˜ K˜K˜/K˜K˜K˜KšœD™DK˜K˜KšžœžœM˜f˜K˜K—šžœ ž˜Kšž˜Kšœžœ˜Kšœ2™2Kšžœ˜Kšžœ˜—Kšœ0™0K˜Cšžœžœž˜6Kšœ)žœ˜1—KšœG™G˜Kšœ'žœžœ˜=—Kšžœžœ'˜Cšž˜šžœ(ž˜.K˜!——K˜IKšœC™Cšž˜Kšœžœžœ6˜LKšžœžœ žœžœ˜,Kšœ"˜"Kšžœ˜—K˜šžœžœ ž˜Kšœžœ˜Kšœžœ˜$K˜ K˜K˜Kšœ žœ˜K˜ Kšœ žœ˜ Kšžœžœ!˜:K˜&K˜K˜Kšžœ˜—šžœž˜Kšž˜K˜šžœžœ ž˜Kšœ(™(K˜6K˜Kšžœ˜—Kšžœ˜—Kšžœ˜K˜—š œž œ˜žœ˜G—˜ Kšž˜K˜&K˜Kšžœ˜—Kšžœ(˜/—šžœž˜Kšœ&žœ˜FKšžœ%˜)—šžœ'ž˜.Kšžœžœ˜!—K˜.K˜Fšžœ ž˜'Kšžœžœ˜&—Kšžœ˜—K˜Kšžœžœžœžœ˜=K˜1K˜Kšžœžœ4˜MKšžœ˜K˜—Kšœ0™0Kšœ7™7K˜š œžœžœž œ˜,K˜EKšžœ˜Kšž˜Kšžœžœžœ!˜Kšžœžœ&ž˜BK˜—Kšžœžœžœžœ"˜Tšžœž˜Kšž˜šžœ@ž˜FKšž˜Kšœžœ˜Kšžœžœ%˜>Kšžœ˜Kšžœ˜—Kšžœžœžœ%˜VKšž˜—šž˜Kšž˜Kš œžœžœžœžœ˜-Kšœžœ˜šžœ ž˜˜Kšžœ>žœ˜G—˜ Kšž˜K˜&K˜Kšžœ˜—Kšžœ(˜/—šžœ(žœ˜KKšž˜Kšž˜Kšœžœ˜Kšžœžœ%˜>Kšžœ˜Kšžœ˜—K˜.K˜FKšžœ˜—Kšžœ$žœžœ˜FK˜1K˜Kšžœžœ4˜MKšžœ˜K˜—Kšœ,™,K˜š œžœžœž œ˜0Kšœ&žœžœ˜EKšž˜š žœžœžœžœžœž˜@K˜!—šžœžœ&ž˜BK˜—šžœ-ž˜3Kšž˜K˜&K˜FK˜K˜Kšž˜—šž˜Kšžœžœ%˜>—Kšžœ˜K˜—Kš   œž œžœ žœžœžœ˜?K˜Kš œžœž œžœ˜OKš œžœž œžœ˜OKš œžœž œžœ˜Oš œžœžœž œ˜6Kšž˜K˜(Kšžœžœžœ!˜KKšžœžœžœžœ"˜TKšœT™TKšœ™K˜&KšœŸ%˜Ašžœž˜Kšž˜šžœ ž˜K˜(K˜1Kšžœ(˜/—K˜FKšž œ˜Kšžœ˜—K˜KšœJ™JKšœ"™"Kšž œ˜"Kšžœ˜K˜—š  œžœžœž œ˜