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[]]; }; }. ๘CommDriverImpl.mesa Copyright c 1986 by Xerox Corporation. All rights reserved. Hal Murray, May 29, 1986 2:26:51 am PDT Doug Wyatt, June 10, 1986 2:04:15 pm PDT Buffer allocation This is where buffers actually get created. Beware: D0s and DLions have buffer alignment constraints. If anybody wants to run this code on D0s, the microcode should be fixed. DLions (luckily) only require that the first 3 words of the buffer be on the same page. For now, a BufferObject is big enough so that the Allocator gives each one a separate clump of pages. If that ever changes, don't be surprised by obscure troubles. Discard unwanted packets This lives here since this module is already reasonably hot. NSImpl - Host Number Manipulations - this lives here to save a GFI BEWARE. Is this byte-order dependent? Not if ProcessorFace.ProcessorID guaranteed to be stored in the same format as an XNS.Host on the wire, but who knows ... IOExtrasImpl - Extensions to IO for Endian - this lives here to save a GFI Finalization ส/˜codešœ™Kšœ ฯmœ1™Jšœ žœ˜"Jšžœžœ ž œ ˜?Jšœ žœ˜Jšœžœฯc ˜8Jšœžœ+˜8Kšœžœ˜"Kšœ žœZ˜kJšžœžœ ˜Kšžœžœ˜K˜—šฯnœžœž˜Kšžœžœ'ž˜IKšžœžœ˜%K˜Kšœžœ˜!Kšœ žœ˜#Kš žœžœžœžœžœ˜7K˜š  œžœ žœ žœžœ˜:Kšžœžœ˜ K˜——head™Kšœžœ˜K˜Kšœžœ˜Kšœžœ˜Kšœ žœ˜š  œžœžœžœ˜5Kšœ˜šžœ žœžœ˜Kšœ, œ๘™ชKšœ žœ˜&Kšœ˜šžœ˜ Kšœžœžœžœžœžœ žœžœ˜