-- File: QueueCold.mesa, Last Edit: HGM November 12, 1979 6:01 PM

-- Copyright Xerox Corporation 1979, 1980

DIRECTORY
InlineDefs: FROM "InlineDefs" USING [BITAND, LowHalf],
CommUtilDefs: FROM "CommUtilDefs" USING [
AllocateHyperspace, FreeHyperspace, LockData, UnlockData,
AllocateIocbs, FreeIocbs,
GlobalFrame, SetTimeout, MsecToTicks],
DriverDefs: FROM "DriverDefs" USING [
freeQueue, firstBuffer, bufferSize,
useCount, giantVector, doDebug, Glitch,
QueueCool, QueueIn, QueueOut],
PupStream: FROM "PupStream", -- EXPORTS
PupDefs: FROM "PupDefs", -- EXPORTS
BufferDefs: FROM "BufferDefs" USING [
defaultBufferPoolSize, defaultDataWordsPerBuffer,
Buffer, BufferObject, Dequeue, Enqueue, ReturnFreeBuffer,
QueueInitialize, QueueCleanup],
DriverTyp
es: FROM "DriverTypes" USING [bufferSeal];

QueueCold: MONITOR LOCKS freeQueueLock
IMPORTS InlineDefs, CommUtilDefs, DriverDefs, BufferDefs
EXPORTS DriverDefs, PupStream, PupDefs, BufferDefs
SHARES BufferDefs =
BEGIN OPEN DriverDefs, BufferDefs;


freeQueueLock: PUBLIC MONITORLOCK;
freeQueueNotEmpty: PUBLIC CONDITION;
numberOfBuffers: PUBLIC CARDINAL ← BufferDefs.defaultBufferPoolSize;
dataWordsPerBuffer: PUBLIC CARDINAL ← BufferDefs.defaultDataWordsPe
rBuffer;
wordsPerIocb: PUBLIC CARDINAL ← 0;

-- Buffers and IOCB locations must be rounded up for alignment constraints. A
lto SLA Microcode needs IOCB/LCB to be EVEN. We round things up to a Quad word just in case.

-- size of a buffer without any data
rawOverhead: CARDINAL = SIZE[raw BufferDefs.BufferObject];
-- 1 extra for checksum
pupOverhead: CARDINAL = SIZE[pupWords pup BufferDefs.BufferObject]+1;
overhead: CARDINAL = MAX[
pupOverhead,
SIZE[rppWords rpp BufferDefs.BufferObject]+1];

CantResetWhileActive: PUBLIC ERROR = CODE;

AdjustBufferParms: PUBLIC ENTRY PROCEDURE [bufferPoolSize, bufferSize: CARDINAL] =
BEGIN
IF useCount#0 THEN Glitch[CantResetWhileActive];
IF bufferPoolSize#0 THEN numberOfBuffers ← bufferPoolSize;
IF bufferSize#0 TH
EN dataWordsPerBuffer ← bufferSize;
EN
D;

GetBufferParms: PUBLIC PROCEDURE RETURNS [bufferPoolSize, bufferSize: CARDINAL] =
BEGIN
RETURN[n
umberOfBuffers,dataWordsPerBuffer];
END;

-- NB: wordsPerBuffer
and wordsPerIocb MUST be QuadWord multiples
FreeQueueMake: PUBLIC PROCEDURE =
BEGIN
b: Buffer;
x: POINTER TO BufferObject = LOOPHOLE[6]; -- anything to avoid NIL trap
i: CARDINAL;
wordsPerBuffer: CARDINAL;
wordsPerBuffer ← dataWordsPerBuffer+overhead;
UNTIL InlineDefs.BITAND[wordsPerBuffer,3]=0 DO
wordsPerBuffer ← wordsPerBuffer+1;
ENDLOOP;
bufferSize ← wordsPerBuffer-(@x.encapsulation-LOOPHOLE[x,POINTER]);
firstBuffer ← CommUtilDefs.AllocateHyperspace[wordsPerBuffer*numberOfBuffers+3];
UNTIL InlineDefs.BITAND[InlineDefs.LowHalf[@firstBuffer.encapsulation],3]=0 DO
firstBuffer ← firstBuffer+1;
ENDLOOP;
IF doDebug THEN
BEGIN
giantVector.firstBuffer ← firstBuffer;
giantVector.wordsPerBuffer ← wordsPerBuffer;
giantVector.bufferPoolSize ← numberOfBuffers;
END;
CommUtilDefs.LockData[firstBuffer];
QueueInitialize[@freeQueue];
b ← firstBuffer;
FOR i IN [0..numberOfBuffers) DO
b.iocbChain ← b.userData ← NIL;
b.allNets ← b.bypassZeroNet ← FALSE;
b.type ← raw;
b.size ← big;
b.pupLength ← b.length ← 0;
b.bufferNumber ← i;
b.pupType ← pt177;
b.queue ← NIL;
b.pool ← NIL;
b.next ← NIL;
IF doDebug THEN b.seal ← DriverTypes.bufferSeal;
b.requeueProcedure ← ReturnFreeBuffer;
Enqueue[@freeQueue,b];
b ← b+wordsPerBuffer;
ENDLOOP;
IF wordsPerIocb#0 THEN
BEGIN
iocb: LONG POINTER;
iocb ← CommUtilDefs.AllocateIocbs[wordsPerIocb*numberOfBuffers+3];
b ← firstBuffer;
FOR i IN [0..numberOfBuffers) DO
-- this does NOT align each individual iocb
b.iocbChain ← iocb;
iocb ← iocb+wordsPerIocb;
b ← b+word
sPerBuffer;
ENDLOOP;
END;
END;

FreeQueueDestroy: PUBLIC PROCEDURE =
BEGIN
UNTIL Dequeue[@freeQueue]=NIL DO ENDLOOP;
QueueCleanup[@freeQueue];
CommUtilDefs.UnlockData[firstBuffer];
IF firstBuffer.iocbChain#NIL THEN CommUtilDefs.FreeIocbs[firstBuffer.iocbChain];
CommUtilDefs.FreeHyperspace[firstBuffer];
IF doDebug THEN
BEGIN
firstBuffer ← NIL;
giantVector.firstBuffer ← NIL;
END;
END;

-- initialization
CommUtilDefs.SetTimeout[@freeQueueNotEmpty,CommUtilDefs.MsecToTicks[10000]];
START DriverDefs.QueueCool;
START DriverDefs.QueueIn;
-- Argh, QueueLocked, or QueueLockedTiny
START LOOPHOLE[CommUtilDefs.GlobalFrame[Enqueue],PROGRAM];
START DriverDefs.QueueOut;
IF doDebug THEN
BEGIN
giantVector.firstBuffer ← NIL;
giantVector.freeQueue ← @freeQueue;
END;
END. -- QueueCold