<> <> <> <> <> <<>> DIRECTORY AMBridge, AMTypes, Atom, Basics, BasicTime, Booting, Commander, CommandTool, ComputeClient, ComputeClientExtras, ComputeClientInternal, ComputeServer, ComputeServerCallbacks, ComputeServerCallbacksRpcControl, ComputeServerClient, ComputeServerUser, ComputeServerUserRpcControl, ComputeServerControllerRpcControl, ComputeServerRpcControl, Convert, FS, FSBackdoor, GVBasics, GVNames, Interpreter, IO, PrincOps, PrincOpsUtils, Process, ProcessProps, PupDefs, PupErrors, PupStream, PupTypes, Rope, RPC, UnsafeStorage, UserCredentials, UserProfile, VM; ComputeClientImpl: CEDAR MONITOR IMPORTS AMBridge, BasicTime, Booting, Commander, CommandTool, ComputeClient,ComputeClientInternal, ComputeServerCallbacks, ComputeServerCallbacksRpcControl, ComputeServerClient, ComputeServerUserRpcControl, ComputeServerControllerRpcControl, ComputeServerRpcControl, Convert, FS, FSBackdoor, GVNames, Interpreter, IO, PrincOpsUtils, Process, ProcessProps, PupDefs, PupErrors, PupStream, Rope, RPC, UnsafeStorage, UserCredentials, UserProfile, VM EXPORTS ComputeClient, ComputeClientExtras, ComputeClientInternal, ComputeServerCallbacks, ComputeServerUser 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: PupDefs.PupAddress _ StreamPupAddress, -- initially bogus; once established, this is the unique ID for the connection and hence the RPC call 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, 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 PupDefs.PupAddress; myNetAddressRope: PUBLIC ROPE; CachePrefixesOKToRead: PUBLIC LIST OF ROPE; <> GetControllerInterfaceProcess: PUBLIC PROC [forceImport: BOOL _ FALSE] = { 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["ComputeControllerPackagesImpl.NoticeNewPackage"].result; IF result = NIL THEN localImportWorked _ FALSE; importedControllerInterface.clientStubNoticeNewPackage _ lNoticeNewPackage; MyNoticeNewPackage _ LOOPHOLE[AMBridge.TVToProc[result]]; result _ Interpreter.Evaluate["ComputeControllerPackagesImpl.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]]; }; IF ~localImportWorked THEN { importedControllerInterface _ NIL; importedControllerInterface _ ComputeServerControllerRpcControl.ImportNewInterface[interfaceName: [ type: "ComputeServerController.summoner", instance: ComputeClientInternal.ControllerGVName, version: [1,1]] ! RPC.ImportFailed => { Process.Pause[Process.SecondsToTicks[13]]; 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] = { IF abortCount = 0 THEN TRUSTED { Process.Detach[FORK TryToAbortProcess[serviceToAbort]]; }; abortCount _ abortCount + 1; IF abortCount = 3 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 = { 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 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 ! PupErrors.StreamClosing => CONTINUE;]; CONTINUE; }; PupErrors.StreamClosing => { currentService.inStreamEOF _ TRUE; CONTINUE; }; ]]; ENDLOOP; currentService.remoteStream.Flush[ ! PupErrors.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 { 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; doneSomething _ TRUE; }; IF ~doneSomething THEN Process.Pause[5 ! ABORTED => {DoAbort[currentService]; CONTINUE;};]; ENDLOOP; }; <<  Start of Body for StartService >> <> 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 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[ ! PupErrors.StreamClosing => CONTINUE;]; WHILE ~currentService.callAbandoned AND ~currentService.callOver AND ~currentService.callFailed DO Process.Pause[7 ! 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; serverInstance: RPC.ShortROPE; serverPupAddress: PupDefs.PupAddress; serverInterface: ComputeServerRpcControl.InterfaceRecord; inOutPupStream: STREAM _ NIL; askForServiceErrMsg: ROPE; errMsg: Rope.ROPE _ NIL; askFound: ComputeServer.AskResponce; currentService.serverInstance _ NIL; currentService.command _ service; { IF queueService AND serverName = NIL THEN { [found: askFound, instance: serverInstance, serverPupAddress: serverPupAddress, errMsg: errMsg] _ controllerInterface.FindServiceWithQueueing[service: service, 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 _ PupDefs.GetPupAddress[[0,0], serverName ! PupStream.PupNameTrouble => GOTO badName]; serverInstance _ Rope.Cat[Convert.RopeFromCard[serverPupAddress.net, 8, FALSE], "#", Convert.RopeFromCard[serverPupAddress.host, 8, FALSE], "#"]; } ELSE { errorMessageX _ "Cannot Import from Server Selected by Controller"; [found: found, instance: serverInstance] _ controllerInterface.FindService[service ! 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, streamPupAddress: StreamPupAddress, needListener: (needRemoteInStream OR needRemoteOutStream) ! 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 inOutPupStream _ PupStream.PupByteStreamCreate[remote: serverPupAddress, ticks: PupStream.SecondsToTocks[1] ! PupErrors.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; -- note: this GOTO may not in fact go to streamOpenFailed. It appears that somebody catches UNWIND above here and does a non-local transfer, then returns with a good stream. }; ] ; msg _ NIL; -- see comment on the GOTO above currentService.remoteStream _ inOutPupStream; currentService.streamReady _ TRUE; [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; }; ENDCASE; 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; <> }; streamOpenFailed => { currentService.callFailed _ TRUE; currentService.msg _ Rope.Concat[askForServiceErrMsg, msg]; DestroyServiceItem[serverPupAddress, currentService]; currentService.controllerAndServerOK _ FALSE; currentService.found _ TRUE; currentService.success _ false; 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: PupDefs.PupAddress, 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[]]]]]; }; 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: PupDefs.PupAddress, 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: PupDefs.PupAddress] 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: PupDefs.PupAddress, 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: PupDefs.PupAddress] 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: PupDefs.PupAddress] = { 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: PupDefs.PupAddress, 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: PupDefs.PupAddress, 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: PupDefs.PupAddress, 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: PupDefs.PupAddress, 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: PupDefs.PupAddress, 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: PupDefs.PupAddress, 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: PupDefs.PupAddress, 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: PupDefs.PupAddress, 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: PupDefs.PupAddress, 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: PupDefs.PupAddress, 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: PupDefs.PupAddress, 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: PupDefs.PupAddress, 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: PupDefs.PupAddress, 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: PupDefs.PupAddress, 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: PupDefs.PupAddress, 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: PupDefs.PupAddress, 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: PupDefs.PupAddress, 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: PupDefs.PupAddress, 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: PupDefs.PupAddress, 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: PupDefs.PupAddress, 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: PupDefs.PupAddress, 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: PupDefs.PupAddress] RETURNS [Rope.ROPE] = { item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; RETURN [UserProfile.GetProfileName[]]; }; <> <<>> rGetState: PUBLIC PROC [listenerPupAddress: PupDefs.PupAddress] RETURNS [UserCredentials.State] = { item: serviceState; found: BOOL; [found, item] _ MatchPupAddress[listenerPupAddress]; IF ~found THEN MakeUnmatchedError[]; RETURN [UserCredentials.GetState[]]; }; rGet: PUBLIC PROC [listenerPupAddress: PupDefs.PupAddress] 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: PupDefs.PupAddress] = { newItem.listenerPupAddress _ serverPupAddress; newItem.next _ serviceStateListBase; serviceStateListBase _ newItem; }; MatchPupAddress: PUBLIC ENTRY PROC [serverPupAddress: PupDefs.PupAddress] 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: PupDefs.PupAddress] 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]]; 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]; }; <> <> <> <> <> <> <> << ELSE {>> <<[tryDifferentController: tryDifferentController] _ tempControllerInterface.GetSomeInfo[ ! RPC.CallFailed => { >> <> <> <> <<};>> << ];>> <<};>> <> <> <<};>> <> <> <<};>> <<>> <> MyFindService: PROC [service: Rope.ROPE] RETURNS [found: BOOL, instance: RPC.ShortROPE]; MyFindServiceWithQueueing: PROC [service: Rope.ROPE, version: RPC.ShortROPE, timeToWait: INT, clientMachineName: RPC.ShortROPE, streamPupAddress: PupDefs.PupAddress, needListener: BOOL] RETURNS [found: ComputeServer.AskResponce, instance: RPC.ShortROPE, serverPupAddress: PupDefs.PupAddress, 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, reclamationRate: REAL, freeProcesses: CARDINAL] 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]; lFindService: PROC [interface: ComputeServerControllerRpcControl.InterfaceRecord, service: Rope.ROPE] RETURNS [found: BOOL, instance: RPC.ShortROPE] = { RETURN MyFindService[service]; }; lMyFindServiceWithQueueing: PROC [interface: ComputeServerControllerRpcControl.InterfaceRecord, service: Rope.ROPE, version: RPC.ShortROPE, timeToWait: INT, clientMachineName: RPC.ShortROPE, streamPupAddress: PupDefs.PupAddress, needListener: BOOL] RETURNS [found: ComputeServer.AskResponce, instance: RPC.ShortROPE, serverPupAddress: PupDefs.PupAddress, errMsg: Rope.ROPE] = { RETURN MyFindServiceWithQueueing[service, 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, reclamationRate: REAL, freeProcesses: CARDINAL] 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, reclamationRate, freeProcesses]; }; 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]; }; <> PokeTheController: PUBLIC PROC = { seventeenSecondsInTicks: Process.Ticks = Process.SecondsToTicks[17]; DO tempControllerInterface: ComputeServerControllerRpcControl.InterfaceRecord _ ComputeClientInternal.ControllerInterface; tryDifferentController: BOOL _ FALSE; IF tempControllerInterface = NIL THEN TryToImportController[] ELSE { [tryDifferentController: tryDifferentController] _ tempControllerInterface.GetSomeInfo[ ! RPC.CallFailed => { ComputeClientInternal.ControllerInterface _ NIL; TryToImportController[]; CONTINUE; }; ]; }; IF tryDifferentController THEN { TryToImportController[]; }; Process.Pause[seventeenSecondsInTicks]; ENDLOOP; }; <> ClientRequests: Commander.CommandProc = { serviceList: LIST OF REF ComputeClientInternal.ServiceListObject; serviceList _ ComputeClientInternal.GetCurrentServices[]; WHILE serviceList # NIL DO serverName: ROPE _ serviceList.first.serverInstance; serverName _ PupDefs.GetHostName[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; }; <> 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]; }; <> name, password: ROPE; zones: RPC.Zones _ RPC.standardZones; serverInterfaceCache _ NEW[serverInterfaceArray]; ClientMachineName _ PupDefs.GetMyName[]; StreamPupAddress _ PupDefs.GetPupAddress[[0,0], ClientMachineName]; myNetAddressRope _ Rope.Cat[Convert.RopeFromCard[StreamPupAddress.net, 8, FALSE], "#", Convert.RopeFromCard[StreamPupAddress.host, 8, FALSE], "#"]; [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 ]; ComputeServerUserRpcControl.ExportInterface[ interfaceName: [ type: "ComputeServerUser.summoner", instance: myNetAddressRope, version: [1,1]], user: name, password: RPC.MakeKey[password] ]; ControllerGVName _ UserProfile.Token["Summoner.ControllerName"]; IF ControllerGVName = NIL THEN ControllerGVName _ "PaloAlto.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"]; Booting.RegisterProcs[r: RollbackRecovery]; END. <> <> <> <> <<>>