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[