-- File: Boss.mesa - last edit: -- AOF 15-Feb-88 9:56:51 -- SMA 21-May-86 10:44:29 -- HGM 13-Jul-85 22:51:43 -- Copyright (C) 1984, 1985, 1986, 1987, 1988 by Xerox Corporation. All rights reserved. DIRECTORY Buffer USING [DeviceType], Protocol1 USING [ ProtocolFamily, FamilyIndex, Family, Matrices, MatrixRecord, RemoveFamilyMember], CommFlags USING [doStats], CommHeap USING [Create, Destroy], CommunicationInternal USING [ MakeSystemBufferPool, DestroySystemBufferPool, DispatcherOff, DispatcherOn], Driver USING [Glitch, Device], IEEE8023 USING [CreateDefaultEthernetDrivers], EthernetDriverFriends USING [EtherStatsInfo], Process USING [SecondsToTicks, Pause], SpecialCommunication USING [], StatsOps USING [Start, Stop], StatsOpsExtras USING []; Boss: MONITOR IMPORTS CommHeap, CommunicationInternal, Driver, IEEE8023, Process, Protocol1, StatsOps EXPORTS CommunicationInternal, Buffer, Driver, EthernetDriverFriends, Protocol1, StatsOpsExtras = BEGIN -- SemiPublic things for others Device: PUBLIC TYPE = Driver.Device; firstDevice: PUBLIC Device ← NIL; increasedBufferUseCount, useCount: PUBLIC CARDINAL ← 0; state: {off, ready} ← off; -- on is ready with useCount>0 CommPackageNotActive: PRIVATE <<Glitch>> ERROR = CODE; NetworkNonExistent: PUBLIC <<Driver>> ERROR = CODE; << This code is a bit delicate. There are probably many funny cases that won't work correctly. In particular, there is a race condition between adding/deleting a driver and adding/deleting a router. >> AddDeviceToChain: PUBLIC PROC[network: Driver.Device] = BEGIN --Add new drivers to the end of the chain so that the normal --Ethernet driver will be network zero. AddToChainEntry: ENTRY PROC[] = BEGIN tail: Driver.Device ← firstDevice; IF firstDevice = NIL THEN {firstDevice ← network; network.index ← 1} ELSE BEGIN i: CARDINAL ← 1; UNTIL tail.next = NIL DO tail ← tail.next; i ← i + 1; ENDLOOP; tail.next ← network; network.index ← i + 1; END; END; --AddToChainEntry network.next ← NIL; --make sure end of chain is NIL IF state = ready THEN BEGIN AddToChainEntry[]; --link it up network.activateDriver[]; --activate him IF (increasedBufferUseCount > 0) AND (network.changeNumberOfInputBuffers # NIL) THEN network.changeNumberOfInputBuffers[TRUE]; END; END; --AddDeviceToChain ChangeNumberOfInputBuffers: PUBLIC ENTRY PROC[increaseTheBuffers: BOOLEAN] = BEGIN IF state # ready THEN Driver.Glitch[CommPackageNotActive]; IF increaseTheBuffers THEN BEGIN increasedBufferUseCount ← increasedBufferUseCount + 1; IF increasedBufferUseCount > 1 THEN RETURN; END ELSE BEGIN IF increasedBufferUseCount = 0 THEN RETURN; -- donot go negative increasedBufferUseCount ← increasedBufferUseCount - 1; IF increasedBufferUseCount # 0 THEN RETURN; END; FOR net: Driver.Device ← firstDevice, net.next UNTIL net = NIL DO IF net.changeNumberOfInputBuffers = NIL THEN LOOP; net.changeNumberOfInputBuffers[increaseTheBuffers]; ENDLOOP; END; --ChangeNumberOfInputBuffers CommPackageGo: PUBLIC --ENTRY-- PROC = BEGIN UseCount: ENTRY PROC RETURNS[BOOLEAN] = INLINE {RETURN[(useCount ← useCount + 1) > 1]}; extra: CARDINAL ← 0; network: Driver.Device; IF UseCount[] THEN RETURN; --we've already been here state ← ready; --assert the state CommHeap.Create[]; --that exports CommHeap.zone StatsOps.Start[]; --then (maybe) start stats [] ← IEEE8023.CreateDefaultEthernetDrivers[]; --default drivers FOR network ← firstDevice, network.next UNTIL network = NIL DO extra ← extra + network.buffers; ENDLOOP; CommunicationInternal.MakeSystemBufferPool[extra]; --buffers for drivers CommunicationInternal.DispatcherOn[]; --and access to drivers END; --CommPackageGo CommPackageOff: PUBLIC --ENTRY-- PROC = BEGIN UseCount: ENTRY PROC RETURNS[BOOLEAN] = INLINE {RETURN[(useCount ← useCount - 1) # 0]}; IF UseCount[] THEN RETURN; --still more clients FOR network: Driver.Device ← firstDevice, network.next UNTIL network = NIL DO network.deleteDriver[]; ENDLOOP; CommunicationInternal.DispatcherOff[]; --don't allow transmits CommunicationInternal.DestroySystemBufferPool[]; --kill buffering package StatsOps.Stop[]; --than maybe stop stats CommHeap.Destroy[]; --and the zone state ← off; --record the obvious END; --CommPackageOff GetContext: PUBLIC ENTRY PROC[ driver: Device, family: Protocol1.ProtocolFamily] RETURNS[LONG POINTER] = BEGIN --looking for intersection of driver and family base: LONG POINTER TO Protocol1.MatrixRecord; base ← @driver.matrix[0]; THROUGH[0..LENGTH[driver.matrix]) DO IF base.family.name = family THEN RETURN[base.context]; base ← base + SIZE[Protocol1.MatrixRecord] REPEAT FINISHED => RETURN[NIL]; ENDLOOP; END; --GetContext GetDeviceChain: PUBLIC PROC RETURNS [Driver.Device] = BEGIN IF state # ready THEN Driver.Glitch[CommPackageNotActive]; RETURN[firstDevice]; END; --GetDeviceChain GetDoStats: PUBLIC <<StatsOpsExtras>> PROC[] RETURNS [BOOLEAN] = {RETURN[CommFlags.doStats]}; GetEthernetStats: PUBLIC PROC[physicalOrder: CARDINAL] RETURNS [EthernetDriverFriends.EtherStatsInfo] = BEGIN info: LONG POINTER TO EthernetDriverFriends.EtherStatsInfo; info ← GetNthDevice[physicalOrder, ethernet].stats; RETURN[info↑]; END; --GetEthernetStats GetNthDevice: PUBLIC ENTRY PROC[ physicalOrder: CARDINAL, medium: Buffer.DeviceType] RETURNS [net: Driver.Device] = BEGIN ENABLE UNWIND => NULL; i: CARDINAL ← 0; FOR net ← firstDevice, net.next UNTIL net = NIL DO SELECT TRUE FROM (net.device # medium) => NULL; ((i ← i + 1) = physicalOrder) => RETURN; ENDCASE; ENDLOOP; ERROR NetworkNonExistent; END; --GetNthDevice GetUseCount: PUBLIC PROC RETURNS[CARDINAL] = {RETURN[useCount]}; RemoveDeviceFromChain: PUBLIC <<Driver>> PROC[network: Driver.Device] = BEGIN RemoveFromChainEntry: ENTRY PROC[] = BEGIN IF firstDevice = network THEN firstDevice ← network.next ELSE FOR tail: Driver.Device ← firstDevice, tail.next UNTIL tail.next = network DO REPEAT FINISHED => tail.next ← network.next; ENDLOOP; END; --RemoveFromChainEntry network.alive ← FALSE; --that stops traffic through the driver RemoveFromChainEntry[]; --remove the object from the device chain --Remove all family members associated with this driver FOR fi: Protocol1.FamilyIndex IN[0..LENGTH[network.matrix]) DO --matrix gets reordered as family members are removed. context: LONG POINTER ← network.matrix[0].context; Protocol1.RemoveFamilyMember[network, network.matrix[0].family]; ENDLOOP; network.deactivateDriver[]; --then deactivate the driver Process.Pause[Process.SecondsToTicks[10]]; --just wait for traffic to die END; --RemoveDeviceFromChain SmashDeviceChain: PUBLIC PROC = {firstDevice ← NIL}; END. LOG 16-May-84 14:39:36 AOF Post Klamath 19-May-86 16:26:33 SMA New encapsulation scheme. 11-Jun-87 15:40:42 AOF Don't delete context in RemoveDeviceFromChain. 18-Jul-87 10:29:21 AOF Moving from EtherMAC to IEEE8023. 15-Oct-87 12:19:31 AOF Don't hold monitor and call .deactivateDriver. 5-Nov-87 10:13:54 AOF Consistant check for changing # of buffers = NIL. 15-Feb-88 9:56:00 AOF Add StatsOpsExtras to export GetDoStats.