<> <> <> <> DIRECTORY AMBridge, AMModel, AMProcess, AMTypes, Basics, BasicTime, CedarProcess, Commander, CommandTool, ComputeServer, ComputeServerControllerRpcControl, ComputeServerInternal, ComputeServerRpcControl, ComputeServerControl, ComputeServerServer, ComputeServerStatistics, FSBackdoor, FSFileOps, Idle, Interpreter, IO, Loader, LupineRuntime, MessageWindow, PrincOps, PrincOpsUtils, PrintTV, Process, ProcessBackdoor, Rope, RPC, SafeStorage, SummonerControllerControl, SymTab, SystemVersion, Terminal, UserCredentials, UserProfile, ViewerClasses, ViewerIO, ViewerOps, VMSideDoor, VMStatistics, WatchStats, WorldVM; ComputeServerMaintenanceImpl: CEDAR MONITOR IMPORTS AMBridge, AMModel, AMProcess, AMTypes, Basics, BasicTime, CedarProcess, Commander, CommandTool, ComputeServerControllerRpcControl, ComputeServerInternal, ComputeServerRpcControl, ComputeServerServer, ComputeServerStatistics, FSBackdoor, FSFileOps, Idle, Interpreter, IO, Loader, LupineRuntime, MessageWindow, PrincOpsUtils, Process, ProcessBackdoor, Rope, RPC, SafeStorage, SummonerControllerControl, SymTab, SystemVersion, UserCredentials, UserProfile, ViewerIO, ViewerOps, VMSideDoor, VMStatistics, WatchStats, WorldVM EXPORTS ComputeServerControl, ComputeServerInternal, ComputeServerStatistics SHARES ComputeServerServer = BEGIN <> <> ROPE: TYPE = Rope.ROPE; TimeUpThisIncarnation: PUBLIC INT _ 0; RequestesThisIncarnation: PUBLIC INT _ 0; TimeBusyThisIncarnation: PUBLIC INT _ 0; TotalTimeUp: PUBLIC INT _ 0; TotalRequestes: PUBLIC INT _ 0; TotalTimeBusy: PUBLIC INT _ 0 ; watchStatsRecord: WatchStats.WatchStatsRecord; lastNoGFI: INT _ -1; noGFIChanged: BOOL _ TRUE; LastRMReclamations: INT; LastTime: BasicTime.GMT ; serverMachineName: RPC.ShortROPE; serverMachinePupAddress: RPC.ShortROPE; wasUp: BOOL _ FALSE; isIdle: BOOL _ FALSE; -- is Cedar "idle" or not aConditionSomewhere: LONG POINTER TO CONDITION _ NIL; usingVerticalRetrace: BOOL _ TRUE; verticalRetraceTV: AMTypes.TV; pointerToVerticalRetraceTV: LONG POINTER TO CONDITION _ NIL; myConditionForCPUStats: CONDITION; notifyCPUStatsProcess: LONG POINTER TO PrincOps.ProcessStateBlock _ NIL; PackageEntry: TYPE = ComputeServerInternal.PackageEntry; CmdEntryObject: TYPE = ComputeServerInternal.CmdEntryObject; CmdEntry: TYPE = ComputeServerInternal.CmdEntry; ServiceEnabled: PUBLIC BOOL _ FALSE; IdleTransitionsEnabled: PUBLIC BOOL _ FALSE; whatsActiveProcessDead: CONDITION; whatsActiveProcess: PROCESS _ NIL; active: BOOL _ FALSE; enabled: BOOL _ FALSE; levelCounters: ARRAY PrincOps.Priority OF INT; backgroundSeen: INT _ 0; timeOutType: TYPE = ARRAY [0..maxIndex) OF RECORD[process: PrincOps.PsbIndex, gfh: PrincOps.GlobalFrameHandle, pc: CARDINAL]; timeout: REF timeOutType; maxIndex: CARDINAL = 50; index: CARDINAL _ 0; TerminalImplGF: AMTypes.TV; searchReadyList: BOOLEAN _ TRUE; -- sometimes the user gets the machine gets into a state where searching the ready list is a bad idea. This boolean allows the user to stop the Spy from searching the ready list. maxVerticalRetraceProcessIndex: CARDINAL = 5; verticalRetraceProcesses: ARRAY [0..maxVerticalRetraceProcessIndex) OF RECORD[ psbi: PrincOps.PsbIndex, seenCounter: INT, -- ranges from 0 through 10000; bumped when seen, debumped when not seen seenThisTime: BOOL ]; nextVerticalRetraceProcesses: CARDINAL _ 0; verticalRetraceProcessCount: INT _ 0; maxVerticalRetraceProcessCount: INT = 5; vrpLockSet: BOOL _ FALSE; vrpLockAvailable: CONDITION _ [timeout: 0]; triedToPowerOff: BOOL _ FALSE; <> ServerOn: Commander.CommandProc = { argv: CommandTool.ArgumentVector _ NIL; controllerName, remoteCommandDirectory, localCommandDirectory: Rope.ROPE _ NIL; IF ServiceEnabled THEN RETURN ["Server already enabled"]; argv _ CommandTool.Parse[cmd ! CommandTool.Failed => { msg _ errorMsg; CONTINUE; }]; IF argv = NIL THEN RETURN[$Failure, msg]; IF argv.argc > 1 THEN controllerName _ argv[1]; IF argv.argc > 2 THEN remoteCommandDirectory _ argv[2]; IF argv.argc > 3 THEN localCommandDirectory _ argv[3]; SummonerControllerControl.StartUpController[controllerName]; msg _ StartUpServer[controllerName, remoteCommandDirectory, localCommandDirectory]; IF ~Rope.IsEmpty[msg] THEN SummonerControllerControl.ShutDownController[]; }; StartUpServer: PUBLIC PROC [controllerName: Rope.ROPE _ NIL, remoteCommandDirectory: Rope.ROPE _ NIL, localCommandDirectory: Rope.ROPE _ NIL] RETURNS [msg: ROPE _ NIL] = { name, password: ROPE; ComputeServerInternal.LastActiveTime _ BasicTime.Now[]; [name, password] _ UserCredentials.Get[]; msg _ ComputeServerInternal.InitCommands[remoteCommandDirectory, localCommandDirectory]; IF ~Rope.IsEmpty[msg] THEN RETURN; ServiceEnabled _ TRUE; ComputeServerInternal.ReportServerEvent[type: serverEnabled, command: NIL, startTime: BasicTime.nullGMT, endTime: BasicTime.nullGMT, remoteMachineName: NIL, userName: NIL]; TRUSTED {Process.Detach[FORK TickStatistics[]]; }; ComputeServerInternal.ControllerGVName _ IF Rope.IsEmpty[controllerName] THEN UserProfile.Token["Summoner.ControllerName"] ELSE controllerName; IF ComputeServerInternal.ControllerGVName = NIL THEN ComputeServerInternal.ControllerGVName _ "PaloAlto1.summoner" ; ComputeServerRpcControl.ExportInterface[ interfaceName: [ type: "ComputeServer.summoner", instance: ComputeServerInternal.MyNetAddressRope, version: [1,1]], user: name, password: RPC.MakeKey[password] ! LupineRuntime.BindingError => CONTINUE;]; ComputeServerInternal.ControllerInterface _ ComputeServerControllerRpcControl.ImportNewInterface[ interfaceName: [ type: "ComputeServerController.summoner", instance: ComputeServerInternal.ControllerGVName, version: [1,1]] ! RPC.ImportFailed => { SummonerControllerControl.ControllerCannnotBeImported[why]; CONTINUE; }; ]; IF ComputeServerInternal.ControllerInterface # NIL THEN { SummonerControllerControl.NoticeControllerIsUp[]; TellControllerAboutExtraCommands[]; }; ComputeServerInternal.InitStats[ComputeServerInternal.myHostName, ComputeServerInternal.MyNetAddressRope]; TRUSTED {Process.Detach[FORK ComputeServerInternal.SummonerServerMonitor[]]; }; StartCounting[]; }; StartCounting: PUBLIC ENTRY PROC = { priority: CedarProcess.Priority; enabled _ TRUE; WHILE whatsActiveProcess # NIL AND ~active DO WAIT whatsActiveProcessDead; ENDLOOP; IF ~active THEN { priority _ CedarProcess.GetPriority[]; CedarProcess.SetPriority[realTime]; TRUSTED {Process.Detach[whatsActiveProcess _ FORK WhatsActive[]]; }; CedarProcess.SetPriority[priority]; }; }; StopCounting: PUBLIC ENTRY PROC = { IF ~active THEN RETURN; -- already stopped enabled _ FALSE; }; WhatsActive: PROC = TRUSTED { topProcess: PrincOps.PsbHandle; lastTopProcess: PrincOps.PsbHandle; noBackgroundProcesses: INT _ 0; done: BOOL _ FALSE; topLevel: Process.Priority _ Process.priorityIdleProcess; sameProcessInARow: INT _ 0; frame: PrincOps.FrameHandle; myPrincOps: PrincOps.PsbHandle = PrincOpsUtils.ReadPSB[]; handleMask: PrincOps.PsbLink = [ failed: FALSE, priority: 0, next: LAST[PrincOps.PsbIndex], reserved: 0, vector: FALSE]; NextHandle: PROC [link: CARDINAL] RETURNS [PrincOps.PsbHandle] = TRUSTED INLINE { RETURN[LOOPHOLE[Basics.BITAND[link, LOOPHOLE[handleMask]]]]}; SearchReadyList: PROC = TRUSTED INLINE { once: BOOLEAN _ FALSE; foundTop: BOOLEAN _ FALSE; headOfReadyList, current: PrincOps.PsbHandle; FOR p: CARDINAL IN [0..nextVerticalRetraceProcesses) DO verticalRetraceProcesses[p].seenThisTime _ FALSE; ENDLOOP; noBackgroundProcesses _ 0; PrincOpsUtils.DisableInterrupts[]; topLevel _ Process.priorityIdleProcess; headOfReadyList _ NextHandle[LOOPHOLE[PrincOps.PDA.ready]]; headOfReadyList _ NextHandle[LOOPHOLE[PrincOps.PDA[headOfReadyList].link]]; -- want the SECOND psb. FOR current _ headOfReadyList, NextHandle[LOOPHOLE[PrincOps.PDA[current].link]] DO psb: LONG POINTER TO PrincOps.ProcessStateBlock = @PrincOps.PDA[current]; link: PrincOps.PsbLink = psb.link; level: Process.Priority = link.priority; skip: BOOLEAN _ FALSE; IF current = headOfReadyList THEN IF once THEN EXIT ELSE once _ TRUE; IF psb = notifyCPUStatsProcess THEN LOOP; IF level = Process.priorityIdleProcess THEN LOOP; IF level = Process.priorityBackground THEN noBackgroundProcesses _ noBackgroundProcesses + 1; IF foundTop THEN LOOP; IF current = myPrincOps THEN LOOP; FOR p: CARDINAL IN [0..nextVerticalRetraceProcesses) DO skipPsb: LONG POINTER TO PrincOps.ProcessStateBlock = @PrincOps.PDA.block[verticalRetraceProcesses[p].psbi]; IF skipPsb = psb THEN { skip _ TRUE; IF level > Process.priorityForeground THEN { IF verticalRetraceProcesses[p].seenCounter < 10000 THEN verticalRetraceProcesses[p].seenCounter _ verticalRetraceProcesses[p].seenCounter + 1; verticalRetraceProcesses[p].seenThisTime _ TRUE; }; EXIT; }; ENDLOOP; IF skip THEN LOOP; IF ~link.vector AND PrincOps.PDA.state[level] = PrincOps.NullStateVectorHandle THEN LOOP; -- no SV. frame _ IF link.vector THEN PrincOps.PDA[psb.context.state].frame ELSE psb.context.frame; <> <<(The Spy wakes up with all of the other timeouts. Since it is the highest priority,>> <> <> <> FOR i: CARDINAL IN [0..index) DO IF timeout[i].gfh = NIL AND timeout[i].pc = 0 THEN EXIT; IF timeout[i].gfh # frame.accesslink OR timeout[i].pc # frame.pc THEN LOOP; skip _ TRUE; EXIT; ENDLOOP; IF skip THEN LOOP; <> topLevel _ level; topProcess _ current; foundTop _ TRUE; ENDLOOP; PrincOpsUtils.EnableInterrupts[]; FOR p: CARDINAL IN [0..nextVerticalRetraceProcesses) DO IF verticalRetraceProcesses[p].seenThisTime = FALSE THEN verticalRetraceProcesses[p].seenCounter _ MAX[0, verticalRetraceProcesses[p].seenCounter - 1]; ENDLOOP; }; <
> FOR p: PrincOps.Priority IN PrincOps.Priority DO levelCounters[p] _ 0; ENDLOOP; <> IF verticalRetraceTV = NIL THEN { [] _ NotifyProcessDead[]; RETURN; }; active _ TRUE; aConditionSomewhere _ pointerToVerticalRetraceTV; usingVerticalRetrace _ TRUE; WHILE ~done DO ticksToRebuildSetTimeouts: INT _ 0; rebuildCounter: INT _ 0; DO waitForBWVerticalRetrace: ENTRY PROC = TRUSTED { WAIT aConditionSomewhere; }; <> waitForBWVerticalRetrace[]; IF ~enabled THEN EXIT; IF ticksToRebuildSetTimeouts MOD 3 = 0 THEN { IF searchReadyList THEN SearchReadyList[]; levelCounters[topLevel] _ levelCounters[topLevel] + 1; backgroundSeen _ backgroundSeen + noBackgroundProcesses; IF lastTopProcess = topProcess THEN { sameProcessInARow _ sameProcessInARow + 1; IF topLevel > Process.priorityForeground AND sameProcessInARow > 512 THEN { psbi: INT; alreadySkipped: BOOL _ FALSE; psbi _ (topProcess - PrincOps.NullPsbHandle)/SIZE[PrincOps.ProcessStateBlock]; FOR p: CARDINAL IN [0..nextVerticalRetraceProcesses) DO IF verticalRetraceProcesses[p].psbi = psbi THEN { alreadySkipped _ TRUE; EXIT; }; ENDLOOP; IF ~alreadySkipped THEN { Process.Detach[FORK AddToVerticalRetraceProcesses[topProcess]]; }; }; } ELSE { sameProcessInARow _ 0; lastTopProcess _ topProcess; }; }; ticksToRebuildSetTimeouts _ ticksToRebuildSetTimeouts + 1; IF ticksToRebuildSetTimeouts MOD 1024 = 0 THEN { IF index = maxIndex OR (ticksToRebuildSetTimeouts _ ticksToRebuildSetTimeouts + 1) > 7000 THEN { ticksToRebuildSetTimeouts _ 0; rebuildCounter _ rebuildCounter + 1; FOR p: CARDINAL IN [0..nextVerticalRetraceProcesses) DO IF verticalRetraceProcesses[p].seenCounter <= 0 THEN { reArrange: ENTRY PROC = TRUSTED { nextVerticalRetraceProcesses _ nextVerticalRetraceProcesses - 1; IF nextVerticalRetraceProcesses # p THEN { verticalRetraceProcesses[p].psbi _ verticalRetraceProcesses[nextVerticalRetraceProcesses].psbi; verticalRetraceProcesses[p].seenCounter _ verticalRetraceProcesses[nextVerticalRetraceProcesses].seenCounter; }; verticalRetraceProcesses[nextVerticalRetraceProcesses].psbi _ 0; verticalRetraceProcesses[nextVerticalRetraceProcesses].seenCounter _ 0; }; reArrange[]; }; ENDLOOP; IF rebuildCounter > 10 THEN { SetTimeouts[TRUE]; rebuildCounter _ 0; } ELSE SetTimeouts[noGFIChanged]; noGFIChanged _ FALSE; }; }; ENDLOOP; done _ NotifyProcessDead[]; ENDLOOP; Process.SetPriority[Process.priorityNormal]; }; NotifyCPUStats: PROC = { cnt: INT _ 0 ; TRUSTED {notifyCPUStatsProcess _ @PrincOps.PDA.block[(PrincOpsUtils.ReadPSB[] - PrincOps.NullPsbHandle)/SIZE[PrincOps.ProcessStateBlock]]; }; CedarProcess.SetPriority[realTime]; DO doNotify: ENTRY PROC = { NOTIFY myConditionForCPUStats; }; IF usingVerticalRetrace THEN cnt _ cnt + 1 ELSE cnt _ 0; IF cnt > 5 THEN EXIT; doNotify[]; Process.Pause[4]; ENDLOOP; notifyCPUStatsProcess _ NIL; }; AddToVerticalRetraceProcesses: PROC [ topProcess: PrincOps.PsbHandle] = TRUSTED { getLock: ENTRY PROC = TRUSTED { verticalRetraceProcessCount _ verticalRetraceProcessCount + 1; WHILE vrpLockSet DO WAIT vrpLockAvailable ENDLOOP; vrpLockSet _ TRUE; }; freeLock: ENTRY PROC = TRUSTED { verticalRetraceProcessCount _ verticalRetraceProcessCount - 1; vrpLockSet _ FALSE; NOTIFY vrpLockAvailable; }; localWorld: WorldVM.World; rootContext: AMModel.Context; psbi: INT; stack: AMTypes.TV; process: AMProcess.Process; IF verticalRetraceProcessCount > maxVerticalRetraceProcessCount THEN RETURN; CedarProcess.SetPriority[normal]; getLock[]; IF nextVerticalRetraceProcesses >= maxVerticalRetraceProcessIndex THEN { freeLock[]; RETURN; }; localWorld _ WorldVM.LocalWorld[]; rootContext _ AMModel.RootContext[localWorld]; psbi _ (topProcess - PrincOps.NullPsbHandle)/SIZE[PrincOps.ProcessStateBlock]; FOR p: CARDINAL IN [0..nextVerticalRetraceProcesses) DO IF verticalRetraceProcesses[p].psbi = psbi THEN { freeLock[]; RETURN; }; ENDLOOP; process _ AMProcess.PSBIToTV[localWorld, psbi]; AMProcess.Freeze[LIST[process], LIST[rootContext]]; AMProcess.Adjust[LIST[process], LIST[rootContext]]; [stack: stack] _ AMProcess.GetState[process]; { IF stack # NIL THEN { str: IO.STREAM = IO.ROS[]; gf: AMTypes.TV; gf _ AMTypes.GlobalParent[stack]; <> AMProcess.Thaw[LIST[process]]; IF AMTypes.TVEq[gf, TerminalImplGF ! AMTypes.Error => GOTO bailout] THEN { < 40 THEN {>> insert: ENTRY PROC = TRUSTED { <> IF nextVerticalRetraceProcesses >= maxVerticalRetraceProcessIndex THEN { freeLock[]; RETURN; }; FOR p: CARDINAL IN [0..nextVerticalRetraceProcesses) DO IF verticalRetraceProcesses[p].psbi = psbi THEN { freeLock[]; RETURN; }; ENDLOOP; verticalRetraceProcesses[nextVerticalRetraceProcesses].psbi _ psbi; verticalRetraceProcesses[nextVerticalRetraceProcesses].seenCounter _ 10000; nextVerticalRetraceProcesses _ nextVerticalRetraceProcesses + 1; }; insert[]; }; } ELSE AMProcess.Thaw[LIST[process]]; freeLock[]; EXITS bailout => freeLock[]; }; }; NotifyProcessDead: ENTRY PROC RETURNS[exit: BOOL _ TRUE] = INLINE { IF enabled THEN RETURN [FALSE] ELSE { NOTIFY whatsActiveProcessDead; active _ FALSE; whatsActiveProcess _ NIL; }; }; ServerOff: Commander.CommandProc = { ShutDownServer[]; SummonerControllerControl.ShutDownController[]; }; ShutDownServer: PUBLIC PROC [] RETURNS [] = { ComputeServerInternal.ControllerInterface _ NIL ; ServiceEnabled _ FALSE; ComputeServerInternal.ReportServerEvent[type: serverDisabled, command: NIL, startTime: BasicTime.nullGMT, endTime: BasicTime.nullGMT, remoteMachineName: NIL, userName: NIL]; ComputeServerInternal.PackageTable _ SymTab.Create[mod: 59, case: FALSE]; ComputeServerInternal.ConfigTable _ SymTab.Create[mod: 59, case: FALSE]; StopCounting[]; }; DoStartup: PROC = { msg: ROPE; SummonerControllerControl.StartUpController[ComputeServerInternal.ControllerGVName]; msg _ StartUpServer[ComputeServerInternal.ControllerGVName, ComputeServerInternal.RemoteCommandDir, ComputeServerInternal.LocalCommandDir]; IF ~Rope.IsEmpty[msg] THEN { SummonerControllerControl.ShutDownController[]; MessageWindow.Append[message: Rope.Concat["Can't Start Summoner Server because ", msg], clearFirst: TRUE]; }; }; IdleTransition: Idle.IdleHandler = { <> SELECT reason FROM becomingBusy => { isIdle _ FALSE; }; becomingIdle => { isIdle _ TRUE; }; ENDCASE; IF IdleTransitionsEnabled THEN { SELECT reason FROM becomingBusy => { ShutDownServer[]; SummonerControllerControl.ShutDownController[]; }; becomingIdle => { TRUSTED {Process.Detach[FORK DoStartup[]];}; }; ENDCASE; }; }; EnableAutoIdle: Commander.CommandProc = { IdleTransitionsEnabled _ TRUE; }; DisableAutoIdle: Commander.CommandProc = { IdleTransitionsEnabled _ FALSE; }; <> SendStats: PUBLIC PROC [] RETURNS [success, terminateService, newPackage: BOOL _ FALSE, queueingCommands: LIST OF Rope.ROPE] = { <> controllerInterface: ComputeServerControllerRpcControl.InterfaceRecord; numberCPUs: CARDINAL _ 1; diskPartionSize: INT; freePagesOnDisk: INT; freeboard: INT; oldestLRUFileDate: BasicTime.GMT; freeProcesses: CARDINAL _ 0; totalSamples: INT _ 0; idleBackGroundSamples: INT _ 0; nonBackgroundCPULoad: REAL; aveBackgroundLoad: REAL; NowRMReclamations: INT; ReclamationRate: REAL; NowTime: BasicTime.GMT = BasicTime.Now[]; TimePeriod: REAL; firstCall: BOOL; [diskPartionSize, freePagesOnDisk, freeboard] _ FSBackdoor.VolumePages[]; <> watchStatsRecord _ WatchStats.GetWatchStats[]; IF watchStatsRecord.gfiFree # lastNoGFI THEN { noGFIChanged _ TRUE; lastNoGFI _ watchStatsRecord.gfiFree; }; NowRMReclamations _ VMStatistics.rmReclamations; TimePeriod _ BasicTime.Period[LastTime, NowTime]; TimePeriod _ MAX[1.0, TimePeriod]; IF LastRMReclamations = 0 THEN ReclamationRate _ -1.0 ELSE ReclamationRate _ (NowRMReclamations - LastRMReclamations) / TimePeriod ; LastRMReclamations _ NowRMReclamations; oldestLRUFileDate _ FSFileOps.OldestLruDate[]; <> freeProcesses _ ProcessBackdoor.CountFreeProcesses[]; FOR p: PrincOps.Priority IN PrincOps.Priority DO delta: INT = levelCounters[p]; levelCounters[p] _ 0; totalSamples _ totalSamples + delta; IF p <= Process.priorityBackground THEN idleBackGroundSamples _ idleBackGroundSamples + delta; ENDLOOP; SELECT TRUE FROM ~isIdle AND ~usingVerticalRetrace => { <> IF verticalRetraceTV # NIL THEN TRUSTED { aConditionSomewhere _ pointerToVerticalRetraceTV; usingVerticalRetrace _ TRUE; }; }; totalSamples = 0 AND usingVerticalRetrace AND isIdle => TRUSTED { <> doBroadcast: ENTRY PROC = TRUSTED INLINE { IF oldCondition # NIL THEN BROADCAST oldCondition^; }; oldCondition: LONG POINTER TO CONDITION; oldCondition _ aConditionSomewhere; aConditionSomewhere _ @myConditionForCPUStats; usingVerticalRetrace _ FALSE; doBroadcast[]; Process.Detach[FORK NotifyCPUStats[]]; }; ENDCASE; IF totalSamples = 0 THEN { nonBackgroundCPULoad _ watchStatsRecord.cpuLoad; aveBackgroundLoad _ -1.0; } ELSE { nonBackgroundCPULoad _ MIN[1.0 - ((1.0*idleBackGroundSamples)/totalSamples), watchStatsRecord.cpuLoad]; aveBackgroundLoad _ (1.0 * backgroundSeen) / totalSamples; }; backgroundSeen _ 0; firstCall _ ~wasUp AND ServiceEnabled; controllerInterface _ ComputeServerInternal.ControllerInterface; IF controllerInterface # NIL THEN [terminateService, newPackage, queueingCommands] _ controllerInterface.NewStats[serverMachineName: serverMachineName, serverMachinePupAddress: serverMachinePupAddress, serverUP: ServiceEnabled, firstCall: firstCall, machineType: SystemVersion.machineType, mainMemory: VMSideDoor.rmPages, numberCPUs: numberCPUs, diskPartionSize: diskPartionSize, freePagesOnDisk: freePagesOnDisk, freeboard: freeboard, freeGFI: watchStatsRecord.gfiFree, freeMDS: watchStatsRecord.mdsFree, freeVM: watchStatsRecord.vmFree, oldestLRUFileDate: oldestLRUFileDate, CPULoad: watchStatsRecord.cpuLoad, nonBackgroundCPULoad: nonBackgroundCPULoad, reclamationRate: ReclamationRate, freeProcesses: freeProcesses, userName: UserCredentials.Get[].name, currentRequests: ComputeServerInternal.CurrentRequests, aveBackgroundLoad: aveBackgroundLoad ]; success _ TRUE; wasUp _ ServiceEnabled; }; <> SummonerServerMonitor: PUBLIC PROC [] RETURNS [] = { delayToNextStat: INT _ 2; WHILE ServiceEnabled DO success: BOOL _ TRUE; terminateService: BOOL _ FALSE; newPackage: BOOL _ FALSE; queueingCommands: LIST OF ROPE; cycleCount: INT _ 0; tryDifferentController: BOOL _ FALSE; WHILE ~tryDifferentController AND ComputeServerInternal.ControllerInterface # NIL AND success AND NOT terminateService AND ServiceEnabled DO Process.Pause[Process.SecondsToTicks[delayToNextStat]]; [success, terminateService, newPackage, queueingCommands] _ ComputeServerInternal.SendStats[ ! RPC.CallFailed => { SummonerControllerControl.ControllerCallFailed[why]; ComputeServerInternal.ControllerInterface _ NIL ; newPackage _ FALSE; queueingCommands _ NIL; CONTINUE; }; ]; IF newPackage THEN { ComputeServerInternal.getNewPackages[]; }; IF queueingCommands # NIL THEN newQueueingCommands[queueingCommands]; newPackage _ FALSE; delayToNextStat _ 9; IF (cycleCount _ cycleCount + 1) > 10 THEN { cycleCount _ 0; ComputeServerInternal.KillOldUnstartedServices[]; }; IF cycleCount = 1 OR cycleCount = 6 THEN { controllerInterface: ComputeServerControllerRpcControl.InterfaceRecord _ ComputeServerInternal.ControllerInterface; IF controllerInterface # NIL THEN { [tryDifferentController: tryDifferentController] _ controllerInterface.GetSomeInfo[ ! RPC.CallFailed => { SummonerControllerControl.ControllerCallFailed[why]; ComputeServerInternal.ControllerInterface _ NIL ; newPackage _ FALSE; queueingCommands _ NIL; CONTINUE; }; ]; }; }; IF ComputeServerInternal.DisableIFIdle AND ComputeServerInternal.ActiveServices = 0 THEN { now: BasicTime.GMT = BasicTime.Now[]; unpack: BasicTime.Unpacked; minuteTime: INT; IF BasicTime.Period[from: ComputeServerInternal.LastActiveTime, to: now] > 3600 THEN { unpack _ BasicTime.Unpack[now]; minuteTime _ unpack.hour*100+unpack.minute; IF minuteTime > ComputeServerInternal.DisableIFIdleAfter OR minuteTime < ComputeServerInternal.DisableIFIdleBefore THEN { triedToPowerOff _ TRUE; ShutDownServer[]; SummonerControllerControl.ShutDownController[]; }; }; }; ENDLOOP; <> IF ~tryDifferentController AND ComputeServerInternal.ControllerInterface # NIL AND ~ServiceEnabled THEN [success, terminateService] _ ComputeServerInternal.SendStats[ ! RPC.CallFailed => { SummonerControllerControl.ControllerCallFailed[why]; ComputeServerInternal.ControllerInterface _ NIL ; CONTINUE; }; ]; IF terminateService THEN { ServiceEnabled _ FALSE; ComputeServerInternal.ReportServerEvent[type: serverDisabled, command: NIL, startTime: BasicTime.nullGMT, endTime: BasicTime.nullGMT, remoteMachineName: NIL, userName: NIL]; }; IF ServiceEnabled AND (tryDifferentController OR ComputeServerInternal.ControllerInterface = NIL) THEN ComputeServerInternal.ControllerInterface _ ComputeServerControllerRpcControl.ImportNewInterface[ interfaceName: [ type: "ComputeServerController.summoner", instance: ComputeServerInternal.ControllerGVName, version: [1,1]] ! RPC.ImportFailed => { SummonerControllerControl.ControllerCannnotBeImported[why]; CONTINUE; };]; IF ComputeServerInternal.ControllerInterface # NIL THEN { SummonerControllerControl.NoticeControllerIsUp[]; TellControllerAboutExtraCommands[]; }; ComputeServerInternal.InitStats[ComputeServerInternal.myHostName, ComputeServerInternal.MyNetAddressRope]; ComputeServerInternal.KillOldUnstartedServices[]; IF ComputeServerInternal.ControllerInterface = NIL THEN Process.Pause[Process.SecondsToTicks[7]]; ENDLOOP; }; <> newQueueingCommands: PROC [queueingCommands: LIST OF ROPE] = { FOR q: LIST OF ROPE _ queueingCommands, q.rest UNTIL q = NIL DO foundInCmdTable: BOOL; cmdVal: REF ANY; cmdEntry: CmdEntry; [found: foundInCmdTable, val: cmdVal] _ SymTab.Fetch[x: ComputeServerInternal.CommandTable, key: q.first]; cmdEntry _ NARROW[cmdVal]; IF cmdEntry # NIL THEN { foundPack: BOOL; valPack: REF ANY; packageEntry: PackageEntry; cmdEntry.doQueueing _ TRUE; [found: foundPack, val: valPack] _ SymTab.Fetch[x: ComputeServerInternal.PackageTable, key: cmdEntry.package]; IF ~foundPack THEN LOOP; packageEntry _ NARROW[valPack, PackageEntry]; IF packageEntry.exclusive AND ComputeServerInternal.ActiveServices > 0 THEN LOOP; IF packageEntry.nowActive < packageEntry.maxCountActive THEN { controllerInterface: ComputeServerControllerRpcControl.InterfaceRecord; controllerInterface _ ComputeServerInternal.ControllerInterface; IF controllerInterface # NIL THEN { controllerInterface.MightAcceptQueuedCommand[serverMachineAddress: ComputeServerInternal.MyNetAddressRope, commandName: q.first ! RPC.CallFailed => { SummonerControllerControl.ControllerCallFailed[why]; ComputeServerInternal.ControllerInterface _ NIL ; CONTINUE; }; ]; cmdEntry.okToQueuePosted _ TRUE; }; }; } ELSE { -- might be an extra command - they aren't in the CommandTable foundRegCmd: BOOL; controllerInterface: ComputeServerControllerRpcControl.InterfaceRecord; [found: foundRegCmd] _ SymTab.Fetch[x: ComputeServerServer.Registry, key: q.first]; IF foundRegCmd AND (controllerInterface _ ComputeServerInternal.ControllerInterface) # NIL THEN { controllerInterface.MightAcceptQueuedCommand[serverMachineAddress: ComputeServerInternal.MyNetAddressRope, commandName: q.first ! RPC.CallFailed => { SummonerControllerControl.ControllerCallFailed[why]; ComputeServerInternal.ControllerInterface _ NIL ; CONTINUE; }; ]; }; }; ENDLOOP; }; <> TellControllerAboutExtraCommands: PROC = { procData: LIST OF ComputeServerServer.RegisteredProcHandle; EachPairProc: SymTab.EachPairAction = { loopList: LIST OF ComputeServerInternal.RegisteredProcHandle; procData _ NARROW[val]; FOR loopList _ procData, loopList.rest UNTIL loopList = NIL DO procHandle: ComputeServerInternal.RegisteredProcHandle _ loopList.first; foundCmdTab: BOOL; tempControllerInterface: ComputeServerControllerRpcControl.InterfaceRecord _ NIL; [found: foundCmdTab] _ SymTab.Fetch[x: ComputeServerInternal.CommandTable, key: procHandle.service]; IF ~foundCmdTab AND (tempControllerInterface _ ComputeServerInternal.ControllerInterface) # NIL THEN { tempControllerInterface.ExtraCommandAvailable[serverMachineName: ComputeServerInternal.MyNetAddressRope, commandName: procHandle.service, version: procHandle.version ! RPC.CallFailed => { SummonerControllerControl.ControllerCallFailed[why]; ComputeServerInternal.ControllerInterface _ NIL ; CONTINUE; }; ]; }; ENDLOOP; }; [] _ SymTab.Pairs[x: ComputeServerServer.Registry, action: EachPairProc]; }; <> InitStats: PUBLIC PROC [myName: RPC.ShortROPE, myAddress: RPC.ShortROPE] = { serverMachineName _ myName ; serverMachinePupAddress _ myAddress; LastRMReclamations _ VMStatistics.rmReclamations; LastTime _ BasicTime.Now[]; }; <> TickStatistics: PROC [] = { lastStatTime: BasicTime.GMT _ BasicTime.Now[]; aSecond: Process.Ticks = Process.SecondsToTicks[1]; WHILE ServiceEnabled DO nowTime: BasicTime.GMT _ BasicTime.Now[]; period: INT; period _ BasicTime.Period[lastStatTime, nowTime]; IF period > 0 THEN { TimeUpThisIncarnation _ TimeUpThisIncarnation + period; TotalTimeUp _ TotalTimeUp + period; IF ComputeServerInternal.ActiveServices > 0 THEN { TimeBusyThisIncarnation _ TimeBusyThisIncarnation + period; TotalTimeBusy _ TotalTimeBusy + period; }; }; lastStatTime _ nowTime; Process.Pause[aSecond]; ENDLOOP; TimeUpThisIncarnation _ 0; RequestesThisIncarnation _ 0; TimeBusyThisIncarnation _ 0; }; ServerStatistics: Commander.CommandProc = { IF ServiceEnabled THEN { percentBusy: REAL; realTimeBusyThisIncarnation: REAL _ TimeBusyThisIncarnation; realTimeUpThisIncarnation: REAL _ TimeUpThisIncarnation; percentBusy _ (100.0 * realTimeBusyThisIncarnation) / MAX[1.0, realTimeUpThisIncarnation]; msg _ IO.PutFR["Seconds up %g, requests %g, time busy %g, percent busy %5.2f%%", IO.int[TimeUpThisIncarnation], IO.int[RequestesThisIncarnation], IO.int[TimeBusyThisIncarnation], IO.real[percentBusy] ] } ELSE msg _ "Server not enabled"; }; <> StartServerEventTypescript: Commander.CommandProc = { TRUSTED {Process.Detach[FORK ServerEventTypescript[]];}; }; ServerEventTypescript: PROC = { ENABLE IO.Error => GOTO ViewerDestroyed; currentViewer: ViewerClasses.Viewer _ NIL; currentStream: IO.STREAM _ NIL; currentEvent: REF READONLY ComputeServerStatistics.ServerEvent _ NIL; currentViewer _ ViewerOps.CreateViewer[flavor: $Typescript, info: [iconic: FALSE, name: "Compute Server ""Server"" Event Log"]]; currentStream _ ViewerIO.CreateViewerStreams[name: "", viewer: currentViewer].out; currentStream.PutF["Starting log at %g\n", IO.time[BasicTime.Now[]]]; DO currentEvent _ ComputeServerStatistics.NextServerEvent[currentEvent]; SELECT currentEvent.type FROM startService => { currentStream.PutF["Start %g for %g (%g) at %g\n", IO.rope[currentEvent.command], IO.rope[currentEvent.remoteUser], IO.rope[currentEvent.remoteMachineName], IO.time[currentEvent.startTime]]; }; doneService => { currentStream.PutF["End %g for %g at %g duration %g seconds\n", IO.rope[currentEvent.command], IO.rope[currentEvent.remoteMachineName], IO.time[currentEvent.endTime], IO.int[BasicTime.Period[currentEvent.startTime, currentEvent.endTime]]]; }; serverEnabled => { currentStream.PutF[" **** Server enabled at %g\n", IO.time[BasicTime.Now[]]];}; serverDisabled => { currentStream.PutF[" **** Server disabled at %g\n", IO.time[BasicTime.Now[]]];}; ENDCASE; ENDLOOP; EXITS ViewerDestroyed => {}; }; <> SetTimeouts: PROC [computeVerticalRetrace: BOOL] = TRUSTED { ticks: Process.Ticks; cutoff: Process.Ticks; found: BOOLEAN; frame: PrincOps.FrameHandle; IF index = maxIndex THEN { index _ 0; FOR i: CARDINAL IN [0..maxIndex) DO timeout[i].process _ 0; timeout[i].gfh _ PrincOps.NullGlobalFrame; timeout[i].pc _ 0; ENDLOOP; }; cutoff _ Process.SecondsToTicks[10]; ticks _ PrincOpsUtils.ReadPTC[]; FOR psbi: PrincOps.PsbIndex IN [PrincOps.StartPsb..PrincOps.StartPsb+PrincOps.PDA.count) DO block: PrincOps.ProcessStateBlock = PrincOps.PDA.block[psbi]; IF PrincOps.PDA.block[psbi].mds = 0 THEN LOOP; IF PrincOps.PDA.block[psbi].mds - ticks > cutoff THEN LOOP; -- not significant IF PrincOps.PDA.block[psbi].link.vector THEN frame _ PrincOps.PDA[PrincOps.PDA.block[psbi].context.state].frame ELSE frame _ PrincOps.PDA.block[psbi].context.frame; found _ FALSE; FOR i: CARDINAL IN [0..index) DO IF timeout[i].gfh = frame.accesslink AND timeout[i].pc = frame.pc THEN {found _ TRUE; EXIT}; ENDLOOP; IF found THEN LOOP; timeout[index] _ [psbi, frame.accesslink, frame.pc]; index _ index + 1; IF index = maxIndex THEN EXIT; ENDLOOP; <> <> <> <> <> <> <> <> <> <<[stack: stack] _ AMProcess.GetState[newProcesses.first];>> <> <> <> < 40 THEN {>> <> <> <> <<};>> <<};>> <> <> <> <<};>> }; InitializeBackgroundCounting: PROC = { newContext: AMModel.Context; Loader.MakeProcedureResident[WhatsActive]; Loader.MakeGlobalFrameResident[InitializeBackgroundCounting]; TRUSTED {Process.InitializeCondition[@whatsActiveProcessDead, 10000]; }; timeout _ NEW[timeOutType]; SafeStorage.PinObject[timeout]; SetTimeouts[TRUE]; TRUSTED {newContext _ AMModel.MostRecentNamedContext["TerminalImpl", AMModel.RootContext[WorldVM.LocalWorld[]]];}; TerminalImplGF _ newContext; verticalRetraceTV _ Interpreter.Evaluate["TerminalImpl.verticalRetrace"].result; IF verticalRetraceTV = NIL THEN TRUSTED { usingVerticalRetrace _ FALSE; aConditionSomewhere _ @myConditionForCPUStats; Process.Detach[FORK NotifyCPUStats[]]; } ELSE TRUSTED { usingVerticalRetrace _ TRUE; pointerToVerticalRetraceTV _ AMBridge.PointerFromTV[verticalRetraceTV]; aConditionSomewhere _ pointerToVerticalRetraceTV; }; }; Commander.Register[key: "///Commands/SummonerServerOn", proc: ServerOn, doc: "SummonerServerOn {controllerName {remoteCommandDirectory {localCommandDirectory}}} Turn on use of the Compute Server Service for cluster controllerName using remoteCommandDirectory on a file server and localCommandDirectory on the workstation"]; Commander.Register[key: "///Commands/SummonerServerOff", proc: ServerOff, doc: "Turn off use of the Compute Server Service"]; Commander.Register[key: "///Commands/SummonerEnableAutoIdle", proc: EnableAutoIdle, doc: "Turn on automatic Summoner server toggle at Idle"]; Commander.Register[key: "///Commands/SummonerDisableAutoIdle", proc: DisableAutoIdle, doc: "Turn off automatic Summoner server toggle at Idle"]; Commander.Register[key: "///Commands/SummonerServerTypescript", proc: StartServerEventTypescript, doc: "Start typescript of server events"]; Commander.Register[key: "///Commands/SummonerServerStatistics", proc: ServerStatistics, doc: "Print statistics"]; [] _ Idle.RegisterIdleHandler[IdleTransition]; InitializeBackgroundCounting[]; END. <> <> <> <> <> <> <> <<>>