DIRECTORY BufferDefs USING[ Buffer ], DebuggerFormat USING[ LabelChecksum ], DiskFace USING[ Label, Type ], 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[ ROPE ], TeledebugProtocol, WorldVM USING[ ], WVMPrivate; WVMRemote: MONITOR IMPORTS DebuggerFormat, Process, PupDefs 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] RETURNS[readOnly: BOOL] = BEGIN in: LONG POINTER TO TeledebugProtocol.CoreStoreAcknowledgement; out: LONG POINTER TO TeledebugProtocol.CoreStoreRequest; readOnly _ map.flags.W--riteProtected--; IF NOT readOnly THEN map.flags.D--irty-- _ TRUE; 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 DiskFace.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]; 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, DiskFace.Label]; PupDefs.ReturnFreePupBuffer[p]; IF addr.labelCheck # DebuggerFormat.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 DiskFace.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 DiskFace.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: DiskFace.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 host _ PupDefs.GetPupAddress[TeledebugProtocol.teleSwatSocket, name ! PupDefs.PupNameTrouble => 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. àCedar Remote Debugging: TeleDebug protocol WVMRemote.mesa Andrew Birrell July 29, 1983 3:56 pm Sending diskFetchRequest with diskAddressSetRequestSize causes a combined addressSet and diskFetch. (I didn't design it!) �Ê Ñ˜Jšœ*™*Jšœ™Jšœ%™%J˜šÏk ˜ Jšœ �œ ˜Jšœ�œ˜&Jšœ �œ˜Jšœ�œ˜Jšœ�œØ˜åJšœ �œ.˜™>Jšœ:™:˜9J˜-—Jš�œ=˜?Jš�œ#�œ˜.Jšœ�œ˜Jš�œ�œ�œ �œ˜BJšœ �œ˜,J˜Jš�œD˜FJš�œ�œ˜!Jš�˜—Jš�œ˜J˜ Jš�œ˜J˜—šŸœ�œ�œ˜+Jšœ�œ˜J˜Jšœ�œ�œ�œ˜(Jš�˜J˜Jšœ�œ�œ�œ,˜?Jšœ�œ�œ�œ$˜8J˜ š�œ�œ�œ ˜J˜QJ˜Jšœ�œ˜Jš�œ �œ�œ�œ˜?Jš�œ �œ�œ�œ˜B˜9J˜(—Jš�œ=˜?Jš�œ#�œ˜.Jšœ�œ˜Jš�œ&�œ�œ˜IJ˜Jš�˜—Jš�œ˜J˜ Jš�œ˜J˜—šŸœ�œ�œ˜&Jš�˜J˜2J˜ š�˜Jš�œ�œ ˜J˜/J˜J˜&—Jš�œ˜J˜ Jš�œ˜J˜—šŸœ� œ˜Jšœ&�œ�œ�œ˜FJš�˜Jšœ�œ�œ�œ1˜DJšœ�œ�œ�œ)˜=š�œ3˜5Jšœ�œ˜J˜%˜>J˜-—Jšœ�œ˜Jš�œC˜EJš�œ$˜&Jš�œ#�œ˜.J˜Jš�˜—Jš�œ˜Jš�œ˜J˜J˜—Jšž+˜+J˜J˜"J˜šŸ œ�œ� œ�œ˜7Jš�œ�œ�œ)�œ˜@J˜—šŸœ� œ�œ˜@Jš�œ�œ�œ˜Jš �œ�œ�œ�œ�œ�œ ˜6Jš�œ˜J˜—šŸœ� œ�œ�œ˜?Jš�œ�˜ Jšœ�œ"˜-Jš �œ�œ�œ�œ�œ�œ˜+Jš�œ˜ Jš�œ˜J˜—šŸœ� œ˜šœ2�œ˜;Jš�œ˜%—Jš�˜Jšœ �œ�œ˜Jšœ� œ˜šŸ œ�œ�œ˜*Jšœ �œ�œ˜!—šŸ œ�œ�œ˜Jšœ�œ�œ�œ�œ �œ�œ�œ˜?—J˜J˜š�œ�œ˜6Jšœ-�œ˜3Jš�˜—Jš�œ˜J˜.Jš�œ˜J˜—šŸœ� œ,˜;Jšœ�œ˜Jš�˜J˜J˜&J˜Jš�œ˜J˜—Jšœ�œ�œ˜Jšœ � œ˜J˜Jšœ �œ˜J˜šŸœ�œ� œ�œ˜PJš�œ�œ�œ�œ˜š�œ �œ˜Jšœ�œ˜Jš�œ ˜Jš �œ �œ�œ�œ�œ�œ˜9Jš�œ�œ�œ˜:J˜)—Jš�œ˜Jš�œ˜J˜—Jšœ�œ˜J˜šŸœ� œ˜Jš�˜J˜šŸœ�œ� œ�˜Jš�˜Jš�œ˜ Jš�œ �œ�œ ˜;Jš�œ ˜$Jš�œ˜—Jš Ÿœ�œ�œ�œ�œ ˜/š Ÿœ� œ�œ�œ�˜*Jš�œž5˜;š�œ˜Jšœ�œ#�˜;J˜/—Jš�œ˜—š�œ�˜J˜Jš�œ�˜ Jš�œ ž ˜Jš�œ�œ�œ�œ ˜?—Jš�œ˜Jš�œ˜J˜J˜J˜—JšžL˜LJ˜Jšœ�œ�œ˜Jšœ � œ˜J˜J˜J˜J˜šŸœ�œ�œ˜!Jš�˜Jš�œ�œ�œ˜Jš �œ�œ�œ �œ �œ˜5J˜'Jš�œ˜J˜—šŸœ�œ�œ˜Jšœ �œ�œ ˜$J˜J˜—Jšœ�œ�œ�œ˜"J˜š Ÿ œ�œ�œ �œ�œ˜FJš�˜šœE˜EJšœ�œ˜1—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˜—…—#ª0[