<> <> <> <> <> <> <> <> 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; <<1 extra for pup checksum>> 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; <<2 for checksum, 4 for end test, 3 for round down>> 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.