DriverImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Hal Murray, May 4, 1986 8:58:25 pm PDT
DIRECTORY
Driver USING [Buffer, BufferObject, Network, wordsInIocb],
Process USING [Detach, priorityBackground, SetPriority],
SafeStorage USING [EnableFinalization, EstablishFinalization, FinalizationQueue, FQNext, NewFQ, PinObject],
VM USING [lowCore];
DriverImpl: CEDAR MONITOR
IMPORTS Process, SafeStorage, VM
EXPORTS Driver = {
Buffer: TYPE = Driver.Buffer;
Network: TYPE = Driver.Network;
IOCB: TYPE = ARRAY [0..Driver.wordsInIocb) OF WORD;
Next: PROC [b: Driver.Buffer] RETURNS [Driver.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 { buffer.ovh.next ← NIL; RETURN; };
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[Driver.BufferObject];
SafeStorage.PinObject[buffer];
TRUSTED {
iocb: LONG POINTER TO IOCB ← LOOPHOLE[VM.lowCore.NEW[IOCB]];
buffer.ovh.iocb ← iocb;
iocb^ ← ALL[0]; };
CountNewBuffer[buffer];
buffer.ovh.next ← NIL;
SafeStorage.EnableFinalization[buffer];
};
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] = {
b.ovh.next ← buffers;
IF b.ovh.socket # NIL THEN ERROR;
TRUSTED { buffers ← NARROW[LOOPHOLE[b, REF ANY]]; };
freeBuffers ← freeBuffers.SUCC;
};
Discard unwanted packets
This lives here since this module is already reasonably hot.
NoThankYou: PUBLIC PROC [network: Network, b: Buffer, bytes: NAT] RETURNS [Buffer] = {
RETURN[b]; };
Finalization
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[Driver.BufferObject], npr: 0, fq: bfq];
TRUSTED { Process.Detach[FORK BufferFinalizer[]]; };
}.