-- File: Boss.mesa - last edit:
-- AOF 5-Nov-87 10:14:13
-- SMA 21-May-86 10:44:29
-- HGM 13-Jul-85 22:51:43
-- Copyright (C) 1984, 1985, 1986, 1987 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];
Boss: MONITOR
IMPORTS
CommHeap, CommunicationInternal, Driver, IEEE8023, Process, Protocol1,
StatsOps
EXPORTS
CommunicationInternal, Buffer, Driver, EthernetDriverFriends, Protocol1 =
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 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.