CommDriverImpl.mesa
Copyright © 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
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]]; };
Buffer allocation
buffers: Buffer ← NIL;
totalBuffersCreated: INT ← 0;
totalBuffersAlloced: INT ← 0;
freeBuffers: INT ← 0;
AllocBuffer:
PUBLIC
PROC
RETURNS [buffer: Buffer] = {
buffer ← AllocBufferInner[];
IF buffer =
NIL
THEN {
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.
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;
};
IOExtrasImpl - Extensions to IO for Endian - this lives here to save a GFI
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]];
};
Finalization
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[]]; };