<> <> <> <> DIRECTORY Basics USING [BITAND], Endian USING [bytesPerFWord, bytesPerHWord, FWORD, HWORD], CommBufferExtras USING [gapFreeList, gapNoList], CommDriver USING [Buffer, BufferObject, Network, wordsInIocb], DebuggerSwap USING [CallDebugger], IO USING [EndOfStream, STREAM, UnsafeGetBlock, UnsafePutBlock], IOExtras USING [], PrincOpsUtils USING [], -- Needed by Process.SetPriority Process USING [Detach, priorityBackground, SetPriority], ProcessorFace USING [processorID], SafeStorage USING [EnableFinalization, EstablishFinalization, FinalizationQueue, FQNext, NewFQ, PinObject], VM USING [lowCore], XNS USING [Host]; CommDriverImpl: CEDAR MONITOR IMPORTS Basics, DebuggerSwap, IO, Process, ProcessorFace, SafeStorage, VM EXPORTS CommDriver, IOExtras, XNS = { Buffer: TYPE = CommDriver.Buffer; Network: TYPE = CommDriver.Network; IOCB: TYPE = ARRAY [0..CommDriver.wordsInIocb) OF WORD; Next: PROC [b: Buffer] RETURNS [Buffer] = TRUSTED INLINE { RETURN[LOOPHOLE[b.ovh.next]]; }; <> buffers: Buffer _ NIL; totalBuffersCreated: INT _ 0; totalBuffersAlloced: INT _ 0; freeBuffers: INT _ 0; AllocBuffer: PUBLIC PROC RETURNS [buffer: Buffer] = { buffer _ AllocBufferInner[]; IF buffer = NIL THEN { <> buffer _ NEW[CommDriver.BufferObject]; SafeStorage.PinObject[buffer]; TRUSTED { iocb: LONG POINTER TO IOCB _ LOOPHOLE[VM.lowCore.NEW[IOCB]]; buffer.ovh.iocb _ iocb; iocb^ _ ALL[0]; }; CountNewBuffer[buffer]; SafeStorage.EnableFinalization[buffer]; }; buffer.ovh.next _ NIL; buffer.ovh.gap _ CommBufferExtras.gapNoList; -- DKW: not on any list }; AllocBufferInner: PUBLIC ENTRY PROC RETURNS [buffer: Buffer] = { IF buffers = NIL THEN RETURN[NIL]; buffer _ buffers; buffers _ Next[buffers]; totalBuffersAlloced _ totalBuffersAlloced.SUCC; freeBuffers _ freeBuffers.PRED; }; CountNewBuffer: PUBLIC ENTRY PROC [buffer: Buffer] = { totalBuffersCreated _ totalBuffersCreated.SUCC; totalBuffersAlloced _ totalBuffersAlloced.SUCC; }; FreeBuffer: PUBLIC ENTRY PROC [b: Buffer] = { TRUSTED { b _ NARROW[LOOPHOLE[b, REF ANY]]; }; -- check that runtime type is correct IF b.ovh.socket # NIL THEN ERROR; IF b.ovh.gap#CommBufferExtras.gapNoList THEN DebuggerSwap.CallDebugger["Buffer freed while in a list!"]; b.ovh.next _ buffers; buffers _ b; b.ovh.gap _ CommBufferExtras.gapFreeList; -- DKW: buffer now on the free list freeBuffers _ freeBuffers.SUCC; }; <> <> NoThankYou: PUBLIC PROC [network: Network, b: Buffer, bytes: NAT] RETURNS [Buffer] = { RETURN[b]; }; <> GetThisHost: PUBLIC PROC RETURNS [XNS.Host] ~ { <> TRUSTED { RETURN[LOOPHOLE[ProcessorFace.processorID]]; }; }; IsMulticastHost: PUBLIC PROC [host: XNS.Host] RETURNS [BOOL] ~ { RETURN [Basics.BITAND[host.a, 1] # 0 ]; }; <> GetHWord: PUBLIC PROC [self: IO.STREAM] RETURNS [hword: Endian.HWORD] = TRUSTED { bytes: INT; bytes _ IO.UnsafeGetBlock[self, [LOOPHOLE[LONG[@hword]], 0, Endian.bytesPerHWord]]; IF bytes # Endian.bytesPerHWord THEN ERROR IO.EndOfStream[self]; }; PutHWord: PUBLIC PROC [self: IO.STREAM, hword: Endian.HWORD] = TRUSTED { IO.UnsafePutBlock[self, [LOOPHOLE[LONG[@hword]], 0, Endian.bytesPerHWord]]; }; GetFWord: PUBLIC PROC [self: IO.STREAM] RETURNS [fword: Endian.FWORD] = TRUSTED { bytes: INT; bytes _ IO.UnsafeGetBlock[self, [LOOPHOLE[LONG[@fword]], 0, Endian.bytesPerFWord]]; IF bytes # Endian.bytesPerHWord THEN IO.EndOfStream[self]; }; PutFWord: PUBLIC PROC [self: IO.STREAM, fword: Endian.FWORD] = TRUSTED { IO.UnsafePutBlock[self, [LOOPHOLE[LONG[@fword]], 0, Endian.bytesPerFWord]]; }; <> droppedBuffers: INT _ 0; BufferFinalizer: PROC = { Process.SetPriority[Process.priorityBackground]; DO b: Buffer _ NARROW[SafeStorage.FQNext[bfq]]; SafeStorage.EnableFinalization[b]; FreeBuffer[b]; b _ NIL; droppedBuffers _ droppedBuffers.SUCC; ENDLOOP; }; DropTest: PROC [n: NAT _ 100] = { FOR i: NAT IN [0..n) DO [] _ AllocBuffer[]; ENDLOOP; }; bfq: SafeStorage.FinalizationQueue _ SafeStorage.NewFQ[]; SafeStorage.EstablishFinalization[type: CODE[CommDriver.BufferObject], npr: 0, fq: bfq]; TRUSTED { Process.Detach[FORK BufferFinalizer[]]; }; }.