TeleLoadImpl.mesa
Last Edited by: Stewart, December 26, 1983 4:11 pm
DIRECTORY
Basics USING [BITAND, BITSHIFT, HighByte, LongNumber, LowByte, LowHalf],
IO USING [card, int, PutF, STREAM],
Process USING [MsecToTicks, SetTimeout],
PupDefs USING [GetFreePupBuffer, MsToTocks, PupAddressLookup, PupAddressToRope, PupBuffer, PupPackageMake, PupPackageDestroy, PupRouterSendThis, PupSocket, PupSocketID, PupSocketDestroy, PupSocketMake, ReturnFreePupBuffer, SetPupContentsWords, UniqueLocalPupAddress],
PupTypes USING [fillInHostID, fillInNetID, fillInPupAddress, Pair, PupAddress, PupType],
PupStream USING [GetPupAddress, PupNameTrouble],
Rope USING [ROPE],
TeleLoad;
TeleLoadImpl: MONITOR
IMPORTS Basics, IO, Process, PupDefs, PupStream
EXPORTS TeleLoad =
BEGIN OPEN TeleLoad;
BitOp: TYPE = PROC [a, b: UNSPECIFIED] RETURNS [UNSPECIFIED];
And: BitOp = INLINE { RETURN[Basics.BITAND[a,b]]; };
Shift: BitOp = INLINE { RETURN[Basics.BITSHIFT[a,b]]; };
locMaxByte: PUBLIC NAT ← 150;
NameToAddress: PUBLIC SAFE PROC [name: Rope.ROPE] RETURNS [address: PupTypes.PupAddress, ok: BOOLTRUE] = TRUSTED {
address ← PupStream.GetPupAddress[teleSwatSocket, name !
PupStream.PupNameTrouble => {ok ← FALSE; CONTINUE; }];
};
AddressToName: PUBLIC SAFE PROC [address: PupTypes.PupAddress] RETURNS [nameRope, addressRope: Rope.ROPE] = TRUSTED {
nameRope ← PupDefs.PupAddressLookup[address];
addressRope ← PupDefs.PupAddressToRope[address];
};
Start: PUBLIC SAFE PROC [host: Rope.ROPE, log: IO.STREAM] RETURNS [h: Handle] = TRUSTED {
sendHim: PupTypes.PupAddress;
allok: BOOL;
[sendHim, allok] ← NameToAddress[host];
sendHim.socket ← TeleLoad.teleSwatSocket;
IF NOT allok THEN RETURN[NIL];
h ← NEW[TLObject ← [
host: host,
address: sendHim,
cacheSize: locMaxByte,
log: log]];
RETURN[h];
};
Stop: PUBLIC SAFE PROC [h: Handle] = TRUSTED {
IF h=NIL THEN RETURN;
h.host ← NIL;
h.log ← NIL;
};
Store: PUBLIC ENTRY TeleLoadProc = TRUSTED {
ENABLE UNWIND => NULL;
[ok, attempts] ← GStore[h: h, requestcb: cb, type: coreStoreRequest, tries: tries];
};
Fetch: PUBLIC ENTRY TeleLoadProc = TRUSTED {
ENABLE UNWIND => NULL;
[ok, attempts] ← GFetch[h: h, requestcb: cb, type: coreFetchRequest, tries: tries];
};
SlaveStore: PUBLIC ENTRY TeleLoadProc = TRUSTED {
ENABLE UNWIND => NULL;
[ok, attempts] ← GStore[h: h, requestcb: cb, type: slaveStoreRequest, tries: tries];
};
SlaveFetch: PUBLIC ENTRY TeleLoadProc = TRUSTED {
ENABLE UNWIND => NULL;
[ok, attempts] ← GFetch[h: h, requestcb: cb, type: slaveFetchRequest, tries: tries];
};
Call: PUBLIC ENTRY TeleLoadProc = TRUSTED {
ENABLE UNWIND => NULL;
[ok, attempts] ← GExchange[h: h, requestcb: cb, type: callRequest, tries: tries];
};
Go: PUBLIC ENTRY TeleLoadProc = TRUSTED {
ENABLE UNWIND => NULL;
[ok, attempts] ← GStore[h: h, requestcb: cb, type: goRequest, tries: 1];
};
GoFromBreak: PUBLIC ENTRY TeleLoadProc = TRUSTED {
ENABLE UNWIND => NULL;
[ok, attempts] ← GStore[h: h, requestcb: cb, type: goFromBreakRequest, tries: 1];
};
SingleStep: PUBLIC ENTRY TeleLoadProc = TRUSTED {
ENABLE UNWIND => NULL;
[ok, attempts] ← GStore[h: h, requestcb: cb, type: singleStepRequest, tries: 1];
};
FetchState: PUBLIC ENTRY TeleLoadProc = TRUSTED {
ENABLE UNWIND => NULL;
[ok, attempts] ← GFetch[h: h, requestcb: cb, type: stateFetchRequest, tries: tries];
};
GoToDebugger: PUBLIC ENTRY TeleLoadProc = TRUSTED {
ENABLE UNWIND => NULL;
b: PupDefs.PupBuffer ← PupDefs.GetFreePupBuffer[];
replycb: CorePkt;
replycb ← LOOPHOLE[@b.pupBody];
replycb.advice ← cb.advice;
replycb.address ← cb.address;
replycb.count ← cb.count;
FOR j: CARDINAL IN [0..cb.count) DO
replycb.data[j] ← cb.data[j];
ENDLOOP;
PupDefs.SetPupContentsWords[b, SIZE[CorePktObject]+((cb.count+1)/2)];
b.pupID ← NewPupID[];
b.pupType ← debugRequest;
KingSend[b, h.address];
};
Fires up a process to watch for unsolicited news items from debugees
eventServerUseCount: INT ← 0;
eventServerActive: BOOLFALSE;
eventServerProcess: PROCESS;
eventServerPollingInterval: NAT ← 500;
eventSocket: PupDefs.PupSocket ← NIL;
eventClientProcedure: EventProc;
eventClientData: REF ANY;
StartEventServer: PUBLIC ENTRY SAFE PROC [proc: EventProc, clientData: REF ANY] = TRUSTED {
eventServerUseCount ← eventServerUseCount + 1;
IF eventServerUseCount > 1 THEN RETURN;
IF eventServerActive THEN RETURN;
eventClientProcedure ← proc;
eventClientData ← clientData;
eventServerActive ← TRUE;
eventServerProcess ← FORK TeleloadEventServer[];
};
StopEventServer: PUBLIC ENTRY SAFE PROC = TRUSTED {
eventServerUseCount ← MAX[0, eventServerUseCount - 1];
IF eventServerUseCount > 0 THEN RETURN;
eventServerActive ← FALSE;
JOIN eventServerProcess;
};
TeleloadEventServer: PROC = {
b: PupDefs.PupBuffer ← NIL;
er: EventRecord;
cp: CorePkt;
PupDefs.PupPackageMake[];
eventSocket ← PupDefs.PupSocketMake[local: teleSwatSocket, remote: [PupTypes.fillInNetID, PupTypes.fillInHostID, teleSwatSocket], ticks: PupDefs.MsToTocks[eventServerPollingInterval]];
DO
b ← eventSocket.get[];
IF b # NIL THEN {
cp ← LOOPHOLE[@b.pupBody];
er ← LOOPHOLE[@cp^.data];
eventClientProcedure[b.source, er^, eventClientData];
PupDefs.ReturnFreePupBuffer[b];
};
IF NOT eventServerActive THEN EXIT;
ENDLOOP;
eventClientData ← NIL;
eventClientProcedure ← NIL;
PupDefs.PupSocketDestroy[eventSocket];
PupDefs.PupPackageDestroy[];
};
GStore: INTERNAL PROC [h: Handle, requestcb: CoreBlock, type: PupTypes.PupType, tries: NAT] RETURNS [a: BOOLTRUE, actualAttempts: NAT] = {
b: PupDefs.PupBuffer ← NIL;
id: PupTypes.Pair ← NewPupID[];
replycb: CorePkt;
IF h=NIL THEN RETURN[FALSE, 0];
FOR actualAttempts IN [1..tries] DO
IF b#NIL THEN PupDefs.ReturnFreePupBuffer[b];
b ← PupDefs.GetFreePupBuffer[];
replycb ← LOOPHOLE[@b.pupBody];
replycb.advice ← requestcb.advice;
replycb.address ← requestcb.address;
replycb.count ← requestcb.count;
FOR j: CARDINAL IN [0..requestcb.count) DO
replycb.data[j] ← requestcb.data[j];
ENDLOOP;
PupDefs.SetPupContentsWords[b, SIZE[CorePktObject]+((requestcb.count+1)/2)];
b ← Exchange[h, b, type, id];
IF b=NIL THEN LOOP;
replycb ← LOOPHOLE[@b.pupBody];
IF NOT Check[requestcb, replycb] THEN LOOP;
requestcb.advice ← replycb.advice;
EXIT;
REPEAT
FINISHED => a ← FALSE;
ENDLOOP;
IF b#NIL THEN PupDefs.ReturnFreePupBuffer[b];
};
GFetch: INTERNAL PROC [h: Handle, requestcb: CoreBlock, type: PupTypes.PupType, tries: CARDINAL] RETURNS [a: BOOLTRUE, actualAttempts: NAT] = {
b: PupDefs.PupBuffer ← NIL;
id: PupTypes.Pair ← NewPupID[];
replycb: CorePkt;
IF h=NIL THEN RETURN[FALSE, 0];
FOR actualAttempts IN [1..tries] DO
IF b#NIL THEN PupDefs.ReturnFreePupBuffer[b];
b ← PupDefs.GetFreePupBuffer[];
replycb ← LOOPHOLE[@b.pupBody];
replycb.advice ← requestcb.advice;
replycb.address ← requestcb.address;
replycb.count ← requestcb.count;
PupDefs.SetPupContentsWords[b, SIZE[CorePktObject]];
b ← Exchange[h, b, type, id];
IF b=NIL THEN LOOP;
replycb ← LOOPHOLE[@b.pupBody];
IF replycb.address # requestcb.address THEN LOOP;
IF replycb.count # requestcb.count THEN LOOP;
FOR j: CARDINAL IN [0..requestcb.count) DO
requestcb.data[j] ← replycb.data[j];
ENDLOOP;
requestcb.advice ← replycb.advice;
EXIT;
REPEAT
FINISHED => a ← FALSE;
ENDLOOP;
IF b#NIL THEN PupDefs.ReturnFreePupBuffer[b];
};
GExchange: INTERNAL PROC [h: Handle, requestcb: CoreBlock, type: PupTypes.PupType, tries: CARDINAL] RETURNS [a: BOOLTRUE, actualAttempts: NAT] = {
b: PupDefs.PupBuffer ← NIL;
id: PupTypes.Pair ← NewPupID[];
replycb: CorePkt;
IF h=NIL THEN RETURN[FALSE, 0];
FOR actualAttempts IN [1..tries] DO
IF b#NIL THEN PupDefs.ReturnFreePupBuffer[b];
b ← PupDefs.GetFreePupBuffer[];
replycb ← LOOPHOLE[@b.pupBody];
replycb.advice ← requestcb.advice;
replycb.address ← requestcb.address;
replycb.count ← requestcb.count;
FOR j: CARDINAL IN [0..requestcb.count) DO
replycb.data[j] ← requestcb.data[j];
ENDLOOP;
PupDefs.SetPupContentsWords[b, SIZE[CorePktObject]+((requestcb.count+1)/2)];
b.pupID ← id;
b ← Exchange[h, b, type, id];
IF b=NIL THEN LOOP;
replycb ← LOOPHOLE[@b.pupBody];
IF replycb.address # requestcb.address THEN LOOP;
IF replycb.count # requestcb.count THEN LOOP;
FOR j: CARDINAL IN [0..requestcb.count) DO
requestcb.data[j] ← replycb.data[j];
ENDLOOP;
requestcb.advice ← replycb.advice;
EXIT;
REPEAT
FINISHED => a ← FALSE;
ENDLOOP;
IF b#NIL THEN PupDefs.ReturnFreePupBuffer[b];
};
Exchange: INTERNAL PROC [h: Handle, request: PupDefs.PupBuffer, type: PupTypes.PupType, id: PupTypes.Pair] RETURNS[PupDefs.PupBuffer] = {
reply: PupDefs.PupBuffer ← NIL;
request.pupID ← id;
request.pupType ← type;
KingSend[request, h.address];
DO
IF reply#NIL THEN PupDefs.ReturnFreePupBuffer[reply];
reply ← KingGet[h.address];
IF reply = NIL THEN RETURN[NIL];
IF reply.pupType # LOOPHOLE[LOOPHOLE[type, CARDINAL]+1] THEN LOOP;
IF reply.pupID # id THEN LOOP;
RETURN[reply];
ENDLOOP;
};
Check: INTERNAL PROC [a: CoreBlock, b: CorePkt] RETURNS [BOOL] = {
IF a.address # b.address THEN RETURN[FALSE];
IF a.count # b.count THEN RETURN[FALSE];
FOR i: CARDINAL IN [0..a.count) DO
IF a.data[i] # b.data[i] THEN RETURN[FALSE];
ENDLOOP;
RETURN[TRUE];
};
Communication stuff more conveniently arranged
Failed: PUBLIC ERROR = CODE;
GetCoreBlock: PUBLIC ENTRY SAFE PROC[h: Handle, addr: CoreAddress, count: CARDINAL, addressSpace: AddressSpace ← main] RETURNS [cb: CoreBlock] = TRUSTED {
ENABLE UNWIND => NULL;
RETURN [GetCoreBlockInternal[h, addr, count, addressSpace]];
};
GetCoreBlockInternal: INTERNAL PROC[h: Handle, addr: CoreAddress, count: CARDINAL, addressSpace: AddressSpace] RETURNS [cb: CoreBlock] = {
ok: BOOLEAN;
tries: NAT;
cb ← NEW[CoreBlockObject[count]];
cb.address ← addr;
cb.advice ← [FALSE, FALSE, 0];
[ok, tries] ← GFetch[h, cb, IF addressSpace = main THEN coreFetchRequest ELSE slaveFetchRequest, 5];
IF NOT ok THEN {
IF h.log # NIL THEN h.log.PutF[" ... %d byte read from %08x failed, (%d tries).\n", IO.card[count], IO.card[cb.address], IO.int[tries]];
cb←NIL;
ERROR Failed;
};
};
ReadWord: PUBLIC ENTRY SAFE PROC [h: Handle, addr: CoreAddress, addressSpace: AddressSpace ← main] RETURNS [v: CARDINAL] = TRUSTED {
ENABLE UNWIND => NULL;
RETURN [ReadInternal[h, addr, addressSpace] + (Shift[ReadInternal[h, addr+1, addressSpace], 8])];
};
Read: PUBLIC ENTRY SAFE PROC [h: Handle, addr: CoreAddress, addressSpace: AddressSpace ← main] RETURNS [v: CARDINAL] = TRUSTED {
ENABLE UNWIND => NULL;
RETURN[ReadInternal[h, addr, addressSpace]];
};
ReadInternal: INTERNAL PROC [h: Handle, addr: CoreAddress, addressSpace: AddressSpace] RETURNS [v: CARDINAL] = {
temp: Basics.LongNumber;
blockAddr: CoreAddress;
count: NAT ← h.cacheSize;
IF h.cacheSize = 0 THEN h.cacheSize ← locMaxByte;
h.cacheSize ← MAX[1, MIN[h.cacheSize, locMaxByte]];
temp.lc ← addr;
temp.lc ← temp.lc - (temp.lc MOD h.cacheSize);
blockAddr ← temp.lc;
IF h.cacheCB = NIL THEN {
h.cacheCB ← GetCoreBlockInternal[h: h, addr: blockAddr, count: h.cacheSize, addressSpace: addressSpace];
h.addressSpace ← addressSpace;
};
IF h.cacheCB.address # blockAddr OR h.addressSpace # addressSpace THEN {
FlushWritesInternal[h];
h.cacheCB ← GetCoreBlockInternal[h: h, addr: blockAddr, count: h.cacheSize, addressSpace: addressSpace];
h.addressSpace ← addressSpace;
};
RETURN[h.cacheCB.data[Basics.LowHalf[addr-blockAddr]]];
};
WriteWord: PUBLIC ENTRY SAFE PROC [h: Handle, addr: CoreAddress, value: CARDINAL, addressSpace: AddressSpace ← main] = TRUSTED {
ENABLE UNWIND => NULL;
WriteInternal[h, addr, And[value, 377B], addressSpace];
WriteInternal[h, addr + 1, Shift[value, -8], addressSpace];
};
Write: PUBLIC ENTRY SAFE PROC [h: Handle, addr: CoreAddress, value: CARDINAL, addressSpace: AddressSpace ← main] = TRUSTED {
ENABLE UNWIND => NULL;
WriteInternal[h, addr, value, addressSpace];
};
WriteInternal: INTERNAL PROC [h: Handle, addr: CoreAddress, value: CARDINAL, addressSpace: AddressSpace] = {
temp: Basics.LongNumber;
blockAddr: CoreAddress;
[] ← ReadInternal[h, addr, addressSpace];
temp.lc ← addr;
temp.lc ← temp.lc - (temp.lc MOD h.cacheSize);
blockAddr ← temp.lc;
h.cacheCB.data[Basics.LowHalf[addr-blockAddr]] ← value;
h.dirty ← TRUE;
};
FlushWrites: PUBLIC ENTRY SAFE PROC [h: Handle] = TRUSTED {
ENABLE UNWIND => NULL;
FlushWritesInternal[h];
};
FlushWritesInternal: INTERNAL PROC [h: Handle] = {
IF h.dirty THEN {
ok: BOOL;
tries: NAT;
[ok, tries] ← GStore[h, h.cacheCB, IF h.addressSpace = main THEN coreStoreRequest ELSE slaveStoreRequest, 5];
h.dirty ← FALSE;
IF NOT ok THEN {
IF h.log # NIL THEN h.log.PutF[" Write to %08x failed (%d tries), cache reset anyway.\n", IO.card[h.cacheCB.address], IO.int[tries]];
ERROR Failed;
};
};
};
ResetCache: PUBLIC ENTRY SAFE PROC [h: Handle] = TRUSTED {
ENABLE UNWIND => NULL;
FlushWritesInternal[h];
h.cacheCB ← NIL;
};
SetCacheSize: PUBLIC ENTRY SAFE PROC [h: Handle, bytes: NAT] = TRUSTED {
ENABLE UNWIND => NULL;
FlushWritesInternal[h];
h.cacheCB ← NIL;
h.cacheSize ← IF bytes = 0 THEN locMaxByte ELSE MAX[1, MIN[locMaxByte, bytes]];
};
Swab: PUBLIC SAFE PROC [a: CARDINAL] RETURNS [b: CARDINAL] = TRUSTED {
b ← Basics.BITSHIFT[Basics.LowByte[a], 8] + Basics.HighByte[a];
};
SwabState: PUBLIC SAFE PROC [state: State8086Object] RETURNS [State8086Object] = TRUSTED {
FOR i: Registers8086 IN [AX..FL] DO
state.Regs[i] ← Swab[state.Regs[i]];
ENDLOOP;
RETURN[state];
};
SwabEvent: PUBLIC SAFE PROC [state: EventRecordObject] RETURNS [EventRecordObject] = TRUSTED {
state.regs ← SwabState[state.regs];
state.reason ← Swab[state.reason];
state.clockLow ← Swab[state.clockLow];
state.clockHigh ← Swab[state.clockHigh];
state.bootSwitches ← Swab[state.bootSwitches];
state.advice ← Swab[state.advice];
state.monRelays ← Swab[state.monRelays];
state.tlNet ← Swab[state.tlNet];
state.tlHost ← Swab[state.tlHost];
state.tlImHost ← Swab[state.tlImHost];
state.localNet ← Swab[state.localNet];
RETURN[state];
};
Here lives the single king socket.
These variables are only touched by procedures in the monitor
kingUseCount: INT ← 0;
kingWait: CONDITION;
lastPacket: PupDefs.PupBuffer;
pleaseStopKing: BOOLTRUE;
myID: PupTypes.Pair ← [1711, 1];
These variables are handled outside the monitor
king: PupDefs.PupSocket;
kingProcess: PROCESS;
KingGet: INTERNAL PROC [from: PupTypes.PupAddress] RETURNS [PupDefs.PupBuffer] = {
b: PupDefs.PupBuffer;
IF lastPacket # NIL AND lastPacket.source.net = from.net AND lastPacket.source.host = from.host THEN {
b ← lastPacket;
lastPacket ← NIL;
RETURN[b];
};
WAIT kingWait;
IF lastPacket # NIL AND lastPacket.source.net = from.net AND lastPacket.source.host = from.host THEN {
b ← lastPacket;
lastPacket ← NIL;
RETURN[b];
};
RETURN[NIL];
};
NewPupID: INTERNAL PROC RETURNS [PupTypes.Pair] = {
myID.b ← myID.b + 1;
RETURN [myID];
};
KingSend: INTERNAL PROC [b: PupDefs.PupBuffer ← NIL, to: PupTypes.PupAddress] = {
IF king = NIL THEN {
PupDefs.ReturnFreePupBuffer[b];
RETURN;
};
b.dest ← to;
b.source ← king.getLocalAddress[];
PupDefs.PupRouterSendThis[b];
};
KingDaemon: PROC = {
us: PupTypes.PupAddress ← PupDefs.UniqueLocalPupAddress[PupTypes.fillInPupAddress];
b: PupDefs.PupBuffer;
SetKingPacket: ENTRY PROC [b: PupDefs.PupBuffer] = {
IF lastPacket # NIL THEN PupDefs.ReturnFreePupBuffer[lastPacket];
lastPacket ← b;
NOTIFY kingWait;
};
king ← PupDefs.PupSocketMake[local: us.socket, remote: us, ticks: PupDefs.MsToTocks[500]];
DO
IF pleaseStopKing THEN EXIT;
b ← king.get[];
IF b # NIL THEN SetKingPacket[b];
ENDLOOP;
PupDefs.PupSocketDestroy[king];
king ← NIL;
SetKingPacket[NIL];
};
StartKing: PUBLIC ENTRY SAFE PROC = TRUSTED {
kingUseCount ← kingUseCount + 1;
IF kingUseCount > 1 THEN RETURN;
IF NOT pleaseStopKing THEN RETURN;
pleaseStopKing ← FALSE;
kingProcess ← FORK KingDaemon[];
};
StopKing: PUBLIC SAFE PROC = TRUSTED {
giveUp: BOOLFALSE;
GetLock: ENTRY PROC = {
kingUseCount ← MAX[0, kingUseCount - 1];
IF kingUseCount > 0 THEN giveUp ← TRUE;
IF pleaseStopKing THEN giveUp ← TRUE;
pleaseStopKing ← TRUE;
};
GetLock[];
IF NOT giveUp THEN JOIN kingProcess;
};
StopHimProbing: PUBLIC ENTRY SAFE PROC [h: Handle, setPointers: BOOL] = TRUSTED {
replycb: CorePkt;
b: PupDefs.PupBuffer ← NIL;
IF h = NIL THEN RETURN;
b ← PupDefs.GetFreePupBuffer[];
replycb ← LOOPHOLE[@b.pupBody];
replycb.advice ← [setPointers, FALSE, 0];
replycb.address ← 0;
replycb.count ← 10;
PupDefs.SetPupContentsWords[b, SIZE[CorePktObject]];
b.pupID ← NewPupID[];
b.pupType ← coreFetchRequest;
KingSend[b, h.address];
};
GetEventData: PUBLIC SAFE PROC [h: Handle, setPointers: BOOL] RETURNS [event: EventRecordObject, ok: BOOL] = TRUSTED {
deleteOnReturn: BOOLFALSE;
er: EventRecord;
cb: CoreBlock;
IF h = NIL THEN RETURN [event: event, ok: FALSE];
cb ← NEW[CoreBlockObject[SIZE[EventRecordObject] * 2]];
cb.address ← 0DA00H;
cb.advice ← [setPointers, FALSE, 0];
ok ← Fetch[h, cb, 1].ok;
IF NOT ok THEN RETURN [event: event, ok: FALSE];
er ← LOOPHOLE[BASE[DESCRIPTOR[cb.data]], EventRecord];
event ← SwabEvent[er^];
RETURN [event: event, ok: TRUE];
};
Mainline code
Process.SetTimeout[condition: @kingWait, ticks: Process.MsecToTicks[500]];
END.
December 30, 1981 3:14 PM, Stewart, created from AudioSocket.mesa
December 22, 1982 3:17 pm, Stewart, modifications to TeleLoad
April 25, 1983 11:22 am, LCS, new Event interface and locMaxByte
May 28, 1983 5:47 pm, LCS, cacheSize added, in order to make alteration of running program safe!
December 26, 1983 2:40 pm, LCS, patchup addresses with StripChar