DispatcherImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
BLyon on: March 21, 1981 10:47 AM
DIRECTORY
BufferDefs USING [Buffer, Dequeue, Enqueue, Queue, QueueCleanup, QueueInitialize, QueueLength, QueueObject],
CommFlags USING [doStats, doDebug],
DriverDefs USING [GetGiantVector, Network, ReturnFreeBuffer, Router, RouterObject],
Process USING [SetTimeout, MsecToTicks],
SpecialCommunication USING [SpyProc],
StatsDefs USING [StatIncr];
DispatcherImpl: MONITOR
IMPORTS BufferDefs, DriverDefs, Process, StatsDefs
EXPORTS BufferDefs, DriverDefs, SpecialCommunication
SHARES BufferDefs = BEGIN
EXPORTed TYPEs
Network: PUBLIC TYPE = DriverDefs.Network;
mainFork: PROCESS;
dispatcherPleaseDie: BOOLEAN;
dispatcherReady: CONDITION;
globalInputQueue: BufferDefs.Queue = NEW[BufferDefs.QueueObject];
globalOutputQueue: BufferDefs.Queue = NEW[BufferDefs.QueueObject];
pupRouter, oisRouter: PUBLIC DriverDefs.Router;
dummyRouter: DriverDefs.Router;
dummyRouterObject: DriverDefs.RouterObject ←
[input: DummyInputer, broadcast: DummyBroadcaster, addNetwork: DummyAddDelete,
removeNetwork: DummyAddDelete, stateChanged: DummyStateChanged];
interface of peeking
bufferSpy: SpecialCommunication.SpyProc ← NIL;
Cold procedures
SetSpyProc: PUBLIC PROCEDURE [spy: SpecialCommunication.SpyProc] =
BEGIN bufferSpy ← spy; END;
DummyInputer: PROCEDURE [b: BufferDefs.Buffer] =
BEGIN
IF CommFlags.doStats THEN StatsDefs.StatIncr[statPacketsDiscarded];
b.requeueProcedure[b];
END;
DummyBroadcaster: PROCEDURE [b: BufferDefs.Buffer] =
BEGIN b.requeueProcedure[b]; END;
DummyAddDelete: PROCEDURE [Network] = BEGIN END;
DummyStateChanged: PROCEDURE [Network] = BEGIN END;
SetPupRouter: PUBLIC PROCEDURE [router: DriverDefs.Router] =
BEGIN
IF router = NIL THEN router ← @dummyRouterObject;
pupRouter ← router;
END;
SetOisRouter: PUBLIC PROCEDURE [router: DriverDefs.Router] =
BEGIN
IF router = NIL THEN router ← @dummyRouterObject;
oisRouter ← router;
END;
GetPupRouter: PUBLIC PROCEDURE RETURNS [DriverDefs.Router] =
BEGIN RETURN[pupRouter]; END;
GetOisRouter: PUBLIC PROCEDURE RETURNS [DriverDefs.Router] =
BEGIN RETURN[oisRouter]; END;
DispatcherOn: PUBLIC PROCEDURE =
BEGIN
bufferSpy ← NIL;
dispatcherPleaseDie ← FALSE;
BufferDefs.QueueInitialize[globalInputQueue];
BufferDefs.QueueInitialize[globalOutputQueue];
mainFork ← FORK MainDispatcher[];
END;
DispatcherOff: PUBLIC PROCEDURE =
BEGIN
DispatcherOffLocked[];
JOIN mainFork;
BufferDefs.QueueCleanup[globalInputQueue];
BufferDefs.QueueCleanup[globalOutputQueue];
END;
DispatcherOffLocked: ENTRY PROCEDURE = INLINE
BEGIN dispatcherPleaseDie ← TRUE; NOTIFY dispatcherReady; END;
Hot procedures
MainDispatcher: PUBLIC PROCEDURE =
BEGIN
b: BufferDefs.Buffer;
network: Network;
UNTIL dispatcherPleaseDie DO
WHILE BufferDefs.QueueLength[globalOutputQueue] # 0 DO
give back free buffers first
b ← GrabOutputBuffer[];
IF b.allNets THEN SendToNextNetwork[b] ELSE b.requeueProcedure[b];
ENDLOOP;
IF BufferDefs.QueueLength[globalInputQueue] # 0 THEN
BEGIN
b ← GrabInputBuffer[];
IF (bufferSpy = NIL) OR bufferSpy[b] THEN
BEGIN
network ← b.network;
give it to the right router, and it requeues the buffer
SELECT network.decapsulateBuffer[b] FROM
pup =>
BEGIN
b.type ← pup;
pupRouter.input[b];
END;
ois =>
BEGIN
b.type ← ois;
oisRouter.input[b];
END;
rejected => dummyRouter.input[b];
processed => NULL;
ENDCASE => ERROR; -- UnknownDecapsulation
END; -- end of process input buffer clause
LOOP;
END; -- end of input queue not empty clause
Wait[];
ENDLOOP;
END;
GrabOutputBuffer: ENTRY PROCEDURE RETURNS [BufferDefs.Buffer] = INLINE
BEGIN RETURN[BufferDefs.Dequeue[globalOutputQueue]]; END;
GrabInputBuffer: ENTRY PROCEDURE RETURNS [BufferDefs.Buffer] = INLINE
BEGIN RETURN[BufferDefs.Dequeue[globalInputQueue]]; END;
Wait: ENTRY PROCEDURE = INLINE
BEGIN
IF BufferDefs.QueueLength[globalInputQueue] = 0 AND BufferDefs.QueueLength[
globalOutputQueue] = 0 THEN WAIT dispatcherReady;
END;
SendToNextNetwork: PROCEDURE [b: BufferDefs.Buffer] =
BEGIN
network: Network ← b.network;
b.network ← network ← network.next;
dangerous we are playing with monitor data
IF network = NIL THEN
BEGIN
b.allNets ← FALSE; -- this is where it gets turned off
b.requeueProcedure[b];
RETURN;
END;
SELECT b.type FROM
pup =>
BEGIN
pupRouter.broadcast[b]; -- this requeues b
END;
ois =>
BEGIN
oisRouter.broadcast[b]; -- this requeues b
END;
ENDCASE => ERROR; -- dispatcher only sends out pups or ois's
END;
Locked procedures
These are called from interrupt routines on the Alto; they must be locked in memory.
PutOnGlobalInputQueue: PUBLIC ENTRY PROCEDURE [b: BufferDefs.Buffer] =
BEGIN BufferDefs.Enqueue[globalInputQueue, b]; NOTIFY dispatcherReady; END;
PutOnGlobalDoneQueue: PUBLIC PROCEDURE [b: BufferDefs.Buffer] =
BEGIN
This test avoids an unnecessary process switch in returning buffers to system pool.
IF ~b.allNets AND b.requeueProcedure = DriverDefs.ReturnFreeBuffer THEN
DriverDefs.ReturnFreeBuffer[b]
ELSE PutOnGlobalDoneQueueLocked[b];
END;
PutOnGlobalDoneQueueLocked: ENTRY PROCEDURE [b: BufferDefs.Buffer] = INLINE
BEGIN BufferDefs.Enqueue[globalOutputQueue, b]; NOTIFY dispatcherReady; END;
initialization
pupRouter ← @dummyRouterObject;
oisRouter ← @dummyRouterObject;
dummyRouter ← @dummyRouterObject;
Process.SetTimeout[@dispatcherReady, Process.MsecToTicks[30000]];
IF CommFlags.doDebug THEN
BEGIN
DriverDefs.GetGiantVector[].globalInputQueue ← globalInputQueue;
DriverDefs.GetGiantVector[].globalOutputQueue ← globalOutputQueue;
END;
END. -- DispatcherImpl module
LOG
Time: April 21, 1980 2:56 PM By: Dalal Action: created file for Pilot 5.0.
Time: April 21, 1980 2:57 PM By: Dalal Action: merged the dispatchers.
Time: May 7, 1980 10:34 AM By: BLyon Action: Made pupRouter & oisRouter PUBLIC (they are used by Boss).
Time: May 8, 1980 1:24 PM By: BLyon Action: Made PutOnGlobalDoneQueue more efficient (hopefully it still works).