-- File: LineUse.mesa, Last Edit: HGM January 30, 1981 3:37 PM DIRECTORY Event USING [Item, Reason, AddNotifier], Format USING [], -- Needed by Put.Number FormSW USING [ ClientItemsProcType, ProcType, AllocateItemDescriptor, newLine, CommandItem, StringItem, NumberItem], Inline USING [LowHalf, HighHalf], MsgSW USING [Post], Process USING [Detach, MsecToTicks, SetTimeout, Yield], Put USING [Char, CR, Date, Line, Number, Text], String USING [AppendLongNumber, AppendString], System USING [GreenwichMeanTime, GetGreenwichMeanTime, AdjustGreenwichMeanTime], Time USING [AppendCurrent, Current], Tool USING [ Create, MakeSWsProc, UnusedLogName, MakeMsgSW, MakeFormSW, MakeFileSW, AddThisSW], ToolWindow USING [TransitionProcType, DisplayProcType, CreateSubwindow], Window USING [Handle, Box, DisplayData, DisplayInvert, DisplayWhite], AltoSlaDefs, GateControlDefs USING [gateControlExamine, gateControlStatsAck], PupDefs USING [ AppendPupAddress, PupPackageMake, PupPackageDestroy, PupBuffer, GetFreePupBuffer, ReturnFreePupBuffer, PupAddress, GetPupAddress, PupNameTrouble, GetPupContentsBytes, SetPupContentsWords, PupSocket, PupSocketDestroy, PupSocketMake, MsToTocks], PupTypes USING [fillInSocketID], CommUtilDefs USING [magicMemoryLocation], DriverDefs; LineUse: MONITOR IMPORTS Event, Inline, FormSW, MsgSW, Process, Put, String, System, Time, Tool, ToolWindow, Window, PupDefs SHARES DriverDefs = BEGIN OPEN PupDefs; tool, msg, form, boxes, log: Window.Handle; eventItem: Event.Item ← [eventMask: 177777B, eventProc: Broom]; running: BOOLEAN ← FALSE; pleaseStop: BOOLEAN ← FALSE; indicator: {left, right, off} ← off; seconds: CARDINAL ← 60; target: STRING ← [30]; where: PupAddress ← [[0], [0], [31415, 9265]]; soc: PupSocket ← NIL; giantVector: DriverDefs.GiantVector; giantVectorLoc: POINTER TO DriverDefs.GiantVector; Go: FormSW.ProcType = BEGIN IF running THEN BEGIN MsgSW.Post[msg, "Somebody is already running..."L]; RETURN; END; Put.CR[log]; Put.Date[log, Time.Current[], dateTime]; Put.Text[log, " Watching SLA lines on "L]; IF ~FindPath[] THEN RETURN; running ← TRUE; Process.Detach[FORK Watch[]]; END; Stop: FormSW.ProcType = BEGIN Off[]; END; Off: PROCEDURE = BEGIN IF ~running THEN RETURN; pleaseStop ← TRUE; WHILE running DO Process.Yield[]; ENDLOOP; pleaseStop ← FALSE; END; FindPath: PROCEDURE RETURNS [BOOLEAN] = BEGIN Put.Text[log, target]; Put.Char[log, '=]; GetPupAddress[ @where, target ! PupNameTrouble => BEGIN MsgSW.Post[msg, e]; Put.Line[log, e]; GOTO Trouble; END]; PrintPupAddress[where]; Put.Line[log, "."L]; RETURN[TRUE]; EXITS Trouble => RETURN[FALSE]; END; Watch: ENTRY PROCEDURE = BEGIN time: System.GreenwichMeanTime ← System.GetGreenwichMeanTime[]; pause: CONDITION; MakeConnection[]; SetupBoxes[]; Process.SetTimeout[@pause, Process.MsecToTicks[500]]; GetInfo[]; oldLineInfo ← newLineInfo; FOR line: AltoSlaDefs.Line IN [0..activeLines) DO oldDest[line] ← 177777B; oldLineInfo[line].state ← missing; ENDLOOP; CheckLineState[]; oldLineInfo ← newLineInfo; Put.CR[log]; PrintHeader[]; UNTIL pleaseStop DO UNTIL pleaseStop OR (System.GetGreenwichMeanTime[] - time) >= seconds DO WAIT pause; ENDLOOP; time ← System.AdjustGreenwichMeanTime[time, seconds]; GetInfo[]; PrintTime[]; Put.CR[log]; PrintInfo[]; CheckLineState[]; oldLineInfo ← newLineInfo; ENDLOOP; SetDownBoxes[]; KillConnection[]; running ← FALSE; END; activeLines: CARDINAL; hisLineInfo: LONG POINTER TO ARRAY AltoSlaDefs.Line OF AltoSlaDefs.LineInfoBlock; hisSlaRouting: LONG POINTER TO ARRAY AltoSlaDefs.SlaHost OF AltoSlaDefs.RoutingTableEntry; oldLineInfo, newLineInfo: ARRAY AltoSlaDefs.Line OF AltoSlaDefs.LineInfoBlock; newSlaRoutingTable: ARRAY AltoSlaDefs.SlaHost OF AltoSlaDefs.RoutingTableEntry; oldDest: ARRAY AltoSlaDefs.Line OF CARDINAL; GetInfo: PROCEDURE = BEGIN OPEN AltoSlaDefs; GetBig[ to: @newLineInfo, from: hisLineInfo, size: activeLines*SIZE[LineInfoBlock]]; GetBig[ to: @newSlaRoutingTable, from: hisSlaRouting, size: maxSlaHost*SIZE[RoutingTableEntry]]; END; PrintHeader: PROCEDURE = BEGIN OPEN AltoSlaDefs; Put.Line[ log, " Q Rej Packets Bytes Bits/Sec Delay Ms L H L C H S Hi Sent Recv Sent Recv Sent Recv Hi Send "L]; END; PrintInfo: PROCEDURE = BEGIN FOR line: AltoSlaDefs.Line IN [0..activeLines) DO lib: AltoSlaDefs.LineInfoBlock; temp: LONG INTEGER; O1[line]; D3[newLineInfo[line].hiPriQueue.length]; D2[newLineInfo[line].lowPriQueue.length]; lib.connRejections ← newLineInfo[line].connRejections - oldLineInfo[line].connRejections; lib.hiRejections ← newLineInfo[line].hiRejections - oldLineInfo[line].hiRejections; lib.rejections ← newLineInfo[line].rejections - oldLineInfo[line].rejections; LD3[lib.connRejections]; LD3[lib.hiRejections]; LD3[lib.rejections]; lib.packetsSent ← newLineInfo[line].packetsSent - oldLineInfo[line].packetsSent; lib.packetsRecv ← newLineInfo[line].packetsRecv - oldLineInfo[line].packetsRecv; lib.bytesSent ← newLineInfo[line].bytesSent - oldLineInfo[line].bytesSent; lib.bytesRecv ← newLineInfo[line].bytesRecv - oldLineInfo[line].bytesRecv; lib.queueDelay ← newLineInfo[line].queueDelay - oldLineInfo[line].queueDelay; lib.hiPacketsSent ← newLineInfo[line].hiPacketsSent - oldLineInfo[line].hiPacketsSent; lib.hiBytesSent ← newLineInfo[line].hiBytesSent - oldLineInfo[line].hiBytesSent; lib.hiQueueDelay ← newLineInfo[line].hiQueueDelay - oldLineInfo[line].hiQueueDelay; LD7[lib.hiPacketsSent]; LD7[lib.packetsSent]; LD7[lib.packetsRecv]; LD7[lib.bytesSent]; LD7[lib.bytesRecv]; temp ← lib.bytesSent + AltoSlaDefs.overheadPerPacket*lib.packetsSent; LD7[temp*8/seconds]; temp ← lib.bytesRecv + AltoSlaDefs.overheadPerPacket*lib.packetsRecv; LD7[temp*8/seconds]; LD7[(lib.hiQueueDelay*39)/lib.hiPacketsSent]; LD7[(lib.queueDelay*39)/lib.packetsSent]; Put.CR[log]; ENDLOOP; END; CheckLineState: PROCEDURE = BEGIN changed: BOOLEAN; FOR line: AltoSlaDefs.Line IN [0..activeLines) DO changed ← FALSE; -- find out who this line is connected to FOR host: AltoSlaDefs.SlaHost IN AltoSlaDefs.SlaHost DO rte: POINTER TO AltoSlaDefs.RoutingTableEntry; rte ← @newSlaRoutingTable[host]; IF rte.line = line AND rte.hops = 1 THEN BEGIN IF oldDest[line] # host THEN changed ← TRUE; oldDest[line] ← host; EXIT; END; ENDLOOP; IF oldLineInfo[line].state # newLineInfo[line].state THEN changed ← TRUE; IF ~changed THEN LOOP; PrintTime[]; Put.Text[log, " Line "]; O[line]; Put.Text[log, " is "]; SELECT newLineInfo[line].state FROM up => BEGIN Put.Text[log, "up to host "]; O[oldDest[line]]; END; down => Put.Text[log, "down"L]; loopedBack => Put.Text[log, "looped back"L]; ENDCASE => Put.Line[log, "??"L]; Put.Char[log, '.]; Put.CR[log]; ENDLOOP; END; Read: PROCEDURE [p: LONG POINTER] RETURNS [x: UNSPECIFIED] = BEGIN Get[to: @x, from: p, size: 1]; END; GetBig: PROCEDURE [to: POINTER, from: LONG POINTER, size: CARDINAL] = BEGIN end: CARDINAL ← 0; hunk: CARDINAL; UNTIL end = size DO hunk ← MIN[250, size - end]; Get[to + end, from + end, hunk]; end ← end + hunk; ENDLOOP; END; -- get a block of info from the "right" address space thisID: CARDINAL ← 0; Get: PROCEDURE [to: POINTER, from: LONG POINTER, size: CARDINAL] = BEGIN b: PupBuffer; i: CARDINAL; IF size > 250 THEN ERROR; IF Inline.HighHalf[from] # 0 THEN ERROR; thisID ← thisID + 1; DO -- until we get the answer b ← GetFreePupBuffer[]; b.pupID ← [27182, thisID]; b.pupWords[0] ← LOOPHOLE[Inline.LowHalf[from]]; b.pupWords[1] ← size; b.pupType ← GateControlDefs.gateControlExamine; SetPupContentsWords[b, 2]; soc.put[b]; -- The loop structure here is not very nice..... FlipBoxes[]; b ← soc.get[]; IF b = NIL THEN LOOP; IF b.pupType = error OR b.pupID.b # thisID THEN BEGIN ReturnFreePupBuffer[b]; LOOP; END; IF b.pupType = GateControlDefs.gateControlStatsAck AND GetPupContentsBytes[ b] = 2*(2 + size) THEN EXIT; ERROR; ENDLOOP; FlipBoxes[]; FOR i IN [0..size) DO (to + i)↑ ← b.pupWords[2 + i]; ENDLOOP; ReturnFreePupBuffer[b]; END; PrintTime: PROCEDURE = BEGIN text: STRING = [20]; Time.AppendCurrent[text]; Put.Text[log, text]; END; PrintPupAddress: PROCEDURE [a: PupAddress] = BEGIN text: STRING = [20]; AppendPupAddress[text, a]; Put.Text[log, text]; END; O: PROCEDURE [n: CARDINAL] = BEGIN Put.Number[log, n, [8, FALSE, TRUE, 0]]; END; O1: PROCEDURE [n: CARDINAL] = BEGIN Put.Number[log, n, [8, FALSE, TRUE, 1]]; END; O3: PROCEDURE [n: CARDINAL] = BEGIN Put.Number[log, n, [8, FALSE, TRUE, 3]]; END; D: PROCEDURE [n: CARDINAL] = BEGIN Put.Number[log, n, [10, FALSE, TRUE, 0]]; END; D2: PROCEDURE [n: CARDINAL] = BEGIN Put.Number[log, n, [10, FALSE, TRUE, 2]]; END; D3: PROCEDURE [n: CARDINAL] = BEGIN Put.Number[log, n, [10, FALSE, TRUE, 3]]; END; D4: PROCEDURE [n: CARDINAL] = BEGIN Put.Number[log, n, [10, FALSE, TRUE, 4]]; END; LD2: PROCEDURE [num: LONG INTEGER] = BEGIN s: STRING = [20]; String.AppendLongNumber[s, num, 10]; THROUGH [s.length..2) DO Put.Char[log, ' ]; ENDLOOP; Put.Text[log, s]; END; LD3: PROCEDURE [num: LONG INTEGER] = BEGIN s: STRING = [20]; String.AppendLongNumber[s, num, 10]; THROUGH [s.length..3) DO Put.Char[log, ' ]; ENDLOOP; Put.Text[log, s]; END; LD7: PROCEDURE [num: LONG INTEGER] = BEGIN s: STRING = [20]; String.AppendLongNumber[s, num, 10]; THROUGH [s.length..7) DO Put.Char[log, ' ]; ENDLOOP; Put.Text[log, s]; END; MakeConnection: PROCEDURE = BEGIN soc ← PupSocketMake[PupTypes.fillInSocketID, where, MsToTocks[1000]]; giantVectorLoc ← Read[CommUtilDefs.magicMemoryLocation]; Get[ to: @giantVector, from: giantVectorLoc, size: SIZE[DriverDefs.GiantVector]]; BEGIN OPEN AltoSlaDefs; p: LONG POINTER ← giantVector.slaThings; IF p = NIL THEN ERROR; p ← p + maxByte; -- skip CRC Table activeLines ← Read[p]; p ← 8 + p + maxLine*SIZE[LineTableEntry]; hisSlaRouting ← p; p ← p + maxSlaHost*SIZE[RoutingTableEntry]; hisLineInfo ← p; IF activeLines > maxLine THEN ERROR; END; END; KillConnection: PROCEDURE = BEGIN PupSocketDestroy[soc]; soc ← NIL; END; indicatorBox: Window.Box = [[25, 10], [16, 16]]; DisplayBoxes: ToolWindow.DisplayProcType = BEGIN pattern: ARRAY [0..1] OF ARRAY [0..8) OF WORD; left: WORD = 177400B; right: WORD = 000377B; SELECT indicator FROM left => pattern ← [ALL[left], ALL[right]]; right => pattern ← [ALL[right], ALL[left]]; off => pattern ← [ALL[0], ALL[0]]; ENDCASE; Window.DisplayData[window, indicatorBox, @pattern, 1] END; SetupBoxes: PROCEDURE = BEGIN indicator ← left; DisplayBoxes[boxes]; END; FlipBoxes: PROCEDURE = BEGIN SELECT indicator FROM left => indicator ← right; off, right => indicator ← left; ENDCASE; Window.DisplayInvert[boxes, indicatorBox]; END; SetDownBoxes: PROCEDURE = BEGIN indicator ← off; Window.DisplayWhite[boxes, indicatorBox]; END; MakeBoxesSW: PROCEDURE [window: Window.Handle] = BEGIN boxes ← ToolWindow.CreateSubwindow[parent: window, display: DisplayBoxes]; boxes.box.dims.h ← 36; Tool.AddThisSW[window: window, sw: boxes, swType: vanilla]; END; MakeSWs: Tool.MakeSWsProc = BEGIN logFileName: STRING = [40]; msg ← Tool.MakeMsgSW[window: window, lines: 5]; form ← Tool.MakeFormSW[window: window, formProc: MakeForm]; MakeBoxesSW[window]; Tool.UnusedLogName[logFileName, "LineUse.log$"L]; log ← Tool.MakeFileSW[window: window, name: logFileName]; END; MakeForm: FormSW.ClientItemsProcType = BEGIN nParams: CARDINAL = 4; items ← FormSW.AllocateItemDescriptor[nParams]; items[0] ← FormSW.CommandItem[ tag: "Stop"L, proc: Stop, place: FormSW.newLine]; items[1] ← FormSW.CommandItem[tag: "Go"L, proc: Go]; items[2] ← FormSW.NumberItem[tag: "Seconds"L, value: @seconds, default: 60]; items[3] ← FormSW.StringItem[tag: "Target"L, string: @target]; RETURN[items, TRUE]; END; ClientTransition: ToolWindow.TransitionProcType = BEGIN SELECT TRUE FROM old = inactive => BEGIN String.AppendString[target, "ME"L]; PupDefs.PupPackageMake[]; END; new = inactive => BEGIN IF running THEN Off[]; PupDefs.PupPackageDestroy[]; END; ENDCASE; END; Broom: PROCEDURE [why: Event.Reason] = BEGIN SELECT why FROM makeImage, makeCheck => BEGIN IF running THEN Off[]; PupDefs.PupPackageDestroy[]; END; startImage, restartCheck, continueCheck => BEGIN PupDefs.PupPackageMake[]; END; ENDCASE => NULL; END; Init: PROCEDURE = BEGIN herald: STRING = "Line Use of January 30, 1981"L; tool ← Tool.Create[ name: herald, makeSWsProc: MakeSWs, clientTransition: ClientTransition]; END; -- Main Body Event.AddNotifier[@eventItem]; END.