-- File: DispatcherImpl.mesa -- Edited by: BLyon on: March 21, 1981 10:47 AM DIRECTORY BufferDefs USING [ Buffer, Dequeue, Enqueue, 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.QueueObject; globalOutputQueue: 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).