DIRECTORY AMBridge, AMTypes, Atom, Basics, BasicTime, Booting, Commander, CommandTool, ComputeClient, ComputeClientExtras, ComputeClientInternal, ComputeServer, ComputeServerCallbacks, ComputeServerCallbacksRpcControl, ComputeServerClient, ComputeServerControllerRpcControl, ComputeServerRpcControl, FS, FSBackdoor, GVBasics, GVNames, Interpreter, IO, PrincOps, PrincOpsUtils, Process, ProcessProps, Pup USING [Address, nullSocket], PupName USING [AddressToRope, Error, HisName, MyName, MyRope, NameLookup], PupStream USING [Create, SendMark, StreamClosing, waitForever], Rope, RPC, UnsafeStorage, UserCredentials, UserProfile, VM; ComputeClientImpl: CEDAR MONITOR IMPORTS AMBridge, Atom, BasicTime, Booting, Commander, CommandTool, ComputeClient,ComputeClientInternal, ComputeServerCallbacks, ComputeServerCallbacksRpcControl, ComputeServerClient, ComputeServerControllerRpcControl, ComputeServerRpcControl, FS, FSBackdoor, GVNames, Interpreter, IO, PrincOpsUtils, Process, ProcessProps, PupName, PupStream, Rope, RPC, UnsafeStorage, UserCredentials, UserProfile, VM EXPORTS ComputeClient, ComputeClientExtras, ComputeClientInternal, ComputeServerCallbacks SHARES ComputeServerClient = BEGIN ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; Enabled: PUBLIC ComputeClientInternal.TristateBool _ false; serviceStateListBase: serviceState _ NIL; serviceState: TYPE = REF serviceStateObject; serviceStateObject: PUBLIC TYPE = RECORD [ hack: BOOL _ FALSE, --hopefully adding this field changes type hash next: serviceState _ NIL, -- NIL until added to the list of active calls (serviceStateListBase) listenerPupAddress: Pup.Address _ StreamPupAddress, -- initially bogus; once established, this is the unique ID for the connection and hence the RPC call socketReady: BOOL _ FALSE, streamReady: BOOL _ FALSE, remoteStream: STREAM _ NIL, inStreamEOF: BOOL _ FALSE, outStreamEOF: BOOL _ FALSE, enumerateItem: enumerationState _ NIL, nextFile: ComputeServerCallbacks.OpenFile _ 1, first16OpenFiles: ARRAY [1..16] OF FS.OpenFile _ ALL[FS.nullOpenFile], openFileListBase: openFileItem _ NIL, requestingProcess: PROCESS, callFailed: BOOL _ FALSE, callOver: BOOL _ FALSE, callAbandoned: BOOL _ FALSE, serverInstance: ROPE _ NIL, command: ROPE _ NIL, controllerAndServerOK: BOOL _ TRUE, found: BOOL _ TRUE, success: ComputeServerClient.RemoteSuccess, msg: ROPE _ NIL ]; openFileItem: TYPE = REF openFileItemObject; openFileItemObject: TYPE = RECORD [ next: openFileItem _ NIL, fileNumber: ComputeServerCallbacks.OpenFile, openFile: FS.OpenFile ]; serviceListObject: TYPE = ComputeClientInternal.ServiceListObject; enumerationReady: CONDITION; enumerationNeeded: CONDITION; enumerationState: TYPE = REF enumerationStateObject; enumerationStateObject: TYPE = RECORD [ needNext: BOOL _ FALSE, ready: BOOL _ FALSE, fullFName: ROPE _ NIL, attachedTo: ROPE _ NIL, created: BasicTime.GMT _ BasicTime.nullGMT , bytes: INT _ 0, keep: CARDINAL _ 0, continue: BOOLEAN _ TRUE ]; ControllerInterface: PUBLIC ComputeServerControllerRpcControl.InterfaceRecord; ControllerGVName: PUBLIC ROPE _ NIL; NoOfGetControllerInterfaceProcesses: INT _ 0 ; FirstTryToGetController: BOOL _ TRUE; serverInterfaceItem: TYPE = RECORD [ serverInstance: ROPE _ NIL, interface: ComputeServerRpcControl.InterfaceRecord _ NIL, lastUsed: BasicTime.GMT _ BasicTime.earliestGMT ]; serverInterfaceCacheSize: INT = 20; serverInterfaceArray: TYPE = ARRAY [0..serverInterfaceCacheSize) OF serverInterfaceItem; serverInterfaceCache: REF serverInterfaceArray; ClientMachineName: PUBLIC RPC.ShortROPE ; StreamPupAddress: PUBLIC Pup.Address; myNetAddressRope: PUBLIC ROPE; CachePrefixesOKToRead: PUBLIC LIST OF ROPE; disableServerIFIdle: BOOL _ FALSE; disableIFIdleAfter: INT _ 1900; disableIFIdleBefore: INT _ 700; idleMinutesTilPowerOff: INT _ 10; triedToPowerOff: BOOL _ FALSE; GetControllerInterfaceProcess: PUBLIC PROC [forceImport: BOOL _ FALSE] = { delayBeforeNextProbe: INT _ 13; MakeSureThereIsOne: ENTRY PROC RETURNS [exit: BOOL _ FALSE] = { IF NoOfGetControllerInterfaceProcesses = 0 THEN NoOfGetControllerInterfaceProcesses _ 1 ELSE RETURN[TRUE]; }; NowWeAreGone: ENTRY PROC = { NoOfGetControllerInterfaceProcesses _ 0}; importedControllerInterface: ComputeServerControllerRpcControl.InterfaceRecord _ NIL; IF forceImport THEN { DO IF ~MakeSureThereIsOne[] THEN EXIT; Process.Pause[5]; ENDLOOP; } ELSE {IF MakeSureThereIsOne[] THEN RETURN;}; FirstTryToGetController _ TRUE; WHILE importedControllerInterface = NIL DO info: GVNames.ConnectInfo; connect: GVBasics.Connect; localImportWorked: BOOL _ FALSE; [info: info, connect: connect ] _ GVNames.GetConnect[ComputeClientInternal.ControllerGVName]; IF (info = individual OR info = group) AND Rope.Equal[connect, ComputeClientInternal.myNetAddressRope] THEN TRUSTED { result: AMTypes.TV; localImportWorked _ TRUE; importedControllerInterface _ NEW[ComputeServerControllerRpcControl.InterfaceRecordObject]; result _ Interpreter.Evaluate["ComputeControllerImpl.FindService"].result; IF result = NIL THEN localImportWorked _ FALSE; importedControllerInterface.clientStubFindService _ lFindService; MyFindService _ LOOPHOLE[AMBridge.TVToProc[result]]; result _ Interpreter.Evaluate["ComputeControllerImpl.FindServiceWithQueueing"].result; IF result = NIL THEN localImportWorked _ FALSE; importedControllerInterface.clientStubFindServiceWithQueueing _ lMyFindServiceWithQueueing; MyFindServiceWithQueueing _ LOOPHOLE[AMBridge.TVToProc[result]]; result _ Interpreter.Evaluate["ComputeControllerImpl.NewStats"].result; IF result = NIL THEN localImportWorked _ FALSE; importedControllerInterface.clientStubNewStats _ lNewStats; MyNewStats _ LOOPHOLE[AMBridge.TVToProc[result]]; result _ Interpreter.Evaluate["ComputeControllerImpl.BestServerStats"].result; IF result = NIL THEN localImportWorked _ FALSE; importedControllerInterface.clientStubBestServerStats _ lBestServerStats; MyBestServerStats _ LOOPHOLE[AMBridge.TVToProc[result]]; result _ Interpreter.Evaluate["ComputeControllerImpl.NoticeNewPackage"].result; IF result = NIL THEN localImportWorked _ FALSE; importedControllerInterface.clientStubNoticeNewPackage _ lNoticeNewPackage; MyNoticeNewPackage _ LOOPHOLE[AMBridge.TVToProc[result]]; result _ Interpreter.Evaluate["ComputeControllerImpl.RemoveOldPackage"].result; IF result = NIL THEN localImportWorked _ FALSE; importedControllerInterface.clientStubRemoveOldPackage _ lRemoveOldPackage; MyRemoveOldPackage _ LOOPHOLE[AMBridge.TVToProc[result]]; result _ Interpreter.Evaluate["ComputeControllerImpl.GetSomeInfo"].result; IF result = NIL THEN localImportWorked _ FALSE; importedControllerInterface.clientStubGetSomeInfo _ lGetSomeInfo; MyGetSomeInfo _ LOOPHOLE[AMBridge.TVToProc[result]]; result _ Interpreter.Evaluate["ComputeControllerImpl.CommandUnavailable"].result; IF result = NIL THEN localImportWorked _ FALSE; importedControllerInterface.clientStubCommandUnavailable _ lCommandUnavailable; MyCommandUnavailable _ LOOPHOLE[AMBridge.TVToProc[result]]; result _ Interpreter.Evaluate["ComputeControllerImpl.ExtraCommandAvailable"].result; IF result = NIL THEN localImportWorked _ FALSE; importedControllerInterface.clientStubExtraCommandAvailable _ lExtraCommandAvailable; MyExtraCommandAvailable _ LOOPHOLE[AMBridge.TVToProc[result]]; result _ Interpreter.Evaluate[ "ComputeControllerImpl.MightAcceptQueuedCommand"].result; IF result = NIL THEN localImportWorked _ FALSE; importedControllerInterface.clientStubMightAcceptQueuedCommand _ lMightAcceptQueuedCommand; MyMightAcceptQueuedCommand _ LOOPHOLE[AMBridge.TVToProc[result]]; result _ Interpreter.Evaluate[ "ComputeControllerImpl.GenericToController"].result; IF result = NIL THEN localImportWorked _ FALSE; importedControllerInterface.clientStubGenericToController _ lGenericToController; MyGenericToController _ LOOPHOLE[AMBridge.TVToProc[result]]; }; IF ~localImportWorked THEN { importedControllerInterface _ NIL; importedControllerInterface _ ComputeServerControllerRpcControl.ImportNewInterface[interfaceName: [ type: "ComputeServerController.summoner", instance: ComputeClientInternal.ControllerGVName, version: [1,1]] ! RPC.ImportFailed => { delayBeforeNextProbe _ MIN[delayBeforeNextProbe+3, 180]; Process.Pause[Process.SecondsToTicks[delayBeforeNextProbe]]; CONTINUE; }; ]; }; FirstTryToGetController _ FALSE; ENDLOOP; ComputeClientInternal.ControllerInterface _ importedControllerInterface; NowWeAreGone[]; }; TryToImportController: PUBLIC PROC = { IF NoOfGetControllerInterfaceProcesses = 1 THEN RETURN; TRUSTED {Process.Detach[FORK GetControllerInterfaceProcess[]]; }; Process.Pause[Process.SecondsToTicks[1]]; WHILE NoOfGetControllerInterfaceProcesses = 1 AND FirstTryToGetController DO Process.Pause[Process.SecondsToTicks[1]]; ENDLOOP; }; BestServerStatsDisabled: PROC RETURNS[success: ComputeServerClient.RemoteSuccess _ false, selfIsBest: BOOL_ TRUE, FOM: REAL _ 1.0] = { RETURN [clientNotRunning, FALSE, 1.0]; }; StartServiceDisabled: PROC [service: ROPE, version: ROPE, cmdLine: ROPE, in, out: STREAM, queueService: BOOL _ FALSE, timeToWait: INT _ 3600, retries: NAT _ 3] RETURNS [found: BOOL _ TRUE, success: ComputeServerClient.RemoteSuccess _ false, remoteMsg: ROPE _ NIL, serverInstance: ROPE _ NIL] = { RETURN [FALSE, clientNotRunning, "Client Not Enabled", NIL]; }; StartService: PUBLIC PROC [service: ROPE, version: ROPE, cmdLine: ROPE, in, out: STREAM, queueService: BOOL _ FALSE, timeToWait: INT _ 3600, retries: NAT _ 3] RETURNS [found: BOOL _ TRUE, success: ComputeServerClient.RemoteSuccess _ false, remoteMsg: ROPE _ NIL, serverInstance: ROPE _ NIL] = { RETURN StartServiceExtra[service, version, cmdLine, in, out, queueService, timeToWait, retries, NIL]; }; StartServiceExtra: PUBLIC PROC [service: ROPE, version: ROPE, cmdLine: ROPE, in, out: STREAM, queueService: BOOL _ FALSE, timeToWait: INT _ 3600, retries: NAT _ 3, serverName: ROPE _ NIL] RETURNS [found: BOOL _ TRUE, success: ComputeServerClient.RemoteSuccess _ false, remoteMsg: ROPE _ NIL, serverInstance: ROPE _ NIL] = { importCounter: INT _ 0 ; workingDirectory: ROPE _ NARROW [ ProcessProps.GetProp[$WorkingDirectory] ]; serviceProcess: PROCESS; currentService: serviceState; tempControllerInterface: ComputeServerControllerRpcControl.InterfaceRecord ; controllerAndServerOK: BOOL _ TRUE; count: CARDINAL _ 0 ; abortCount: CARDINAL _ 0; abandon: BOOL _ FALSE; needIn: BOOL _ TRUE; needOut: BOOL _ TRUE; DoAbort: PROC [serviceToAbort: serviceState, fullAbort: BOOL _ FALSE] = { IF abortCount = 0 THEN TRUSTED { Process.Detach[FORK TryToAbortProcess[serviceToAbort]]; }; abortCount _ abortCount + 1; IF abortCount = 3 OR fullAbort THEN { TRUSTED {Process.Detach[serviceProcess];}; serviceToAbort.callFailed _ TRUE; serviceToAbort.callOver _ TRUE; serviceToAbort.callAbandoned _ TRUE; abandon _ TRUE; DestroyServiceItem[serviceToAbort.listenerPupAddress, serviceToAbort]; }; }; { -- begin of block for ENABLE ABORTED ENABLE ABORTED => { DoAbort[currentService]; }; monitorAndBufferStreams: PROC = { msg: ROPE _ NIL; noPages: INT = 2; bufferBlockSize: INT = VM.BytesForPages[noPages]; textBuffer: REF TEXT = NEW[TEXT [bufferBlockSize]]; WHILE ~currentService.callFailed AND (~currentService.callOver OR ~currentService.outStreamEOF) AND (~currentService.inStreamEOF OR ~currentService.outStreamEOF) DO doneSomething: BOOL _ FALSE; Process.CheckForAbort[ ! ABORTED => {DoAbort[currentService]; CONTINUE;};]; IF (needIn OR needOut) AND currentService.socketReady THEN { inOutPupStream: STREAM _ NIL; inOutPupStream _ PupStream.Create[remote: currentService.listenerPupAddress, getTimeout: 1000, putTimeout: PupStream.waitForever ! PupStream.StreamClosing => { msg _ Rope.Concat["Unable to open Pup Byte Stream to Server", SELECT why FROM noRouteToNetwork => " because noRouteToNetwork", transmissionTimeout => " because transmissionTimeout", remoteReject => " because remoteReject", ENDCASE => ""]; GOTO streamOpenFailed; }; ] ; currentService.remoteStream _ inOutPupStream; currentService.streamReady _ TRUE; -- must set streamReady before ~socketReady currentService.socketReady _ FALSE; EXITS streamOpenFailed => { currentService.msg _ msg; currentService.socketReady _ FALSE; DoAbort[currentService, TRUE]; }; }; IF currentService.streamReady AND ~currentService.inStreamEOF AND in.CharsAvail[] > 0 THEN { WHILE in.CharsAvail[] > 0 AND ~currentService.inStreamEOF DO currentService.remoteStream.PutChar[in.GetChar[! IO.EndOfStream => { currentService.inStreamEOF _ TRUE; PupStream.SendMark[currentService.remoteStream, 26B ! PupStream.StreamClosing => CONTINUE;]; CONTINUE; }; PupStream.StreamClosing => { currentService.inStreamEOF _ TRUE; CONTINUE; }; ]]; ENDLOOP; currentService.remoteStream.Flush[ ! PupStream.StreamClosing => { currentService.inStreamEOF _ TRUE; CONTINUE; }; ]; doneSomething _ TRUE; }; IF currentService.callOver AND currentService.streamReady AND currentService.remoteStream.CharsAvail[] = 0 THEN currentService.outStreamEOF _ TRUE; IF currentService.streamReady AND ~currentService.outStreamEOF AND currentService.remoteStream.CharsAvail[] > 0 THEN { charsWanted: INT _ currentService.remoteStream.CharsAvail[]; nBytesRead: INT; TRUSTED { nBytesRead _ currentService.remoteStream.GetBlock[textBuffer, 0, MIN[charsWanted, bufferBlockSize]]; }; IF nBytesRead = 0 AND currentService.remoteStream.EndOf[] THEN currentService.outStreamEOF _ TRUE; IF out # NIL AND ~currentService.outStreamEOF THEN out.PutBlock[textBuffer, 0, nBytesRead]; doneSomething _ TRUE; }; IF ~doneSomething THEN Process.Pause[5 ! ABORTED => {DoAbort[currentService]; CONTINUE;};]; ENDLOOP; }; IF in = NIL OR in = IO.noInputStream THEN needIn _ FALSE; IF out = NIL OR out = IO.noWhereStream THEN needOut _ FALSE; WHILE found AND count < retries AND (controllerAndServerOK OR (count <= 1)) AND success = false AND ~abandon DO count _ count + 1; abortCount _ 0; currentService _ NEW[serviceStateObject]; -- new object per loop => new object per fork currentService.requestingProcess _ LOOPHOLE[Process.GetCurrent[]]; tempControllerInterface _ ControllerInterface; IF serverName = NIL AND tempControllerInterface = NIL THEN { -- try to get a new interface if this one is NIL; not needed if we have an explicit serverName msecInFourTicks: CARDINAL = Process.TicksToMsec[4]; loopsForFiveSeconds: INT = (5*1000)/msecInFourTicks; ComputeClientInternal.TryToImportController[]; FOR loopCount: INT IN [0 .. loopsForFiveSeconds) DO tempControllerInterface _ ControllerInterface; IF tempControllerInterface # NIL THEN EXIT; Process.Pause[4]; ENDLOOP; IF tempControllerInterface = NIL THEN RETURN[FALSE, cantImportController, "Controller cannot be Imported - may be down or recovering"]; }; serviceProcess _ FORK ServiceProcess[tempControllerInterface, currentService, service, version, timeToWait, cmdLine, ClientMachineName, queueService, workingDirectory, needIn, needOut, serverName]; IF ~needIn THEN currentService.inStreamEOF _ TRUE; IF ~needOut THEN currentService.outStreamEOF _ TRUE; monitorAndBufferStreams[]; -- this is where we spend almost all of the call IF currentService.remoteStream # NIL THEN currentService.remoteStream.Close[ ! PupStream.StreamClosing => CONTINUE;]; WHILE ~currentService.callAbandoned AND ~currentService.callOver AND ~currentService.callFailed DO Process.Pause[2 ! ABORTED => {DoAbort[currentService]; CONTINUE;};]; ENDLOOP; IF ~currentService.callAbandoned THEN { TRUSTED {[] _ JOIN serviceProcess;}; controllerAndServerOK _ currentService.controllerAndServerOK; found _ currentService.found; success _ currentService.success; remoteMsg _ currentService.msg; serverInstance _ currentService.serverInstance; }; ENDLOOP; }; -- end of block for ENABLE ABORTED }; ServiceProcess: PROC [controllerInterface: ComputeServerControllerRpcControl.InterfaceRecord, currentService: serviceState, service: ROPE, version: ROPE, timeToWait: INT, cmdLine: ROPE, clientMachineName: RPC.ShortROPE, queueService: BOOL, workingDirectory: ROPE, needRemoteInStream: BOOL, needRemoteOutStream: BOOL, serverName: ROPE ] = { controllerAndServerOK: BOOL _ TRUE; found: BOOL _ TRUE; success: ComputeServerClient.RemoteSuccess; msg: ROPE _ NIL; userName: RPC.ShortROPE = UserCredentials.Get[].name; serverInstance: RPC.ShortROPE; serverPupAddress: Pup.Address; serverInterface: ComputeServerRpcControl.InterfaceRecord; askForServiceErrMsg: ROPE; errMsg: Rope.ROPE _ NIL; askFound: ATOM; currentService.serverInstance _ NIL; currentService.command _ service; { IF queueService AND serverName = NIL THEN { [found: askFound, instance: serverInstance, serverPupAddress: serverPupAddress, errMsg: errMsg] _ controllerInterface.FindServiceWithQueueing[service: service, userName: userName, version: version, timeToWait: timeToWait, clientMachineName: clientMachineName, streamPupAddress: StreamPupAddress, needListener: (needRemoteInStream OR needRemoteOutStream) ! RPC.CallFailed => { currentService.callFailed _ TRUE; ControllerInterface _ NIL; GOTO controllerCallFailed; }; ]; IF askFound = $foundOK THEN { currentService.serverInstance _ serverInstance; serverInterface _ getServerInterfaceFromCache[serverInstance]; IF serverInterface = NIL THEN { currentService.callFailed _ TRUE; currentService.controllerAndServerOK _ FALSE; currentService.found _ TRUE; currentService.success _ cantImportServer; currentService.msg _ "Cannot Import from Server Selected by Controller"; RETURN; }; } ELSE found _ FALSE; } ELSE { -- not queueService or specified server askForServiceCount: INT _ 0; errorMessageX: ROPE _ NIL; IF serverName # NIL THEN { askFound _ $foundOK; errorMessageX _ "Cannot Import from Server specified by request"; serverPupAddress _ PupName.NameLookup[serverName, Pup.nullSocket ! PupName.Error => GOTO badName]; serverInstance _ PupName.AddressToRope[serverPupAddress]; } ELSE { errorMessageX _ "Cannot Import from Server Selected by Controller"; [found: found, instance: serverInstance] _ controllerInterface.FindService[service, userName ! RPC.CallFailed => { currentService.callFailed _ TRUE; ControllerInterface _ NIL; GOTO controllerCallFailed; }; ]; IF ~found THEN { currentService.callFailed _ TRUE; currentService.controllerAndServerOK _ TRUE; currentService.found _ found; currentService.success _ false; currentService.msg _ "Requested command not found"; RETURN; }; }; currentService.serverInstance _ serverInstance; serverInterface _ getServerInterfaceFromCache[serverInstance]; IF serverInterface = NIL THEN { currentService.callFailed _ TRUE; currentService.controllerAndServerOK _ FALSE; currentService.found _ TRUE; currentService.success _ cantImportServer; currentService.msg _ errorMessageX; RETURN; }; [found: askFound, serverPupAddress: serverPupAddress, errMsg: askForServiceErrMsg] _ serverInterface.AskForService[service: service, version: version, clientMachineName: clientMachineName, userName: userName ! RPC.CallFailed => { askForServiceCount _ askForServiceCount + 1; IF askForServiceCount = 1 THEN { [] _ deleteServerInterfaceFromCache[serverInterface]; serverInterface _ getServerInterfaceFromCache[serverInstance]; IF serverInterface # NIL THEN RETRY; }; currentService.callFailed _ TRUE; [] _ deleteServerInterfaceFromCache[serverInterface]; currentService.msg _ "Server did not respond to 'AskForService' request"; GOTO serverCallFailed; }; ]; }; SELECT askFound FROM $notFound => { currentService.callFailed _ TRUE; currentService.controllerAndServerOK _ TRUE; currentService.found _ FALSE; currentService.success _ commandNotFound; currentService.msg _ askForServiceErrMsg; currentService.serverInstance _ serverInstance; RETURN; }; $foundButTooBusy => { currentService.callFailed _ TRUE; currentService.controllerAndServerOK _ TRUE; currentService.found _ FALSE; currentService.success _ serverTooBusy; currentService.msg _ askForServiceErrMsg; currentService.serverInstance _ serverInstance; RETURN; }; $foundOK => { doServiceCount: INT _ 0 ; AddPupAddress[newItem: currentService, serverPupAddress: serverPupAddress] ; IF needRemoteInStream OR needRemoteOutStream THEN { currentService.socketReady _ TRUE; }; msg _ NIL; -- see comment on the GOTO above [success: success, msg: msg] _ serverInterface.DoService[serverPupAddress, myNetAddressRope, cmdLine, workingDirectory, needRemoteInStream, needRemoteOutStream ! RPC.CallFailed => { doServiceCount _ doServiceCount + 1; IF doServiceCount = 1 THEN { [] _ deleteServerInterfaceFromCache[serverInterface]; serverInterface _ getServerInterfaceFromCache[serverInstance]; IF serverInterface # NIL THEN RETRY; }; currentService.callFailed _ TRUE; [] _ deleteServerInterfaceFromCache[serverInterface]; DestroyServiceItem[serverPupAddress, currentService]; currentService.msg _ "Server did not respond to 'DoService' request"; GOTO serverCallFailed; }; ]; DestroyServiceItem[serverPupAddress, currentService]; currentService.callOver _ TRUE; }; $timeOut => { currentService.callFailed _ TRUE; currentService.controllerAndServerOK _ TRUE; currentService.found _ TRUE; currentService.success _ timeOut; currentService.msg _ "Call timed out"; RETURN; }; ENDCASE => { currentService.callFailed _ TRUE; currentService.controllerAndServerOK _ TRUE; currentService.found _ TRUE; currentService.success _ serverTooBusy; currentService.msg _ Rope.Cat["Return atom ", Atom.GetPName[askFound]," not understood"]; currentService.serverInstance _ serverInstance; RETURN; }; currentService.controllerAndServerOK _ controllerAndServerOK; currentService.found _ found; currentService.success _ success; currentService.msg _ Rope.Concat[askForServiceErrMsg, msg]; EXITS controllerCallFailed => { currentService.controllerAndServerOK _ FALSE; currentService.found _ FALSE; currentService.success _ false; currentService.msg _ "Call to the Controller Failed"; currentService.serverInstance _ NIL; RETURN; }; serverCallFailed => { currentService.callFailed _ TRUE; DestroyServiceItem[serverPupAddress, currentService]; currentService.controllerAndServerOK _ FALSE; currentService.found _ TRUE; currentService.success _ false; RETURN; }; badName => { currentService.callFailed _ TRUE; currentService.controllerAndServerOK _ FALSE; currentService.found _ FALSE; currentService.success _ false; currentService.msg _ "Bad server name"; currentService.serverInstance _ NIL; RETURN; }; }; }; DestroyServiceItem: PROC [serverPupAddress: Pup.Address, currentService: serviceState] = { IF DeletePupAddress[serverPupAddress] THEN { FOR file: INT IN [1..16] DO FS.Close[currentService.first16OpenFiles[file] ! FS.Error => CONTINUE;]; currentService.first16OpenFiles[file] _ FS.nullOpenFile; ENDLOOP; FOR nowItem: openFileItem _ currentService.openFileListBase, nowItem.next UNTIL nowItem = NIL DO FS.Close[nowItem.openFile ! FS.Error => CONTINUE;]; nowItem.openFile _ FS.nullOpenFile; ENDLOOP; }; }; TryToAbortProcess: PROC [currentService: serviceState ] = { serverInterface: ComputeServerRpcControl.InterfaceRecord; WHILE ~currentService.streamReady DO IF currentService.callFailed OR currentService.callOver THEN RETURN; Process.Pause[7]; ENDLOOP; serverInterface _ getServerInterfaceFromCache[currentService.serverInstance]; IF serverInterface # NIL THEN serverInterface.AskForAbort[currentService.listenerPupAddress ! RPC.CallFailed => CONTINUE;]; }; getServerInterfaceFromCache: ENTRY PROC [serverInstance: RPC.ShortROPE] RETURNS [serverInterface: ComputeServerRpcControl.InterfaceRecord _ NIL] = { newServerInterface: ComputeServerRpcControl.InterfaceRecord _ NIL; bestIndex: INT _ 0; bestTime: BasicTime.GMT _ BasicTime.latestGMT; now: BasicTime.GMT _ BasicTime.Now[]; FOR index: INT IN [0..serverInterfaceCacheSize) DO IF Rope.Equal[serverInstance, serverInterfaceCache[index].serverInstance] THEN { newServerInterface _ serverInterfaceCache[index].interface; serverInterfaceCache[index].lastUsed _ now; RETURN[serverInterfaceCache[index].interface]; }; IF BasicTime.Period[bestTime, serverInterfaceCache[index].lastUsed] < 0 THEN { bestTime _ serverInterfaceCache[index].lastUsed; bestIndex _ index; }; ENDLOOP; newServerInterface _ ComputeServerRpcControl.ImportNewInterface[ interfaceName: [ type: "ComputeServer.summoner", instance: serverInstance, version: [1,1]] ! RPC.ImportFailed => { CONTINUE; }; ]; IF newServerInterface # NIL THEN { serverInterfaceCache[bestIndex].lastUsed _ now; serverInterfaceCache[bestIndex].serverInstance _ serverInstance; serverInterfaceCache[bestIndex].interface _ newServerInterface; }; RETURN[newServerInterface]; }; deleteServerInterfaceFromCache: ENTRY PROC [serverInterface: ComputeServerRpcControl.InterfaceRecord] RETURNS [gotIt: BOOL _ FALSE] = { FOR index: INT IN [0..serverInterfaceCacheSize) DO IF serverInterfaceCache[index].interface = serverInterface THEN { serverInterfaceCache[index].serverInstance _ NIL; serverInterfaceCache[index].interface _ NIL; serverInterfaceCache[index].lastUsed _ BasicTime.earliestGMT; gotIt _ TRUE; EXIT; }; ENDLOOP; }; MakeUnmatchedError: PROC [] = { ERROR ComputeServerCallbacks.Error[[ $environment, $serverUnmatchedComputation, "remote FS operation performed on server that does not know about the computation"]]; }; MakeEnumerationBugError: PROC [] = { ERROR ComputeServerCallbacks.Error[[ $bug, $serverEnumerationBug, "remote FS enumeration error"]]; }; MakeError: PROC [error: FS.ErrorDesc] = { ERROR ComputeServerCallbacks.Error[[ error.group, error.code, error.explanation.Substr[0, MIN[60, error.explanation.Length[]]]]]; }; rGeneric: PUBLIC PROC [requestCode: ATOM, requestString: ROPE] RETURNS [resultCode: ATOM, resultString: ROPE] = { RETURN [$notImplemented, NIL]; }; rSetDefaultWDir: PUBLIC PROC [dir: RPC.ShortROPE] = { ENABLE FS.Error => {MakeError[error]; }; FS.SetDefaultWDir[dir]; }; rGetDefaultWDir: PUBLIC PROC RETURNS [RPC.ShortROPE] = { ENABLE FS.Error => {MakeError[error]; }; RETURN[FS.GetDefaultWDir[]]; }; rExpandName: PUBLIC PROC[name: ROPE, wDir: RPC.ShortROPE] RETURNS [fullFName: ROPE, cp: FS.ComponentPositions, dirOmitted: BOOLEAN] = { ENABLE FS.Error => {MakeError[error]; }; [fullFName, cp, dirOmitted] _ FS.ExpandName[name, wDir]; }; rFileInfo: PUBLIC PROC [name: ROPE, wantedCreatedTime: BasicTime.GMT, remoteCheck: BOOLEAN, wDir: RPC.ShortROPE] RETURNS [fullFName, attachedTo: ROPE, keep: CARDINAL, bytes: INT, created: BasicTime.GMT] = { ENABLE FS.Error => {MakeError[error]; }; [fullFName, attachedTo, keep, bytes, created] _ FS.FileInfo[name, wantedCreatedTime, remoteCheck, wDir]; }; rStartEnumerateForInfo: PUBLIC PROC [listenerPupAddress: Pup.Address, pattern: ROPE, wDir: RPC.ShortROPE] RETURNS [fullFName, attachedTo: ROPE, created: BasicTime.GMT, bytes: INT, keep: CARDINAL, continue: BOOLEAN] = { ENABLE FS.Error => {MakeError[error]; }; item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; IF item.enumerateItem # NIL THEN MakeEnumerationBugError[]; item.enumerateItem _ NEW[enumerationStateObject]; TRUSTED {Process.Detach[ FORK enumerationInfoProcess[item, pattern, wDir]];}; [fullFName, attachedTo, created, bytes, keep, continue] _ getEnumerateForInfo[item.enumerateItem]; }; rNextEnumerateForInfo: PUBLIC PROC [listenerPupAddress: Pup.Address] RETURNS [fullFName, attachedTo: ROPE, created: BasicTime.GMT, bytes: INT, keep: CARDINAL, continue: BOOLEAN] = { ENABLE FS.Error => {MakeError[error]; }; item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; IF item.enumerateItem = NIL THEN MakeEnumerationBugError[]; [fullFName, attachedTo, created, bytes, keep, continue] _ getEnumerateForInfo[item.enumerateItem]; }; rStartEnumerateForNames: PUBLIC PROC [listenerPupAddress: Pup.Address, pattern: ROPE, wDir: RPC.ShortROPE] RETURNS [fullFName: ROPE, continue: BOOLEAN] = { ENABLE FS.Error => {MakeError[error]; }; item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; IF item.enumerateItem # NIL THEN MakeEnumerationBugError[]; item.enumerateItem _ NEW[enumerationStateObject]; TRUSTED {Process.Detach[ FORK enumerationNameProcess[item, pattern, wDir]];}; [fullFName, continue] _ getEnumerateForName[item.enumerateItem]; }; rNextEnumerateForNames: PUBLIC PROC [listenerPupAddress: Pup.Address] RETURNS [fullFName: ROPE, continue: BOOLEAN] = { ENABLE FS.Error => {MakeError[error]; }; item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; IF item.enumerateItem = NIL THEN MakeEnumerationBugError[]; [fullFName, continue] _ getEnumerateForName[item.enumerateItem]; }; rDoneEnumerate: PUBLIC PROC [listenerPupAddress: Pup.Address] = { setDone: ENTRY PROC = { item.enumerateItem.continue _ FALSE; BROADCAST enumerationNeeded; WHILE item.enumerateItem # NIL DO WAIT enumerationReady; ENDLOOP; }; item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; IF item.enumerateItem = NIL THEN MakeEnumerationBugError[]; setDone[]; }; enumerationInfoProcess: PROC [item: serviceState, pattern: ROPE, wDir: ROPE] = { enumerateItem: enumerationState = item.enumerateItem; inner: FS.InfoProc = { enterNext: ENTRY PROC = { enumerateItem.fullFName _ fullFName; enumerateItem.attachedTo _ attachedTo; enumerateItem.created _ created; enumerateItem.bytes _ bytes; enumerateItem.keep _ keep; enumerateItem.ready _ TRUE; enumerateItem.needNext _ FALSE; BROADCAST enumerationReady; WHILE ~enumerateItem.needNext AND enumerateItem.continue DO WAIT enumerationNeeded; ENDLOOP; }; enterNext[]; RETURN[enumerateItem.continue]; }; innerDone: ENTRY PROC = { enumerateItem.continue _ FALSE; enumerateItem.ready _ TRUE; item.enumerateItem _ NIL ; BROADCAST enumerationReady; }; FS.EnumerateForInfo[pattern, inner, wDir]; innerDone[]; }; getEnumerateForInfo: ENTRY PROC [enumerateItem: enumerationState] RETURNS [fullFName, attachedTo: ROPE, created: BasicTime.GMT, bytes: INT, keep: CARDINAL, continue: BOOL] = { enumerateItem.needNext _ TRUE; WHILE ~enumerateItem.ready DO BROADCAST enumerationNeeded; WAIT enumerationReady; ENDLOOP; enumerateItem.ready _ FALSE; RETURN[enumerateItem.fullFName, enumerateItem.attachedTo, enumerateItem.created, enumerateItem.bytes, enumerateItem.keep, enumerateItem.continue]; }; enumerationNameProcess: PROC [item: serviceState, pattern: ROPE, wDir: ROPE] = { enumerateItem: enumerationState = item.enumerateItem; inner: FS.NameProc = { enterNext: ENTRY PROC = { enumerateItem.fullFName _ fullFName; enumerateItem.ready _ TRUE; enumerateItem.needNext _ FALSE; BROADCAST enumerationReady; WHILE ~enumerateItem.needNext AND enumerateItem.continue DO WAIT enumerationNeeded; ENDLOOP; }; enterNext[]; RETURN[enumerateItem.continue]; }; innerDone: ENTRY PROC = { enumerateItem.continue _ FALSE; enumerateItem.ready _ TRUE; item.enumerateItem _ NIL ; BROADCAST enumerationReady; }; FS.EnumerateForNames[pattern, inner, wDir]; innerDone[]; }; getEnumerateForName: ENTRY PROC [enumerateItem: enumerationState] RETURNS [fullFName: ROPE, continue: BOOL] = { enumerateItem.needNext _ TRUE; WHILE ~enumerateItem.ready DO BROADCAST enumerationNeeded; WAIT enumerationReady; ENDLOOP; enumerateItem.ready _ FALSE; RETURN[enumerateItem.fullFName, enumerateItem.continue]; }; rOpen: PUBLIC PROC [listenerPupAddress: Pup.Address, name: ROPE, lock: FS.Lock _ $read, wantedCreatedTime: BasicTime.GMT _ BasicTime.nullGMT, remoteCheck: BOOLEAN _ TRUE, wDir: RPC.ShortROPE, forceRemoteOpen: BOOL _ FALSE] RETURNS [globalNameToOpen: ROPE _ NIL, openFile: ComputeServerCallbacks.OpenFile _ 0] = { ENABLE FS.Error => {MakeError[error]; }; cacheNameProc: FSBackdoor.NameProc = { gotOne _ TRUE; }; localOpenFile: FS.OpenFile; item: serviceState; found: BOOL; fullFName, attachedTo: ROPE; keep: CARDINAL; created: BasicTime.GMT; gotOne: BOOL _ FALSE; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; [fullFName: fullFName, attachedTo: attachedTo, keep: keep, created: created] _ FS.FileInfo[name, wantedCreatedTime, remoteCheck, wDir]; IF keep = 0 THEN attachedTo _ fullFName; -- global filenames return a keep of 0 FSBackdoor.EnumerateCacheForNames[proc: cacheNameProc, volName: NIL, pattern: attachedTo]; IF gotOne AND Rope.Length[attachedTo] > 0 AND lock = $read AND ~forceRemoteOpen THEN { prefixFound: BOOL _ FALSE; globalNameToOpen _ attachedTo; FOR l: LIST OF ROPE _ CachePrefixesOKToRead, l.rest UNTIL l = NIL DO IF Rope.Find[attachedTo, l.first, 0, FALSE] = 0 THEN {prefixFound _ TRUE; EXIT;}; ENDLOOP; IF prefixFound AND (listenerPupAddress.net = StreamPupAddress.net) THEN openFile _ -1 } ELSE { localOpenFile _ FS.Open[name, lock, wantedCreatedTime, remoteCheck, wDir]; openFile _ addOpenFileToServiceState[item, localOpenFile]; }; }; rCreate: PUBLIC PROC [listenerPupAddress: Pup.Address, name: ROPE, setPages: BOOLEAN _ TRUE, pages: INT _ 0, setKeep: BOOLEAN _ FALSE, keep: CARDINAL _ 1, wDir: RPC.ShortROPE] RETURNS [openFile: ComputeServerCallbacks.OpenFile _ 0] = { ENABLE FS.Error => {MakeError[error]; }; localOpenFile: FS.OpenFile; item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; localOpenFile _ FS.Create[name, setPages, pages, setKeep, keep, wDir]; openFile _ addOpenFileToServiceState[item, localOpenFile]; }; rOpenOrCreate: PUBLIC PROC [listenerPupAddress: Pup.Address, name: ROPE, keep: CARDINAL _ 1, pages: INT _ 5, wDir: RPC.ShortROPE] RETURNS [openFile: ComputeServerCallbacks.OpenFile _ 0] = { ENABLE FS.Error => {MakeError[error]; }; localOpenFile: FS.OpenFile; item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; localOpenFile _ FS.OpenOrCreate[name, keep, pages, wDir]; openFile _ addOpenFileToServiceState[item, localOpenFile]; }; rGetClass: PUBLIC PROC [listenerPupAddress: Pup.Address, file: ComputeServerCallbacks.OpenFile] RETURNS [ATOM] = { ENABLE FS.Error => {MakeError[error]; }; localOpenFile: FS.OpenFile; item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; localOpenFile _ findOpenFileInServiceState[item, file]; RETURN[FS.GetClass[localOpenFile]]; }; rSameFile: PUBLIC PROC [listenerPupAddress: Pup.Address, file1, file2: ComputeServerCallbacks.OpenFile] RETURNS [BOOLEAN] = { ENABLE FS.Error => {MakeError[error]; }; localOpenFile1, localOpenFile2: FS.OpenFile; item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; localOpenFile1 _ findOpenFileInServiceState[item, file1]; localOpenFile2 _ findOpenFileInServiceState[item, file2]; RETURN[FS.SameFile[localOpenFile1, localOpenFile2]]; }; rGetName: PUBLIC PROC [listenerPupAddress: Pup.Address, file: ComputeServerCallbacks.OpenFile] RETURNS [fullFName, attachedTo: ROPE] = { ENABLE FS.Error => {MakeError[error]; }; localOpenFile: FS.OpenFile; item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; localOpenFile _ findOpenFileInServiceState[item, file]; [fullFName, attachedTo] _ FS.GetName[localOpenFile]; }; rGetInfo: PUBLIC PROC [listenerPupAddress: Pup.Address, file: ComputeServerCallbacks.OpenFile] RETURNS [keep: CARDINAL, pages, bytes: INT, created: BasicTime.GMT, lock: FS.Lock] = { ENABLE FS.Error => {MakeError[error]; }; localOpenFile: FS.OpenFile; item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; localOpenFile _ findOpenFileInServiceState[item, file]; [keep, pages, bytes, created, lock] _ FS.GetInfo[localOpenFile]; }; rSetPageCount: PUBLIC PROC [listenerPupAddress: Pup.Address, file: ComputeServerCallbacks.OpenFile, pages: INT] = { ENABLE FS.Error => {MakeError[error]; }; localOpenFile: FS.OpenFile; item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; localOpenFile _ findOpenFileInServiceState[item, file]; FS.SetPageCount[localOpenFile, pages]; }; rSetByteCountAndCreatedTime: PUBLIC PROC [listenerPupAddress: Pup.Address, file: ComputeServerCallbacks.OpenFile, bytes: INT _ -1, created: BasicTime.GMT _ BasicTime.nullGMT] = { ENABLE FS.Error => {MakeError[error]; }; localOpenFile: FS.OpenFile; item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; localOpenFile _ findOpenFileInServiceState[item, file]; FS.SetByteCountAndCreatedTime[localOpenFile, bytes, created]; }; rRead: PUBLIC PROC [listenerPupAddress: Pup.Address, file: ComputeServerCallbacks.OpenFile, from, nPages: INT, pageBuffer: ComputeServerCallbacks.RESULTPageBuffer] = { ENABLE FS.Error => {MakeError[error]; }; localOpenFile: FS.OpenFile; item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; localOpenFile _ findOpenFileInServiceState[item, file]; TRUSTED { IF BASE[pageBuffer] = VM.AddressForPageNumber[ VM.PageNumberForAddress[BASE[pageBuffer]]] THEN { FS.Read[localOpenFile, from, nPages, BASE[pageBuffer]]; -- buffer page aligned } ELSE { vmBuffer: VM.Interval _ VM.Allocate[nPages]; vmBufferAddress: LONG POINTER _ VM.AddressForPageNumber[vmBuffer.page]; { ENABLE UNWIND => IF vmBuffer.page # 0 THEN VM.Free[vmBuffer ! VM.AddressFault => CONTINUE;]; FS.Read[localOpenFile, from, nPages, vmBufferAddress]; PrincOpsUtils.LongCopy[from: vmBufferAddress, nwords: VM.WordsForPages[nPages], to: BASE[pageBuffer]]; VM.Free[vmBuffer]; }; }; }; }; rWrite: PUBLIC PROC [listenerPupAddress: Pup.Address, file: ComputeServerCallbacks.OpenFile, to: INT, nPages: INT, pageBuffer: ComputeServerCallbacks.VALUEPageBuffer] = { ENABLE FS.Error => {MakeError[error]; }; localOpenFile: FS.OpenFile; item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; localOpenFile _ findOpenFileInServiceState[item, file]; TRUSTED { IF BASE[pageBuffer] = VM.AddressForPageNumber[ VM.PageNumberForAddress[BASE[pageBuffer]]] THEN { FS.Write[localOpenFile, to, nPages, BASE[pageBuffer]]; -- buffer page aligned } ELSE { vmBuffer: VM.Interval _ VM.Allocate[nPages]; vmBufferAddress: LONG POINTER _ VM.AddressForPageNumber[vmBuffer.page]; { ENABLE UNWIND => IF vmBuffer.page # 0 THEN VM.Free[vmBuffer ! VM.AddressFault => CONTINUE;]; PrincOpsUtils.LongCopy[from: BASE[pageBuffer], nwords: VM.WordsForPages[nPages], to: vmBufferAddress]; FS.Write[localOpenFile, to, nPages, vmBufferAddress]; VM.Free[vmBuffer]; }; }; }; }; rClose: PUBLIC PROC [listenerPupAddress: Pup.Address, file: ComputeServerCallbacks.OpenFile] = { ENABLE FS.Error => {MakeError[error]; }; localOpenFile: FS.OpenFile; item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; localOpenFile _ findOpenFileInServiceState[item, file]; FS.Close[localOpenFile ! FS.Error => MakeError[error]]; removeOpenFileFromServiceState[item, file]; }; rCopy: PUBLIC PROC [listenerPupAddress: Pup.Address, from, to: ROPE, setKeep: BOOLEAN _ FALSE, keep: CARDINAL _ 1, wantedCreatedTime: BasicTime.GMT _ BasicTime.nullGMT, remoteCheck: BOOLEAN _ TRUE, attach: BOOLEAN _ FALSE, wDir: RPC.ShortROPE _ NIL] RETURNS [toFName: ROPE] = { ENABLE FS.Error => {MakeError[error]; }; item: serviceState; found: BOOL; toFName: ROPE; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; [toFName: toFName] _ FS.Copy[from, to, setKeep, keep, wantedCreatedTime, remoteCheck, attach, wDir]; }; rDelete: PUBLIC PROC [listenerPupAddress: Pup.Address, name: ROPE, wantedCreatedTime: BasicTime.GMT _ BasicTime.nullGMT, wDir: RPC.ShortROPE _ NIL] = { ENABLE FS.Error => {MakeError[error]; }; item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; FS.Delete[name, wantedCreatedTime, wDir]; }; rRename: PUBLIC PROC [listenerPupAddress: Pup.Address, from, to: ROPE, setKeep: BOOLEAN _ FALSE, keep: CARDINAL _ 1, wantedCreatedTime: BasicTime.GMT _ BasicTime.nullGMT, wDir: RPC.ShortROPE _ NIL] = { ENABLE FS.Error => {MakeError[error]; }; item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; FS.Rename[from, to, setKeep, keep, wantedCreatedTime, wDir]; }; rSetKeep: PUBLIC PROC [listenerPupAddress: Pup.Address, name: ROPE, keep: CARDINAL _ 1, wDir: RPC.ShortROPE _ NIL] = { ENABLE FS.Error => {MakeError[error]; }; item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; FS.SetKeep[name, keep, wDir]; }; rBoolean: PUBLIC PROC [listenerPupAddress: Pup.Address, key: Rope.ROPE, default: BOOLEAN _ FALSE] RETURNS [value: BOOLEAN] = { item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; RETURN [UserProfile.Boolean[key, default]]; }; rNumber: PUBLIC PROC [listenerPupAddress: Pup.Address, key: Rope.ROPE, default: INT _ 0] RETURNS [value: INT] = { item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; RETURN [UserProfile.Number[key, default]]; }; rToken: PUBLIC PROC [listenerPupAddress: Pup.Address, key: Rope.ROPE, default: Rope.ROPE _ NIL] RETURNS [value: Rope.ROPE] = { item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; RETURN [UserProfile.Token[key, default]]; }; rListOfTokens: PUBLIC PROC [listenerPupAddress: Pup.Address, key: Rope.ROPE, default: LIST OF Rope.ROPE _ NIL] RETURNS [value: LIST OF Rope.ROPE] = { item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; RETURN [UserProfile.ListOfTokens[key, default]]; }; rLine: PUBLIC PROC [listenerPupAddress: Pup.Address, key: Rope.ROPE, default: Rope.ROPE _ NIL] RETURNS [value: Rope.ROPE] = { item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; RETURN [UserProfile.Line[key, default]]; }; rGetProfileName: PUBLIC PROC [listenerPupAddress: Pup.Address] RETURNS [Rope.ROPE] = { item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; RETURN [UserProfile.GetProfileName[]]; }; rGetState: PUBLIC PROC [listenerPupAddress: Pup.Address] RETURNS [UserCredentials.State] = { item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; RETURN [UserCredentials.GetState[]]; }; rGet: PUBLIC PROC [listenerPupAddress: Pup.Address] RETURNS [name, password: Rope.ROPE] = { item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; [name, password] _ UserCredentials.Get[]; }; AddPupAddress: ENTRY PROC [newItem: serviceState, serverPupAddress: Pup.Address] = { newItem.listenerPupAddress _ serverPupAddress; newItem.next _ serviceStateListBase; serviceStateListBase _ newItem; }; MatchPupAddress: PUBLIC ENTRY PROC [serverPupAddress: Pup.Address] RETURNS [found: BOOL, item: serviceState] = { nowItem: serviceState _ serviceStateListBase ; WHILE nowItem # NIL DO IF serverPupAddress = nowItem.listenerPupAddress THEN RETURN [TRUE, nowItem]; nowItem _ nowItem.next; ENDLOOP; RETURN[FALSE, NIL]; }; DeletePupAddress: ENTRY PROC [serverPupAddress: Pup.Address] RETURNS [found: BOOL] = { nowItem: serviceState _ serviceStateListBase ; lastItem: serviceState _ NIL; WHILE nowItem # NIL DO IF serverPupAddress = nowItem.listenerPupAddress THEN { IF lastItem = NIL THEN serviceStateListBase _ nowItem.next ELSE lastItem.next _ nowItem.next; RETURN[TRUE]; }; lastItem _ nowItem; nowItem _ nowItem.next; ENDLOOP; RETURN[FALSE]; }; GetCurrentServices: PUBLIC ENTRY PROC RETURNS [serviceList: LIST OF REF serviceListObject _ NIL] = { nowItem: serviceState _ serviceStateListBase ; WHILE nowItem # NIL DO current: REF serviceListObject _ NEW [serviceListObject _ [listenerPupAddress: nowItem.listenerPupAddress, serverInstance: nowItem.serverInstance, command: nowItem.command, process: nowItem.requestingProcess]]; serviceList _ CONS[current, serviceList]; nowItem _ nowItem.next; ENDLOOP; }; addOpenFileToServiceState: ENTRY PROC [item: serviceState, localOpenFile: FS.OpenFile] RETURNS [openFile: ComputeServerCallbacks.OpenFile ] = { openFile _ item.nextFile; IF item.nextFile <= 16 THEN item.first16OpenFiles[item.nextFile] _ localOpenFile ELSE { fileItem: openFileItem _ NEW[openFileItemObject _ [fileNumber: item.nextFile, openFile: localOpenFile]]; fileItem.next _ item.openFileListBase; item.openFileListBase _ fileItem; }; item.nextFile _ item.nextFile + 1 ; }; findOpenFileInServiceState: ENTRY PROC [item: serviceState, file: ComputeServerCallbacks.OpenFile] RETURNS [foundFile: FS.OpenFile _ FS.nullOpenFile] = { IF file <= 16 THEN RETURN[item.first16OpenFiles[file]] ELSE { nowItem: openFileItem _ item.openFileListBase; WHILE nowItem # NIL DO IF nowItem.fileNumber = file THEN RETURN[nowItem.openFile]; nowItem _ nowItem.next; ENDLOOP; }; }; removeOpenFileFromServiceState: ENTRY PROC [item: serviceState, file: ComputeServerCallbacks.OpenFile] = { IF file <= 16 THEN item.first16OpenFiles[file] _ FS.nullOpenFile ELSE { nowItem: openFileItem _ item.openFileListBase; prevItem: openFileItem _ NIL; WHILE nowItem # NIL DO IF nowItem.fileNumber = file THEN { IF prevItem = NIL THEN item.openFileListBase _ nowItem.next ELSE prevItem.next _ nowItem.next; nowItem.next _ NIL; nowItem.openFile _ FS.nullOpenFile; RETURN; }; prevItem _ nowItem; nowItem _ nowItem.next; ENDLOOP; }; }; ClientOn: Commander.CommandProc = { argv: CommandTool.ArgumentVector _ NIL; controllerName: Rope.ROPE _ NIL; newEnabled: ComputeClientInternal.TristateBool _ true; 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 ~Rope.Equal["-", controllerName] THEN { ControllerGVName _ controllerName; ControllerInterface _ NIL; TRUSTED {Process.Detach[FORK ComputeClientInternal.GetControllerInterfaceProcess[TRUE]]; }; }; IF argv.argc > 2 THEN { IF Rope.Equal["halftrue", argv[2]] THEN { Enabled _ halftrue; }; }; }; Enabled _ newEnabled; ComputeServerClient.RegisterProcs[StartService: StartService, BestServerStats: ComputeClient.BestServerStats]; }; ClientOff: Commander.CommandProc = { Enabled _ halftrue; ComputeServerClient.RegisterProcs[StartService: StartServiceDisabled, BestServerStats: BestServerStatsDisabled]; }; MyFindService: PROC [service: Rope.ROPE, userName: RPC.ShortROPE] RETURNS [found: BOOL, instance: RPC.ShortROPE]; MyFindServiceWithQueueing: PROC [service: Rope.ROPE, userName: RPC.ShortROPE, version: RPC.ShortROPE, timeToWait: INT, clientMachineName: RPC.ShortROPE, streamPupAddress: Pup.Address, needListener: BOOL] RETURNS [found: ATOM, instance: RPC.ShortROPE, serverPupAddress: Pup.Address, errMsg: Rope.ROPE]; MyNewStats: PROC [serverMachineName: RPC.ShortROPE, serverMachinePupAddress: RPC.ShortROPE, serverUP: BOOL, firstCall: BOOL, machineType: PrincOps.MachineType, mainMemory: CARDINAL, numberCPUs: CARDINAL, diskPartionSize: INT, freePagesOnDisk: INT, freeboard: INT, freeGFI: CARDINAL, freeMDS: CARDINAL, freeVM: CARDINAL, oldestLRUFileDate: BasicTime.GMT, CPULoad: REAL, nonBackgroundCPULoad: REAL, reclamationRate: REAL, freeProcesses: CARDINAL, userName: RPC.ShortROPE, currentRequests: LIST OF ComputeServer.Request, aveBackgroundLoad: REAL] RETURNS [terminateService, newPackage: BOOL, queueingCommands: LIST OF Rope.ROPE]; MyBestServerStats: PROC RETURNS[instance: RPC.ShortROPE, FOM: REAL] ; MyNoticeNewPackage: PROC [package: RPC.ShortROPE] RETURNS [error: BOOL, tryDifferentController: BOOL, msg: Rope.ROPE]; MyRemoveOldPackage: PROC [package: RPC.ShortROPE] RETURNS [error: BOOL, tryDifferentController: BOOL, msg: Rope.ROPE]; MyGetSomeInfo: PROC RETURNS [error: BOOL, tryDifferentController: BOOL, msg: Rope.ROPE, serverList: LIST OF Rope.ROPE, bestFOM: REAL]; MyCommandUnavailable: PROC [serverMachineName: RPC.ShortROPE, commandName: Rope.ROPE, version: RPC.ShortROPE]; MyExtraCommandAvailable: PROC [serverMachineName: RPC.ShortROPE, commandName: Rope.ROPE, version: RPC.ShortROPE]; MyMightAcceptQueuedCommand: PROC [serverMachineAddress: RPC.ShortROPE, commandName: Rope.ROPE]; MyGenericToController: PROC [requestCode: ATOM, requestString: Rope.ROPE] RETURNS [resultCode: ATOM, resultString: Rope.ROPE]; lFindService: PROC [interface: ComputeServerControllerRpcControl.InterfaceRecord, service: Rope.ROPE, userName: RPC.ShortROPE] RETURNS [found: BOOL, instance: RPC.ShortROPE] = { RETURN MyFindService[service, userName]; }; lMyFindServiceWithQueueing: PROC [interface: ComputeServerControllerRpcControl.InterfaceRecord, service: Rope.ROPE, userName: RPC.ShortROPE, version: RPC.ShortROPE, timeToWait: INT, clientMachineName: RPC.ShortROPE, streamPupAddress: Pup.Address, needListener: BOOL] RETURNS [found: ATOM, instance: RPC.ShortROPE, serverPupAddress: Pup.Address, errMsg: Rope.ROPE] = { RETURN MyFindServiceWithQueueing[service, userName, version, timeToWait, clientMachineName, streamPupAddress, needListener]; }; lNewStats: PROC [interface: ComputeServerControllerRpcControl.InterfaceRecord, serverMachineName: RPC.ShortROPE, serverMachinePupAddress: RPC.ShortROPE, serverUP: BOOL, firstCall: BOOL, machineType: PrincOps.MachineType, mainMemory: CARDINAL, numberCPUs: CARDINAL, diskPartionSize: INT, freePagesOnDisk: INT, freeboard: INT, freeGFI: CARDINAL, freeMDS: CARDINAL, freeVM: CARDINAL, oldestLRUFileDate: BasicTime.GMT, CPULoad: REAL, nonBackgroundCPULoad: REAL, reclamationRate: REAL, freeProcesses: CARDINAL, userName: RPC.ShortROPE, currentRequests: LIST OF ComputeServer.Request, aveBackgroundLoad: REAL] RETURNS [terminateService, newPackage: BOOL, queueingCommands: LIST OF Rope.ROPE] = { RETURN MyNewStats[serverMachineName, serverMachinePupAddress, serverUP, firstCall, machineType, mainMemory, numberCPUs, diskPartionSize, freePagesOnDisk, freeboard, freeGFI, freeMDS, freeVM, oldestLRUFileDate, CPULoad, nonBackgroundCPULoad, reclamationRate, freeProcesses, userName, currentRequests, aveBackgroundLoad]; }; lBestServerStats: PROC [interface: ComputeServerControllerRpcControl.InterfaceRecord] RETURNS[instance: RPC.ShortROPE, FOM: REAL] = { RETURN MyBestServerStats[]; }; lNoticeNewPackage: PROC [interface: ComputeServerControllerRpcControl.InterfaceRecord, package: RPC.ShortROPE] RETURNS [error: BOOL, tryDifferentController: BOOL, msg: Rope.ROPE] = { RETURN MyNoticeNewPackage[package]; }; lRemoveOldPackage: PROC [interface: ComputeServerControllerRpcControl.InterfaceRecord, package: RPC.ShortROPE] RETURNS [error: BOOL, tryDifferentController: BOOL, msg: Rope.ROPE] = { RETURN MyRemoveOldPackage [package]; }; lGetSomeInfo: PROC [interface: ComputeServerControllerRpcControl.InterfaceRecord] RETURNS [error: BOOL, tryDifferentController: BOOL, msg: Rope.ROPE, serverList: LIST OF Rope.ROPE, bestFOM: REAL] = { RETURN MyGetSomeInfo[]; }; lCommandUnavailable: PROC [interface: ComputeServerControllerRpcControl.InterfaceRecord, serverMachineName: RPC.ShortROPE, commandName: Rope.ROPE, version: RPC.ShortROPE] = { MyCommandUnavailable[serverMachineName, commandName, version]; }; lExtraCommandAvailable: PROC [interface: ComputeServerControllerRpcControl.InterfaceRecord, serverMachineName: RPC.ShortROPE, commandName: Rope.ROPE, version: RPC.ShortROPE] = { MyExtraCommandAvailable[serverMachineName, commandName, version]; }; lMightAcceptQueuedCommand: PROC [interface: ComputeServerControllerRpcControl.InterfaceRecord, serverMachineAddress: RPC.ShortROPE, commandName: Rope.ROPE] = { MyMightAcceptQueuedCommand[serverMachineAddress, commandName]; }; lGenericToController: PROC [interface: ComputeServerControllerRpcControl.InterfaceRecord, requestCode: ATOM, requestString: Rope.ROPE] RETURNS [resultCode: ATOM, resultString: Rope.ROPE] = { RETURN MyGenericToController[requestCode, requestString]; }; PokeTheController: PUBLIC PROC = { loopCnt: INT _ 0; seventeenSecondsInTicks: Process.Ticks = Process.SecondsToTicks[17]; waitTime: Process.Ticks _ seventeenSecondsInTicks; DO tempControllerInterface: ComputeServerControllerRpcControl.InterfaceRecord _ ComputeClientInternal.ControllerInterface; resultCode: ATOM _ NIL; IF tempControllerInterface = NIL THEN TryToImportController[] ELSE { [resultCode: resultCode] _ tempControllerInterface.GenericToController[$CurrentController, NIL ! RPC.CallFailed => { ComputeClientInternal.ControllerInterface _ NIL; TryToImportController[]; CONTINUE; }; ]; }; IF resultCode = $notImplemented THEN { tryDifferentController: BOOL _ FALSE; [tryDifferentController: tryDifferentController] _ tempControllerInterface.GetSomeInfo[ ! RPC.CallFailed => { ComputeClientInternal.ControllerInterface _ NIL; TryToImportController[]; CONTINUE; }; ]; IF tryDifferentController THEN { TryToImportController[]; }; } ELSE { IF resultCode = $NotCurrentController THEN { TryToImportController[]; }; }; loopCnt _ loopCnt + 1; IF loopCnt > 25 OR waitTime # seventeenSecondsInTicks THEN { unpack: BasicTime.Unpacked; minuteTime: INT; loopCnt _ 0; IF disableServerIFIdle THEN { unpack _ BasicTime.Unpack[BasicTime.Now[]]; minuteTime _ unpack.hour*100+unpack.minute; IF minuteTime > disableIFIdleAfter OR minuteTime < disableIFIdleBefore THEN { waitMinutes: INT = MIN[20, idleMinutesTilPowerOff]; waitTime _ Process.SecondsToTicks[2*60*waitMinutes]; triedToPowerOff _ TRUE; } ELSE waitTime _ seventeenSecondsInTicks; }; }; Process.Pause[waitTime]; ENDLOOP; }; ClientRequests: Commander.CommandProc = { serviceList: LIST OF REF ComputeClientInternal.ServiceListObject; serviceList _ ComputeClientInternal.GetCurrentServices[]; WHILE serviceList # NIL DO serverName: ROPE _ serviceList.first.serverInstance; serverName _ PupName.HisName[serviceList.first.listenerPupAddress]; IF msg # NIL THEN msg _ Rope.Concat[msg, "\n"]; msg _ Rope.Concat[msg, IO.PutFR[" %g running on %g (%g) ", IO.rope[serviceList.first.command], IO.rope[serverName], IO.rope[serviceList.first.serverInstance]]]; serviceList _ serviceList.rest; ENDLOOP; }; OutstandingRequests: PUBLIC PROC RETURNS [requests: LIST OF ComputeClientExtras.PendingRequest _ NIL] = { serviceList: LIST OF REF ComputeClientInternal.ServiceListObject; serviceList _ ComputeClientInternal.GetCurrentServices[]; WHILE serviceList # NIL DO serverName: ROPE _ serviceList.first.serverInstance; serverName _ PupName.HisName[serviceList.first.listenerPupAddress]; requests _ CONS[[service: serviceList.first.command, serverName: serverName, process: serviceList.first.process], requests]; serviceList _ serviceList.rest; ENDLOOP; }; RemoteProcessSite: PUBLIC PROC [process: PROCESS] RETURNS [serverName: ROPE _ NIL] = { serviceList: LIST OF REF ComputeClientInternal.ServiceListObject; serviceList _ ComputeClientInternal.GetCurrentServices[]; WHILE serviceList # NIL DO IF process = serviceList.first.process THEN { serverName: ROPE _ serviceList.first.serverInstance; serverName _ PupName.HisName[serviceList.first.listenerPupAddress]; RETURN[serverName]; }; serviceList _ serviceList.rest; ENDLOOP; }; CanRunProc: Commander.CommandProc = { argv: CommandTool.ArgumentVector _ NIL; commandName: Rope.ROPE _ NIL; resultCode: ATOM; tempControllerInterface: ComputeServerControllerRpcControl.InterfaceRecord; argv _ CommandTool.Parse[cmd ! CommandTool.Failed => { msg _ errorMsg; CONTINUE; }]; IF argv.argc > 1 THEN commandName _ argv[1]; tempControllerInterface _ ComputeClientInternal.ControllerInterface; IF tempControllerInterface = NIL THEN { ComputeClientInternal.TryToImportController[]; RETURN[$Failure, "Compute Server Controller Down - try again later"] ; }; [resultCode: resultCode, resultString: msg] _ tempControllerInterface.GenericToController[$CommandInfo, commandName ! RPC.CallFailed => { ComputeClientInternal.ControllerInterface _ NIL; ComputeClientInternal.TryToImportController[]; msg _ "RPC Call Failed - controller might be down or recovering"; GOTO returnError; }; ]; SELECT resultCode FROM $success => {}; ENDCASE => { msg _ Rope.Cat["Return code: ", IF resultCode = NIL THEN "NIL" ELSE Atom.GetPName[resultCode]]; }; EXITS returnError => { RETURN[$Failure, msg] }; }; ServerLoadsProc: Commander.CommandProc = { resultCode: ATOM; tempControllerInterface: ComputeServerControllerRpcControl.InterfaceRecord; tempControllerInterface _ ComputeClientInternal.ControllerInterface; IF tempControllerInterface = NIL THEN { ComputeClientInternal.TryToImportController[]; RETURN[$Failure, "Compute Server Controller Down - try again later"] ; }; [resultCode: resultCode, resultString: msg] _ tempControllerInterface.GenericToController[$ServerLoads, NIL ! RPC.CallFailed => { ComputeClientInternal.ControllerInterface _ NIL; ComputeClientInternal.TryToImportController[]; msg _ "RPC Call Failed - controller might be down or recovering"; GOTO returnError; }; ]; SELECT resultCode FROM $success => {}; ENDCASE => { msg _ Rope.Cat["Return code: ", IF resultCode = NIL THEN "NIL" ELSE Atom.GetPName[resultCode]]; }; EXITS returnError => { RETURN[$Failure, msg] }; }; RollbackRecovery: Booting.RollbackProc = { ControllerInterface _ NIL; TRUSTED {Process.Detach[FORK ComputeClientInternal.GetControllerInterfaceProcess[]]; }; }; ProfileChanged: UserProfile.ProfileChangedProc = { SELECT reason FROM firstTime => { }; rollBack => { }; edit => { GetProfileConstants[]; }; ENDCASE; }; GetProfileConstants: PROC = { CachePrefixesOKToRead _ UserProfile.ListOfTokens[key: "Summoner.CachePrefixesOKToRead", default: NIL]; disableServerIFIdle _ UserProfile.Boolean[key: "Summoner.ServerOffIfIdle", default: FALSE] AND ~UserProfile.Boolean["Watch.powerOffInhibit", FALSE]; idleMinutesTilPowerOff _ UserProfile.Number["Watch.idleMinutesTilPowerOff", 10]; disableIFIdleAfter _ UserProfile.Number["Watch.powerOffAfter", 1900]; SELECT disableIFIdleAfter FROM < 0 => disableIFIdleAfter _ 0; > 2400 => disableIFIdleAfter _ 2400; ENDCASE; disableIFIdleBefore _ UserProfile.Number["Watch.powerOffBefore", 700]; SELECT disableIFIdleBefore FROM < 0 => disableIFIdleBefore _ 0; > 2400 => disableIFIdleBefore _ 2400; ENDCASE; }; name, password: ROPE; zones: RPC.Zones _ RPC.standardZones; serverInterfaceCache _ NEW[serverInterfaceArray]; ClientMachineName _ PupName.MyName[]; myNetAddressRope _ PupName.MyRope[]; StreamPupAddress _ PupName.NameLookup[ClientMachineName, Pup.nullSocket]; [name, password] _ UserCredentials.Get[]; TRUSTED { IF PrincOpsUtils.IsBound[LOOPHOLE[UnsafeStorage.GetTransientPageUZone]] THEN zones.heap _ UnsafeStorage.GetTransientPageUZone[] ; -- LOOPHOLE should not be needed, but the compiler give a bogus type error }; ComputeServerCallbacksRpcControl.ExportInterface[ interfaceName: [ type: "ComputeServerCallbacks.summoner", instance: myNetAddressRope, version: [1,1]], user: name, password: RPC.MakeKey[password], parameterStorage: zones ]; ControllerGVName _ UserProfile.Token["Summoner.ControllerName"]; IF ControllerGVName = NIL THEN ControllerGVName _ "PaloAlto1.summoner" ; GetProfileConstants[]; UserProfile.CallWhenProfileChanges[proc: ProfileChanged]; TRUSTED {Process.Detach[FORK ComputeClientInternal.GetControllerInterfaceProcess[]]; }; TRUSTED {Process.Detach[FORK ComputeClientInternal.PokeTheController[]]; }; Commander.Register[key: "///Commands/SummonerClientOn", proc: ClientOn, doc: "Turn on use of the Compute Server Client {for the specified cluster}"]; Commander.Register[key: "///Commands/SummonerClientOff", proc: ClientOff, doc: "Turn off use of the Compute Server Client"]; Commander.Register[key: "///Commands/SummonerClientRequests", proc: ClientRequests, doc: "Print all active requests"]; Commander.Register[key: "///Commands/SummonerCommandInfo", proc: CanRunProc, doc: "Print all commands or print all servers that the Controller expects to be able to do a command"]; Commander.Register[key: "///Commands/SummonerServerLoads", proc: ServerLoadsProc, doc: "Print server load statistics"]; Booting.RegisterProcs[r: RollbackRecovery]; END. ุComputeClientImpl.mesa Client side of the interface implementation. Last Edited by: Bob Hagmann, July 24, 1986 8:35:37 am PDT Hal Murray, March 23, 1986 0:12:08 am PST Spreitzer, September 3, 1985 3:40:52 pm PDT Copyright c 1984 by Xerox Corporation. All rights reserved. Declarations Service Initialization and Status WHILE currentService.remoteStream.CharsAvail[] > 0 AND ~currentService.outStreamEOF DO char: CHAR; char _ currentService.remoteStream.GetChar[! IO.EndOfStream => {currentService.outStreamEOF _ TRUE; CONTINUE;}]; IF out # NIL AND ~currentService.outStreamEOF THEN out.PutChar[char]; ENDLOOP;  Start of Body for StartService  The idea is to start up another process to actually do the call. This process will wake up periodically and check ABORT and copy streams around (monitorAndBufferStreams). On ABORT, we try to abort the remote process. We either Detach the forked process after three ABORTs, or we JOIN with it and recover the results. loop to allow for retries, re-import of controller and server, stream errors and who knows what else Must set serverInstance, controllerAndServerOK, found, success, and msg in currentService before returning! RETURN[FALSE, TRUE, cantImportServer, "Cannot Import from Server Selected by Controller", NIL]; RETURN[TRUE, found, false, "Requested command not found", NIL]; RETURN[FALSE, TRUE, cantImportServer, "Cannot Import from Server Selected by Controller", NIL]; RETURN [TRUE, FALSE, commandNotFound, errMsg, serverInstance]; RETURN [TRUE, FALSE, serverTooBusy, errMsg, serverInstance]; RETURN [TRUE, FALSE, serverTooBusy, errMsg, serverInstance]; RETURN[FALSE, FALSE, false, "Call to the Controller Failed", NIL]; currentService.msg _ msg; --setup by all places that do a GOTO serverCallFailed RETURN[FALSE, TRUE, false, msg, serverInstance]; RETURN[FALSE, FALSE, false, "Bad server name", NIL]; FS from the Client Workstation - Exported to ComputeServerCallbacks generic call to allow for expansion without RPC interface recompilation Get buffer, transfer file data into it, copy it into the result buffer. All of this because the result buffer is not page aligned. Get buffer, transfer file data into it, write it into the file. All of this because the result buffer is not page aligned. UserProfile and UserCredentials from the Client Workstation - Exported to ComputeServerCallbacks UserProfile stuff UserCredentials Client Services List Maintence Client On/Off Dummies to strip off an arg for the local call Revalidate Controller Interface cache Print all active requests Return a list of pending requests from this workstation Where is a remote service Return a list of pending requests from this workstation Print all servers that the Controller expects to be able to do a command Print server load statistics Rollback Recovery Profile/Rollback Restart PROC [reason: ProfileChangeReason]; Initialization ControllerInterface _ ComputeServerControllerRpcControl.ImportNewInterface[ interfaceName: [ type: "ComputeServerController.summoner", instance: ControllerGVName, version: [1,1]] ! RPC.ImportFailed => { TRUSTED {Process.Detach[FORK GetControllerInterfaceProcess[]]; }; CONTINUE; }; ]; Bob Hagmann March 10, 1985 12:14:31 pm PST changes to: ClientMachineName, StreamPupAddress, myNetAddressRope, StartService, name, clientMachineName, StreamPupAddress, myNetAddressRope Bob Hagmann June 20, 1985 7:35:44 am PDT added retries to BestServerStats Bob Hagmann April 18, 1986 11:59:38 am PST moved ComputeServerUser into ComputeServerCallbacks ส?+– "Cedar" style˜headšœ™Ibodyšœ,™,L™9Icode™)™+Jšœ ฯmœ1™NšœX˜XNšžœ žœžœžœ˜/Nšœ[˜[Nšœžœ˜ANšœS˜SNšžœ žœžœžœ˜/NšœQ˜QNšœžœ˜žœž˜MO˜0O˜6O˜(Ošžœ˜—Nšžœ˜Nšœ˜—Nšœ˜Nšœ-˜-NšœžœŸ+˜ONšœžœ˜#šž˜šœ˜Nšœ˜Nšœžœ˜#Nšœžœ˜N˜—Nšœ˜——šžœžœžœžœ˜\šžœžœž˜<šœ0˜0šžœ˜Nšœžœ˜"NšœQžœ˜\Nšžœ˜ Nšœ˜—šœ˜Nšœžœ˜"Nšžœ˜ N˜——Nšœ˜Nšžœ˜—šœA˜ANšœžœ˜"Nšžœ˜ Nšœ˜—Nšœ˜Nšœžœ˜Nšœ˜—Nš žœžœžœ.žœžœ˜“šžœžœžœ.žœ˜vNšœ žœ,˜˜>šžœžœžœ˜Nšœžœ˜!Nšœ'žœ˜-Nšœžœ˜Nšœ*˜*NšœH˜HNšžœ˜NšžœžœžœHžœ™_N˜—N˜—Nšœžœ žœ˜N˜—šœžœŸ'˜/Nšœžœ˜Nšœžœžœ˜šžœžœžœ˜Nšœ˜NšœA˜ANšœTžœ ˜bNšœ9˜9N˜—šœžœ˜NšœC˜CNšœ\˜\šœžœ˜Nšœžœ˜!Nšœžœ˜Nšžœ˜Nšœ˜—Nšœ˜šžœžœ˜Nšœžœ˜!Nšœ'žœ˜,Nšœ˜Nšœ˜Nšœ3˜3Nšžœ˜Nšžœžœ/žœ™?N˜—N˜—Nšœ/˜/Nšœ>˜>šžœžœžœ˜Nšœžœ˜!Nšœ'žœ˜-Nšœžœ˜Nšœ*˜*Nšœ#˜#Nšžœ˜NšžœžœžœHžœ™_N˜—Nšœฯ˜ฯšœžœ˜Nšœ,˜,šžœžœ˜ Nšœ5˜5Nšœ>˜>Nšžœžœžœžœ˜$N˜—Nšœžœ˜!Nšœ5˜5NšœI˜INšžœ˜Nšœ˜—Nšœ˜N˜—šžœ ž˜šœ˜Nšœžœ˜!Nšœ'žœ˜,Nšœžœ˜Nšœ)˜)Nšœ)˜)Nšœ/˜/Nšžœ˜Nšžœžœžœ+™>N˜—šœ˜Nšœžœ˜!Nšœ'žœ˜,Nšœžœ˜Nšœ'˜'Nšœ)˜)Nšœ/˜/Nšžœ˜Nšžœžœžœ)™˜>Nšžœžœžœžœ˜$N˜—Nšœžœ˜!Nšœ5˜5Nšœ5˜5NšœE˜ENšžœ˜Nšœ˜—Nšœ˜Nšœ5˜5Nšœžœ˜N˜—šœ ˜ Nšœžœ˜!Nšœ'žœ˜,Nšœžœ˜Nšœ!˜!Nšœ&˜&Nšžœ˜Nšžœžœžœ)™žœ˜BNšœ žœ˜Nšœžœ˜.Nšœžœ˜%šžœžœžœž˜2šžœHžœ˜PNšœ;˜;Nšœ+˜+Nšžœ(˜.N˜—šžœFžœ˜NNšœ0˜0Nšœ˜N˜—Nšžœ˜—šœ@˜@NšœZ˜Zšœžœ˜Nšžœ˜ Nšœ˜—N˜—šžœžœžœ˜"Nšœ0˜0Nšœ@˜@Nšœ?˜?N˜—Nšžœ˜N˜—š ขœžœžœ<žœ žœžœ˜‡šžœžœžœž˜2šžœ9žœ˜ANšœ-žœ˜1Nšœ(žœ˜,Nšœ=˜=Nšœžœ˜ Nšžœ˜N˜—Nšžœ˜—N˜——šžœA™CM˜šกœžœ˜Mšžœ ˜ฅMšœ˜—M˜šกœžœ˜$Mšžœ]˜bMšœ˜M˜—šก œžœ žœ˜)MšžœUžœ$˜Mšœ˜M˜—šขœž œžœžœžœžœžœ˜qMšœH™HMšžœžœ˜M˜M˜—šขœžœžœžœ˜5Mšžœžœ˜(Mšžœ˜Mšœ˜—M˜š ขœžœžœžœžœ˜8Mšžœžœ˜(Mšžœžœ˜Mšœ˜—M˜šข œžœžœžœžœ žœ žœžœ!žœ˜‡Mšžœžœ˜(Mšœžœ˜8M˜—M˜šข žœžœžœžœžœžœ žœžœžœ žœžœ˜ฮMšžœžœ˜(Mšœ0žœ6˜hM˜—M˜šขžœžœ,žœžœ žœžœžœ žœžœ žœ˜ฺMšžœžœ˜(Mšœ˜Mšœžœ˜ Mšœ4˜4Mšžœžœ˜$Mšžœžœžœ˜;Mšœžœ˜1Mšžœžœ0˜MMšœb˜bM˜—J˜šขœžœžœ#žœžœžœ žœžœ žœ˜ตJšžœžœ˜(Jšœ˜Jšœžœ˜ Mšœ4˜4Mšžœžœ˜$Mšžœžœžœ˜;Jšœb˜bJ˜—J˜šขžœžœ,žœžœ žœ žœ žœ˜›Mšžœžœ˜(Mšœ˜Mšœžœ˜ Mšœ4˜4Mšžœžœ˜$Mšžœžœžœ˜;Mšœžœ˜1Mšžœžœ0˜MMšœ@˜@M˜—J˜š ขœžœžœ$žœ žœ žœ˜wMšžœžœ˜(Mšœ˜Jšœžœ˜ Mšœ4˜4Mšžœžœ˜$Mšžœžœžœ˜;Jšœ@˜@M˜—J˜šขœžœžœ'˜Bšœ žœžœ˜Jšœžœ˜$Jšž œ˜šžœžœž˜!Jšžœ˜Jšžœ˜—J˜—Jšœ˜Jšœžœ˜ Mšœ4˜4Mšžœžœ˜$Mšžœžœžœ˜;M˜ J˜J˜—šขžœ žœžœ˜QJšœ5˜5šขœžœ ˜šœ žœžœ˜Jšœ$˜$Jšœ&˜&Jšœ ˜ Jšœ˜Jšœ˜Jšœžœ˜Jšœžœ˜Jšž œ˜šžœžœž˜;Jšžœ˜Jšžœ˜—J˜—J˜ Jšžœ˜J˜—šข œžœžœ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜Jšž œ˜J˜—J˜Jšžœ(˜*J˜ J˜—J˜šขžœžขœ"žœžœžœ žœžœ žœ˜ฏJšœžœ˜šžœž˜Jšž œ˜Jšžœ˜Jšžœ˜—Jšœžœ˜JšžœŒ˜’J˜—J˜šขžœ žœžœ˜QJšœ5˜5šขœžœ ˜šœ žœžœ˜Jšœ$˜$Jšœžœ˜Jšœžœ˜Jšž œ˜šžœžœž˜;Jšžœ˜Jšžœ˜—J˜—J˜ Jšžœ˜J˜—šข œžœžœ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜Jšž œ˜J˜—J˜Jšžœ)˜+J˜ J˜—J˜š ขžœžขœ"žœ žœ žœ˜oJšœžœ˜šžœž˜Jšž œ˜Jšžœ˜Jšžœ˜—Jšœžœ˜Jšžœ2˜8J˜—J˜šขœžœžœ)žœžœ,žœ#žœžœžœžœžœžœžœžœ4˜ธJšžœžœ˜(šœ&˜&Jšœ žœ˜J˜—Jšœžœ ˜Jšœ˜Mšœžœ˜ Jšœžœ˜Jšœžœ˜Jšœžœ˜Jšœžœžœ˜Jšœ4˜4Mšžœžœ˜$JšœOžœ6˜‡Jšžœ žœŸ&˜PJšœ@žœ˜Zš žœžœžœžœžœ˜VJ˜Jšœ˜šžœžœžœžœ!žœžœžœ˜EJšœQ˜QJšžœ˜—Jšžœ žœ1žœ˜UJ˜—šœžœ˜Jšœžœ8˜JJšœ:˜:J˜—J˜—J˜šขœžœžœ)žœ žœžœ žœžœžœžœ žœ žœ4˜๋Jšžœžœ˜(Jšœžœ ˜Jšœ˜Mšœžœ˜ Jšœ4˜4Mšžœžœ˜$Jšœžœ4˜FJšœ:˜:J˜—J˜šข œžœžœ)žœžœ žœ žœ žœ4˜ฝJšžœžœ˜(Jšœžœ ˜Jšœ˜Mšœžœ˜ Jšœ4˜4Mšžœžœ˜$Jšœžœ'˜9Jšœ:˜:J˜—J˜š ข œžœžœJžœžœ˜rJšžœžœ˜(Jšœžœ ˜Jšœ˜Mšœžœ˜ Jšœ4˜4Mšžœžœ˜$Mšœ7˜7Mšžœžœ˜#J˜—J˜š ข œžœžœRžœžœ˜}Jšžœžœ˜(Jšœ žœ ˜,Jšœ˜Mšœžœ˜ Jšœ4˜4Mšžœžœ˜$Mšœ9˜9Mšœ9˜9Mšžœžœ+˜4J˜J˜—š ขœžœžœJžœžœ˜ˆJšžœžœ˜(Jšœžœ ˜Jšœ˜Mšœžœ˜ Jšœ4˜4Mšžœžœ˜$Mšœ7˜7Mšœžœ˜4J˜—J˜šขœžœžœJžœžœžœžœžœ ˜ตJšžœžœ˜(Jšœžœ ˜Jšœ˜Mšœžœ˜ Jšœ4˜4Mšžœžœ˜$Mšœ7˜7Mšœ&žœ˜@J˜—J˜šข œžœžœQžœ˜sJšžœžœ˜(Jšœžœ ˜Jšœ˜Mšœžœ˜ Jšœ4˜4Mšžœžœ˜$Mšœ7˜7Mšžœ$˜&J˜—J˜š ขœžœžœQžœžœ˜ฒJšžœžœ˜(Jšœžœ ˜Jšœ˜Mšœžœ˜ Jšœ4˜4Mšžœžœ˜$Mšœ7˜7Mšžœ;˜=J˜—J˜J˜J˜J˜šขœžœžœXžœ:˜งJšžœžœ˜(Jšœžœ ˜Jšœ˜Mšœžœ˜ Jšœ4˜4Mšžœžœ˜$Mšœ7˜7šžœ˜ š žœžœžœžœžœžœ˜`Mšžœ#žœŸ˜OM˜—šœžœ˜Mšœ žœ žœ˜,Mšœžœžœžœ%˜G˜šžœžœžœžœžœžœžœ˜\M™ƒ—Mšžœ4˜6Mšœ6žœžœ˜fMšžœ˜M˜—M˜—Mšœ˜—J˜—J˜š ขœžœžœNžœ žœ9˜ชJšžœžœ˜(Jšœžœ ˜Jšœ˜Mšœžœ˜ Jšœ4˜4Mšžœžœ˜$Mšœ7˜7šžœ˜ š žœžœžœžœžœžœ˜`Mšžœ"žœŸ˜NM˜—šœžœ˜Mšœ žœ žœ˜,Mšœžœžœžœ%˜G˜šžœžœžœžœžœžœžœ˜\M™{—Mšœžœžœ-˜fMšžœ3˜5Mšžœ˜M˜—M˜—Mšœ˜—J˜—J˜šขœžœžœM˜`Jšžœžœ˜(Jšœžœ ˜Jšœ˜Mšœžœ˜ Jšœ4˜4Mšžœžœ˜$Mšœ7˜7Mšžœžœ˜7Mšœ+˜+J˜—J˜š ขœžœžœ-žœ žœžœžœ#žœ#žœžœ žœžœžœ žœžœ žœ˜•Jšžœžœ˜(Jšœ˜Mšœžœ˜ Mšœ žœ˜Jšœ4˜4Mšžœžœ˜$MšœžœM˜dJšœ˜—J™J™šขœžœžœ)žœžœžœ žœ˜—Jšžœžœ˜(Jšœ˜Mšœžœ˜ Jšœ4˜4Mšžœžœ˜$Mšžœ'˜)Jšœ˜—J™J™šขœžœžœ-žœ žœžœžœ#žœžœ žœ˜สJšžœžœ˜(Jšœ˜Mšœžœ˜ Jšœ4˜4Mšžœžœ˜$Mšžœ:˜žœ˜ณJš8ข œžœžœ%žœžœ žœ1žœžœžœžœ žœ žœ žœ žœžœ žœžœžœžœ žœžœžœ+žœžœ žœžœžœžœ˜๒Jš  œžœžœ žœ žœžœ˜FJš œžœ žœ žœ žœžœ žœ˜vJš œžœ žœ žœ žœžœ žœ˜vJš  œžœžœ žœžœ žœžœžœžœ žœ˜‡Jš  œžœžœžœ žœ ˜nJš  œžœžœžœ žœ ˜qJš œžœžœžœ˜_Jš œžœžœžœžœžœžœ˜~J˜šข œžœNžœ žœ žœ žœ žœ˜ฒJšžœ"˜(J˜—šขœžœNžœ žœžœžœžœ9žœžœ žœ žœ8žœ˜๏Jšžœv˜|J˜—š8ข œžœSžœ%žœžœ žœ1žœžœžœžœ žœ žœ žœ žœžœ žœžœžœž œ žœžœžœ+žœžœ žœžœžœžœ˜ฑJšžœน˜ฟJ˜—š œžœžœ<ž œ žœ žœžœ˜…Jšžœ˜J˜—šขœžœIžœ žœ žœžœ žœ˜ถJšžœ˜#J˜—šขœžœIžœ žœ žœžœ žœ˜ถJšžœ˜$J˜—šข œžœ@žœ žœžœ žœžœžœžœ žœ˜ศJšžœ˜J˜—š  œžœSžœžœ žœ˜ฎJšœ>˜>J˜—š ขœžœSžœžœ žœ˜ฑJšœA˜AJ˜—šขœžœVžœžœ˜ŸJšœ>˜>J˜—šขœžœMžœžœžœžœžœ˜พJšžœ3˜9J˜—J˜—™%šกœžœžœ˜#Jšœ žœ˜JšœD˜DJšœ2˜2šž˜Jšœw˜wJšœ žœžœ˜Jšžœžœžœ˜=šœžœ˜šœ[žœžœ˜uNšœ,žœ˜0Nšœ˜Nšžœ˜ Nšœ˜—J˜Jšœ˜šžœžœ˜&Jšœžœžœ˜%šœZžœ˜nNšœ,žœ˜0Nšœ˜Nšžœ˜ Nšœ˜—J˜šžœžœ˜ Nšœ˜J˜—J˜—šœžœ˜šžœ$žœ˜,Jšœ˜J˜—J˜——J˜šžœžœ$žœ˜