PupSockets.mesa
Copyright © 1984 by Xerox Corporation. All rights reserved.
HGM March 14, 1981 11:50 AM
Andrew Birrell June 22, 1983 5:25 pm
Russ Atkinson, October 31, 1984 3:20:13 pm PST
DIRECTORY
Process USING [SetTimeout, DisableTimeout],
PrincOpsUtils USING [GlobalFrame],
CommFlags USING [doDebug],
CommUtilDefs USING [EnableAborts, GetReturnFrame],
PupRouterDefs USING [PupRouterForgetAboutSocket, PupRouterKnowAboutSocket, routerLock, PupRouterSocketObject],
PupDefs USING [ GetLocalPupAddress, DequeuePup, PupAddress, PupBuffer, PupRouterSendThis, PupSocket, PupSocketID, Pair, PupSocketObject, Tocks, veryLongWait, veryShortWait],
BufferDefs,
PupTypes;
PupSockets: MONITOR LOCKS PupRouterDefs.routerLock
IMPORTS Process, PrincOpsUtils, CommUtilDefs, PupRouterDefs, PupDefs
EXPORTS PupRouterDefs, PupDefs
SHARES BufferDefs =
{ OPEN PupRouterDefs, PupDefs;
Global data. This data should only be referenced by global routines, and not mentioned by local routines.
InstancePtr: TYPE = POINTER TO FRAME[PupSockets];
free: InstancePtr ← LOOPHOLE[PrincOpsUtils.GlobalFrame[LOOPHOLE[PupSocketMake]]];
Global routines, exported through PupRouterDefs & PupDefs. These routines manage the various instances. This stuff is a crock, since multiple global frames are poison in a large system.
GetInstance: ENTRY PROC RETURNS [him: InstancePtr] = {
IF free = NIL THEN {
him ← NEW PupSockets;
START him; -- Do initialization code
RETURN;
};
him ← free;
free ← free.next;
};
FreeInstance: ENTRY PROC [him: InstancePtr] = {
him.next ← free;
free ← him;
};
PupSocketMake: PUBLIC SAFE PROC [local: PupSocketID, remote: PupAddress, ticks: Tocks, id: Pair] RETURNS [PupSocket] = TRUSTED {
RETURN [PupSocketCommon[GetLocalPupAddress[local, remote], remote, ticks, id]];
};
PupSocketMakeFull: PUBLIC SAFE PROC [local, remote: PupAddress, ticks: Tocks] RETURNS [PupSocket] = TRUSTED {
RETURN [PupSocketCommon[local, remote, ticks, [0,0]]];
};
PupSocketCommon: PROC [local, remote: PupAddress, ticks: Tocks, id: Pair] RETURNS [PupSocket] = {
him: InstancePtr ← GetInstance[];
We need to check local to verify that it is valid
him.myPupRouterSocket.local ← local;
him.myPupRouterSocket.remote ← remote;
him.myPupRouterSocket.id ← id;
him.dontWait ← him.kick ← FALSE;
PupRouterKnowAboutSocket[@him.myPupRouterSocket];
SELECT ticks FROM
veryShortWait => dontWait ← TRUE;
veryLongWait => Process.DisableTimeout[@him.myPupRouterSocket.ready];
ENDCASE => Process.SetTimeout[@him.myPupRouterSocket.ready, ticks];
CommUtilDefs.EnableAborts[@him.myPupRouterSocket.ready];
RETURN[him.myPupSocket];
};
PupSocketKick: PUBLIC ENTRY SAFE PROC [s: PupSocket] = TRUSTED {
him: InstancePtr ← LOOPHOLE[PrincOpsUtils.GlobalFrame[LOOPHOLE[s.put]]];
him.kick ← TRUE;
NOTIFY him.myPupRouterSocket.ready;
};
PupSocketDestroy: PUBLIC SAFE PROC [s: PupSocket] = TRUSTED {
him: InstancePtr ← LOOPHOLE[PrincOpsUtils.GlobalFrame[LOOPHOLE[s.put]]];
PupRouterForgetAboutSocket[@him.myPupRouterSocket];
FreeInstance[him];
};
The following routines are "local" to the global frame instance. They should not refer to global data at all, and should only refer to arguments and per-instance data.
Get: ENTRY SAFE PROC RETURNS [b: PupBuffer] = TRUSTED {
ENABLE UNWIND => NULL;
IF ~dontWait AND myPupRouterSocket.input.length = 0 THEN {
IF ~kick THEN WAIT myPupRouterSocket.ready[];
};
kick ← FALSE;
IF myPupRouterSocket.input.length = 0 THEN RETURN[NIL];
b ← PupDefs.DequeuePup[myPupRouterSocket.input];
IF CommFlags.doDebug AND b # NIL THEN
b.debug ← CommUtilDefs.GetReturnFrame[].accesslink;
};
Put: PROC [b: PupBuffer] = {
b.dest ← myPupRouterSocket.remote;
b.source ← myPupRouterSocket.local;
PupRouterSendThis[b];
};
SetRemoteAddress: ENTRY SAFE PROC [a: PupAddress] = TRUSTED {
myPupRouterSocket.remote ← a;
};
GetLocalAddress: ENTRY SAFE PROC RETURNS [PupAddress] = TRUSTED {
RETURN[myPupRouterSocket.local];
};
The per-instance data. No global routine should discuss these variables without qualifying them. No local routine should discuss them in qualified versions. The initialization is performed for every NEW of the frame.
myPupSocket: PupSocket = NEW[PupSocketObject ← [
put: Put, get: Get,
setRemoteAddress: SetRemoteAddress, getLocalAddress: GetLocalAddress] ];
dontWait, kick: BOOLFALSE;
next: InstancePtr ← NIL;
myPupRouterSocket: PupRouterSocketObject;
myPupRouterSocket.input ← NEW[BufferDefs.QueueObject];
}.