File: 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[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[s.put]];
him.kick ← TRUE;
NOTIFY him.myPupRouterSocket.ready;
};
PupSocketDestroy:
PUBLIC
SAFE
PROC [s: PupSocket] =
TRUSTED {
him: InstancePtr ← LOOPHOLE[PrincOpsUtils.GlobalFrame[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: BOOL ← FALSE;
next: InstancePtr ← NIL;
myPupRouterSocket: PupRouterSocketObject;
myPupRouterSocket.input ← NEW[BufferDefs.QueueObject];
}.