-- Cedar Remote Debugging: TeleDebug protocol -- WVMRemote.mesa -- Andrew Birrell August 2, 1983 12:39 pm DIRECTORY BufferDefs USING[ Buffer ], Device USING[ Type ], PilotDisk USING[ Label, LabelCheckSum ], Process USING[ EnableAborts ], PupDefs USING[ GetFreePupBuffer, GetPupAddress, GetPupContentsBytes, MsToTocks, PupBuffer, PupNameTrouble, PupPackageDestroy, PupPackageMake, PupSocket, PupSocketDestroy, PupSocketMake, ReturnFreePupBuffer, SetPupContentsWords ], PupTypes USING[ fillInSocketID, Pair, PupAddress, PupType ], Rope USING[ Fetch, Length, ROPE ], TeledebugProtocol, WorldVM USING[ ], WVMPrivate; WVMRemote: MONITOR IMPORTS PilotDisk, Process, PupDefs, Rope EXPORTS WorldVM, WVMPrivate = BEGIN Machine: PUBLIC TYPE = PupTypes.PupAddress; -- Public procedures -- ReadRemoteCore: PUBLIC PROC[host: Machine, data: REF WVMPrivate.PageData, mempage: WVMPrivate.PageNumber] RETURNS[map: WVMPrivate.MapEntry, ok: BOOLEAN] = BEGIN in: LONG POINTER TO TeledebugProtocol.CoreFetchAcknowledgement; out: LONG POINTER TO TeledebugProtocol.CoreFetchRequest; Lock[host]; DO ENABLE UNWIND => Unlock[]; p: PupDefs.PupBuffer _ PupDefs.GetFreePupBuffer[]; out _ LOOPHOLE[@p.pupWords]; out^ _ [page: mempage]; p _ SendAndReceive[p, TeledebugProtocol.coreFetchRequest, TeledebugProtocol.coreFetchRequestSize]; in _ LOOPHOLE[@p.pupWords]; IF PupWords[p] # TeledebugProtocol.coreFetchAcknowledgementSize OR WVMPrivate.PageNumber[in.page] # mempage THEN { PupDefs.ReturnFreePupBuffer[p]; LOOP }; data^ _ LOOPHOLE[in.data, WVMPrivate.PageData]; map _ LOOPHOLE[in.flags]; PupDefs.ReturnFreePupBuffer[p]; ok _ in.flags#TeledebugProtocol.vacantFlag; EXIT ENDLOOP; Unlock[]; END; WriteRemoteCore: PUBLIC PROC[host: Machine, data: REF WVMPrivate.PageData, mempage: WVMPrivate.PageNumber, map: WVMPrivate.MapEntry] = BEGIN in: LONG POINTER TO TeledebugProtocol.CoreStoreAcknowledgement; out: LONG POINTER TO TeledebugProtocol.CoreStoreRequest; Lock[host]; DO ENABLE UNWIND => Unlock[]; p: PupDefs.PupBuffer _ PupDefs.GetFreePupBuffer[]; out _ LOOPHOLE[@p.pupWords]; out.page _ mempage; out.flags _ LOOPHOLE[map]; LOOPHOLE[@out.data, LONG POINTER TO WVMPrivate.PageData]^ _ data^; p _ SendAndReceive[p, TeledebugProtocol.coreStoreRequest, TeledebugProtocol.coreStoreRequestSize]; in _ LOOPHOLE[@p.pupWords]; IF PupWords[p] # TeledebugProtocol.coreStoreAcknowledgementSize OR WVMPrivate.PageNumber[in.page] # mempage THEN { PupDefs.ReturnFreePupBuffer[p]; LOOP }; IF in.flags#LOOPHOLE[map, WORD] THEN ERROR; PupDefs.ReturnFreePupBuffer[p]; EXIT; ENDLOOP; Unlock[]; END; ClientDiskTellsLies: ERROR = CODE; ReadRemoteDisk: PUBLIC PROC[host: Machine, data: REF WVMPrivate.PageData, addr: WVMPrivate.DiskAddress, label: LONG POINTER TO PilotDisk.Label] = BEGIN in: LONG POINTER TO TeledebugProtocol.DiskFetchAcknowledgement; out: LONG POINTER TO TeledebugProtocol.DiskAddressSetRequest; Lock[host]; DO ENABLE UNWIND => Unlock[]; p: PupDefs.PupBuffer _ PupDefs.GetFreePupBuffer[]; out _ LOOPHOLE[@p.pupWords]; out^ _ [addr.diskPage + addr.offset, addr.deviceType, addr.deviceOrdinal]; -- Sending diskFetchRequest with diskAddressSetRequestSize causes -- a combined addressSet and diskFetch. (I didn't design it!) p _ SendAndReceive[p, TeledebugProtocol.diskFetchRequest, TeledebugProtocol.diskAddressSetRequestSize]; IF PupWords[p] # TeledebugProtocol.diskFetchAcknowledgementSize THEN { PupDefs.ReturnFreePupBuffer[p]; LOOP }; in _ LOOPHOLE[@p.pupWords]; IF data # NIL THEN data^ _ LOOPHOLE[in.data, WVMPrivate.PageData]; label^ _ LOOPHOLE[in.label, PilotDisk.Label]; PupDefs.ReturnFreePupBuffer[p]; IF addr.labelCheck # PilotDisk.LabelCheckSum[label, addr.offset] THEN ERROR ClientDiskTellsLies[]; EXIT ENDLOOP; Unlock[]; END; WriteRemoteDisk: PUBLIC PROC[host: Machine, data: REF WVMPrivate.PageData, addr: WVMPrivate.DiskAddress, label: LONG POINTER TO PilotDisk.Label] = BEGIN p: PupDefs.PupBuffer; in: LONG POINTER TO TeledebugProtocol.DiskStoreAcknowledgement; out: LONG POINTER TO TeledebugProtocol.DiskStoreRequest; Lock[host]; DO ENABLE UNWIND => Unlock[]; SetDiskAddress[addr.deviceType, addr.deviceOrdinal, addr.diskPage + addr.offset]; p _ PupDefs.GetFreePupBuffer[]; out _ LOOPHOLE[@p.pupWords]; LOOPHOLE[@out.label, LONG POINTER TO PilotDisk.Label]^ _ label^; LOOPHOLE[@out.data, LONG POINTER TO WVMPrivate.PageData]^ _ data^; p _ SendAndReceive[p, TeledebugProtocol.diskStoreRequest, TeledebugProtocol.diskStoreRequestSize]; IF PupWords[p] # TeledebugProtocol.diskStoreAcknowledgementSize THEN { PupDefs.ReturnFreePupBuffer[p]; LOOP }; in _ LOOPHOLE[@p.pupWords]; IF in.label = TeledebugProtocol.noLabel THEN ERROR ClientDiskTellsLies[]; PupDefs.ReturnFreePupBuffer[p]; EXIT ENDLOOP; Unlock[]; END; GoRemote: PUBLIC PROC[host: Machine] = BEGIN p: PupDefs.PupBuffer _ PupDefs.GetFreePupBuffer[]; Lock[host]; BEGIN ENABLE UNWIND => Unlock[]; p _ SendAndReceive[p, TeledebugProtocol.go, 0]; p.pupID _ IncPair[p.pupID]; Send[p, TeledebugProtocol.goReply, 0]; END; Unlock[]; END; SetDiskAddress: PROCEDURE [ device: Device.Type, deviceOrdinal: CARDINAL, page: LONG CARDINAL] = BEGIN in: LONG POINTER TO TeledebugProtocol.DiskAddressSetAcknowledgement; out: LONG POINTER TO TeledebugProtocol.DiskAddressSetRequest; DO p: PupDefs.PupBuffer _ PupDefs.GetFreePupBuffer[]; out _ LOOPHOLE[@p.pupWords]; out^ _ [page, device, deviceOrdinal]; p _ SendAndReceive[p, TeledebugProtocol.diskAddressSetRequest, TeledebugProtocol.diskAddressSetRequestSize]; in _ LOOPHOLE[@p.pupWords]; IF PupWords[p] # TeledebugProtocol.diskAddressSetAcknowledgementSize OR in^ # [page, device, deviceOrdinal] THEN { PupDefs.ReturnFreePupBuffer[p]; LOOP }; PupDefs.ReturnFreePupBuffer[p]; EXIT ENDLOOP; END; -- Actual packet transmission/reception! -- lastPupID: PupTypes.Pair _ [0, 0]; GetNextPupID: ENTRY PROCEDURE RETURNS [PupTypes.Pair] = INLINE BEGIN RETURN[lastPupID_IncPair[IncPair[lastPupID]]]; END; IncPair: PROCEDURE [id: PupTypes.Pair] RETURNS [PupTypes.Pair] = INLINE BEGIN OPEN id; RETURN [[a+(IF b=LAST[CARDINAL] THEN 1 ELSE 0), b+1]]; END; PupWords: PROCEDURE [p: PupDefs.PupBuffer] RETURNS [CARDINAL] = INLINE BEGIN w: CARDINAL = PupDefs.GetPupContentsBytes[p]; IF w MOD 2 # 0 THEN RETURN[LAST[CARDINAL]]; RETURN[w/2]; END; SendAndReceive: PROCEDURE [ x: PupDefs.PupBuffer, t: PupTypes.PupType, words: CARDINAL] RETURNS [answer: PupDefs.PupBuffer] = BEGIN requeued: BOOLEAN _ TRUE; done: CONDITION; MyRequeue: ENTRY PROC[BufferDefs.Buffer] = { requeued _ TRUE; NOTIFY done }; WaitRequeue: ENTRY PROC = { ENABLE UNWIND => NULL; UNTIL requeued DO WAIT done ENDLOOP }; x.requeueProcedure _ MyRequeue; x.pupID _ GetNextPupID[]; DO WaitRequeue[]; requeued _ FALSE; Send[x, t, words]; answer _ Receive[x.pupID ! ReceiveTimeout => LOOP]; EXIT ENDLOOP; WaitRequeue[]; PupDefs.ReturnFreePupBuffer[x]; END; Send: PROCEDURE [x: PupDefs.PupBuffer, t: PupTypes.PupType, words: CARDINAL] = BEGIN x.pupType _ t; PupDefs.SetPupContentsWords[x, words]; socket.put[x]; END; ReceiveTimeout: ERROR = CODE; getMeAPup: CONDITION; receivedPup: PupDefs.PupBuffer; wantPup: BOOLEAN; Receive: ENTRY PROCEDURE[thisPupID: PupTypes.Pair] RETURNS [PupDefs.PupBuffer] = BEGIN ENABLE UNWIND => NULL; DO wantPup _ TRUE; receivedPup _ NIL; WAIT getMeAPup; IF receivedPup=NIL THEN RETURN WITH ERROR ReceiveTimeout; IF receivedPup.pupID = thisPupID THEN RETURN[receivedPup]; PupDefs.ReturnFreePupBuffer[receivedPup]; ENDLOOP; END; keepReceiving: BOOLEAN; ReceiveProcess: PROCEDURE = BEGIN x: PupDefs.PupBuffer; Pass: ENTRY PROCEDURE = INLINE BEGIN IF wantPup THEN { wantPup _ FALSE; receivedPup _ x; NOTIFY getMeAPup } ELSE PupDefs.ReturnFreePupBuffer[x]; END; Notify: ENTRY PROC = INLINE {NOTIFY getMeAPup}; Like: PROCEDURE RETURNS [BOOLEAN] = INLINE BEGIN -- first level of screening (don't care about others) RETURN [ x.source = remote AND x.dest = socket.getLocalAddress[] AND x.pupType = TeledebugProtocol.acknowledgement]; END; WHILE keepReceiving DO x _ socket.get[]; IF x = NIL THEN Notify[] -- timeout ELSE IF Like[] THEN Pass[] ELSE PupDefs.ReturnFreePupBuffer[x]; ENDLOOP; END; -- There is only one socket, protected by Lock/Unlock during remote calls -- locked: BOOLEAN _ FALSE; unlocked: CONDITION; socket: PupDefs.PupSocket; remote: PupTypes.PupAddress; Lock: ENTRY PROC[host: Machine] = BEGIN ENABLE UNWIND => NULL; WHILE locked DO WAIT unlocked ENDLOOP; locked _ TRUE; socket.setRemoteAddress[remote _ host]; END; Unlock: ENTRY PROC = { locked _ FALSE; NOTIFY unlocked }; LookupFailed: PUBLIC ERROR = CODE; LocateRemote: PUBLIC PROC [name: Rope.ROPE] RETURNS[ host: Machine ] = BEGIN s: STRING = [40]; length: INT = Rope.Length[name]; IF length > s.maxlength THEN s.length _ s.maxlength ELSE s.length _ length; FOR i: CARDINAL IN [0..s.length) DO s[i] _ Rope.Fetch[name, i] ENDLOOP; host.net _ [0]; host.host _ [0]; host.socket _ TeledebugProtocol.teleSwatSocket; PupDefs.GetPupAddress[@host, s ! PupDefs.PupNameTrouble => GOTO bad]; EXITS bad => ERROR LookupFailed[] END; receiveProcess: PROCESS; StartTeledebugging: PROC = BEGIN PupDefs.PupPackageMake[]; Process.EnableAborts[@getMeAPup]; remote.net _ [0]; remote.host _ [0]; socket _ PupDefs.PupSocketMake[ local: PupTypes.fillInSocketID, remote: remote, ticks: PupDefs.MsToTocks[500] ]; keepReceiving _ TRUE; wantPup _ FALSE; receiveProcess _ FORK ReceiveProcess; Unlock[]; END; StopTeledebugging: PROC = BEGIN Lock[remote]; keepReceiving _ FALSE; JOIN receiveProcess; PupDefs.PupSocketDestroy[socket]; PupDefs.PupPackageDestroy[]; END; StartTeledebugging[]; END. Ę6˜Jš„Īc.œœ+œĪk œ žœžœžœ$žœžœ‡žœ7žœžœ žœĪb œžœžœ#žœžœ žœžœœĪnœžœžœžœ<žœžœžœžœžœžœ4žœžœžœ5žœžœžœQžœļžœžœCžœ/žœ#žœžœ+žœgžœžœžœ œžœžœžœ\žœžœžœžœ4žœžœžœ5žœžœžœQžœ9žœ žœ žœžœžœĒžœžœCžœ/žœ#žœ žœ žœžœžœžœ,žœžœžœžœžœ œžœžœžœCžœžœžœžœžœžœžœ4žœžœžœ:žœžœžœQžœdBœ>œŠžœCžœ#žœžœžœžœžœ žœ.žœGžœDžœžœžœžœžœ œžœžœžœCžœžœžœžœžœžœžœ4žœžœžœ5žœžœžœ•žœžœ žœžœžœ"žœ žœžœžœĨžœCžœ#žœžœžœ&žœžœBžœžœžœ œžœžœžœFžœžœžœžœžœ œž œ+žœžœžœžœžœžœžœ9žœžœžœ,žœ?žœŅžœžœIžœ*žœ#žœ.žœžœžœ+œ&  œžœž œžœžœžœžœ)žœ œž œžœžœžœžœžœžœžœžœžœžœžœ œž œžœžœžœžœžœ%žœžœžœžœžœžœžœ žœ œž œ9žœžœ!žœ žœžœ ž œ  œžœžœ'žœžœ   œžœžœ žœžœžœžœ žœžœžœDžœžœGžœžœžœ5žœ œž œEžœžœNžœžœžœ ž œ+žœ œžœž œžœžœžœžœžœžœ žœžœžœžœ žœžœžœžœžœžœžœžœ@žœžœžœ œž œžœ œžœž œžœžœžœ žœ žœžœžœ%žœ œžœžœžœžœ œž œžœžœžœžœ6œžœžœ#žœ;žœžœžœžœžœžœ  œžœžœžœžœ#žœžœLœ žœžœ ž œ< œžœžœžœžœžœžœžœžœžœ žœ žœ.žœ œžœžœžœžœžœžœžœ  œžœžœ žœžœžœžœžœžœžœžœžœžœžœžœžœ”žœ žœžœžœžœ œžœžœũžœ žœžœžœ œžœžœ#žœžœVžœžœ˜ĖQ—…—(Î/