RouteChannelRemoteImpl.mesa
Copyright Ó 1985, 1987, 1988 by Xerox Corporation. All rights reserved.
by Bryan Preas July 10, 1985 6:57:00 pm PDT
last edited by Bryan Preas July 20, 1987 7:47:21 pm PDT
Christian Le Cocq March 21, 1988 2:15:52 pm PST
DIRECTORY
BasicTime USING [Now],
CD USING [Layer, Number],
CedarProcess USING [Fork],
Commander USING [CommandProc],
ComputeClientExtras USING [StartServiceExtra],
ComputeServerClient USING [RemoteSuccess, StartService],
ComputeServerServer USING [Register],
DABasics USING [Number, Rect],
FS USING [StreamOpen, Delete, Rename],
IO USING [Close, STREAM, PutFR, card, char],
RefIO USING [WriteRef, ReadRef],
Rope USING [ROPE, Cat, Index, Substr, Equal, Fetch],
Route USING [DesignRules, Optimization, ResultData, ResultDataRec],
RouteChannel USING [ChannelData, Method, MethodRec, TrackSequence, DirectionSequence, WriteResult],
RouteChannelTopol USING [RouteOneChan],
RoutePrivate USING [RoutingAreaParms],
RouteUtil USING [CompareResult],
SymTab USING [Create, Delete, Update, Fetch, Store, Ref, UpdateAction];
RouteChannelRemoteImpl: CEDAR MONITOR
IMPORTS BasicTime, CedarProcess, ComputeClientExtras, ComputeServerClient, ComputeServerServer, FS, IO, RefIO, Rope, RouteChannel, RouteChannelTopol, RouteUtil, SymTab --, Convert, Rope, TerminalIO
EXPORTS RouteChannel = {
ResultSummary: TYPE ~ REF ResultSummaryRec;
ResultSummaryRec: TYPE ~ RECORD[
nOut: NAT ← 0,
servers: LIST OF Rope.ROPENIL,
bestResult: Route.ResultData,
bestMethod: RouteChannel.Method
];
oneFinished: CONDITION;
nForked: NAT ← 0;
maxForkedPossible: NAT ← 8;
idTable: SymTab.Ref ← SymTab.Create[];
csCommandName: Rope.ROPE ← "ChannelRoute";
debug: BOOLEANFALSE;
okToFlush: BOOLEANFALSE;
okToRemoteSubmit: BOOLEANFALSE;
cachedChanData: RouteChannel.ChannelData;
cachedParms: RoutePrivate.RoutingAreaParms;
cachedRules: Route.DesignRules;
cachedId: Rope.ROPE ← "invalid";
TopoWiring: PUBLIC PROC [chanData: RouteChannel.ChannelData,
parms: RoutePrivate.RoutingAreaParms,
rules: Route.DesignRules,
opt: Route.Optimization]
RETURNS [bestResult: Route.ResultData] = {
channel route the routing area
bestResult ← IF okToRemoteSubmit
THEN RemoteTopoWiring[chanData, parms, rules, opt]
ELSE LocalTopoWiring[chanData, parms, rules, opt];
};
LocalTopoWiring: PROC [chanData: RouteChannel.ChannelData,
parms: RoutePrivate.RoutingAreaParms,
rules: Route.DesignRules,
opt: Route.Optimization]
RETURNS [bestResult: Route.ResultData] = {
channel route the routing area
lastMethod: RouteChannel.Method ← NEW[RouteChannel.MethodRec];
bestMethod: RouteChannel.Method;
result: Route.ResultData;
start with a bad result
maxL: NAT = LAST[NAT];
bestResult ← NEW[Route.ResultDataRec ← [maxL, maxL, maxL, maxL, maxL, maxL, maxL, DABasics.Rect[maxL, maxL, maxL, maxL]]];
loop through the options
FOR method: RouteChannel.Method ← GetNextMethod[lastMethod], GetNextMethod[lastMethod] WHILE method # NIL DO
result ← RouteChannelTopol.RouteOneChan[chanData, parms, rules, method];
lastMethod ← method;
IF debug THEN RouteChannel.WriteResult[result, parms, rules, method];
IF RouteUtil.CompareResult[result, bestResult] = less THEN
{bestResult ← result; bestMethod ← method};
IF opt = noIncompletes AND bestResult.numIncompletes = 0 THEN EXIT;
ENDLOOP;
restore results of the best method
IF bestMethod # lastMethod THEN
bestResult ← RouteChannelTopol.RouteOneChan[chanData, parms, rules, bestMethod];
RouteChannel.WriteResult[bestResult, parms, rules, bestMethod];
};
RemoteTopoWiring: PROC [chanData: RouteChannel.ChannelData,
parms: RoutePrivate.RoutingAreaParms,
rules: Route.DesignRules,
opt: Route.Optimization]
RETURNS [bestResult: Route.ResultData] = {
channel route the routing area
bestMethod: RouteChannel.Method;
id: Rope.ROPE ← GetUniqueId[];
WriteRefOnFile[chanData, "ChannelDataSource", id];
WriteRefOnFile[parms, "RoutingAreaParms", id];
WriteRefOnFile[rules, "DesignRules", id];
CacheInputArgs[chanData, parms, rules, id];
loop through the options
FOR method: RouteChannel.Method ← GetNextMethod[NEW[RouteChannel.MethodRec]], GetNextMethod[method] WHILE method # NIL DO
ForkOneMethod[id, method];
ENDLOOP;
[bestResult, bestMethod] ← WaitForEveryOne[id];
read results of the best method
chanData ← NARROW[ReadRefFromFile[Rope.Cat["ChannelDataRes", MethodName[bestMethod]], id]];
RouteChannel.WriteResult[bestResult, parms, rules, bestMethod];
};
GetNextMethod: PROC [currentMethod: RouteChannel.Method]
RETURNS [nextMethod: RouteChannel.Method] = {
SELECT currentMethod.directionSequence FROM
start =>
nextMethod ← NEW[RouteChannel.MethodRec ← [outsideInTop, leftToRight]];
leftToRight =>
nextMethod ← NEW[RouteChannel.MethodRec ← [currentMethod.trackSequence, rightToLeft]];
rightToLeft =>
nextMethod ← NEW[RouteChannel.MethodRec ← [currentMethod.trackSequence, alternateLeft]];
alternateLeft =>
nextMethod ← NEW[RouteChannel.MethodRec ← [currentMethod.trackSequence, alternateRight]];
alternateRight => {
nextMethod ← NEW[RouteChannel.MethodRec ← [currentMethod.trackSequence, leftToRight]];
SELECT currentMethod.trackSequence FROM
start =>
nextMethod.trackSequence ← outsideInTop;
outsideInTop =>
nextMethod.trackSequence ← outsideInBottom;
outsideInBottom =>
nextMethod.trackSequence ← botToTop;
botToTop =>
nextMethod.trackSequence ← topToBot;
topToBot =>
nextMethod ← NIL;
ENDCASE;
};
ENDCASE;
IF debug AND nextMethod # NIL THEN {
TerminalIO.PutRope[Rope.Cat["\nNew method: ", RouteChannel.directionSequenceName[nextMethod.directionSequence], ", ", RouteChannel.trackSequenceName[nextMethod.trackSequence]]]};
};
CacheInputArgs: ENTRY PROC [chanData: RouteChannel.ChannelData,
parms: RoutePrivate.RoutingAreaParms,
rules: Route.DesignRules,
id: Rope.ROPE] ~ {
ENABLE UNWIND => NULL;
cachedId ← id;
cachedChanData ← chanData;
cachedParms ← parms;
cachedRules ← rules;
};
GetCachedArgs: ENTRY PROC [id: Rope.ROPE] RETURNS [chanData: RouteChannel.ChannelData, parms: RoutePrivate.RoutingAreaParms, rules: Route.DesignRules,
notValid: BOOLEAN] ~ {
ENABLE UNWIND => NULL;
IF Rope.Equal[id, cachedId] THEN RETURN[cachedChanData, cachedParms, cachedRules, FALSE]
ELSE RETURN [NIL, NIL, NIL, TRUE];
};
GetUniqueId: PROC RETURNS [id: Rope.ROPE] ~ {
maxL: NAT = LAST[NAT];
rs: ResultSummary ← NEW[ResultSummaryRec ← [bestResult: NEW[Route.ResultDataRec ← [maxL, maxL, maxL, maxL, maxL, maxL, maxL, DABasics.Rect[maxL, maxL, maxL, maxL]]]]];
id ← IO.PutFR["%d", IO.card[LOOPHOLE[BasicTime.Now[], CARD]]];
[] ← SymTab.Store[x: idTable, key: id, val: rs];
WriteRefOnFile[rs.bestResult, "BestResult", id];
};
ForkData: TYPE ~ REF ForkDataRec;
ForkDataRec: TYPE ~ RECORD [id: Rope.ROPE, method: RouteChannel.Method];
ForkOneMethod: ENTRY PROC [id: Rope.ROPE, method: RouteChannel.Method] ~ {
ENABLE UNWIND => NULL;
forkData: ForkData ← NEW[ForkDataRec ← [id, method]];
rs: ResultSummary ← NARROW[SymTab.Fetch[x: idTable, key: id].val];
UNTIL nForked<maxForkedPossible DO WAIT oneFinished ENDLOOP;
rs.nOut ← rs.nOut+1;
[] ← CedarProcess.Fork[SubmitOneChan, forkData, [background, TRUE, TRUE]];
nForked ← nForked+1;
};
OneFinished: ENTRY PROC ~ {
ENABLE UNWIND => NULL;
nForked ← nForked-1;
BROADCAST oneFinished;
};
SubmitOneChan: PROC [data: REF] RETURNS [results: REFNIL] ~ {
CedarProcess.ForkableProc
Open: SymTab.UpdateAction ~ {
rs: ResultSummary ← NARROW[val];
IF rs.servers#NIL THEN {
serverInstance ← rs.servers.first;
rs.servers ← rs.servers.rest;
};
};
Close: SymTab.UpdateAction ~ {
rs: ResultSummary ← NARROW[val];
IF RouteUtil.CompareResult[result, rs.bestResult]=less THEN {
rs.bestResult ← result;
rs.bestMethod ← forkData.method;
RenameBestResult[methodName, forkData.id];
}
ELSE IF okToFlush THEN {
FlushFile[Rope.Cat["ResultData", methodName], forkData.id];
FlushFile[Rope.Cat["ChannelDataRes", methodName], forkData.id];
};
rs.nOut ← rs.nOut-1;
rs.servers ← CONS[serverInstance, rs.servers];
};
ntries: NAT ← 10;
result: Route.ResultData;
forkData: ForkData ← NARROW[data];
methodName: Rope.ROPE ← MethodName[forkData.method];
cmdLine: Rope.ROPE ← Rope.Cat[forkData.id, methodName];
msg: Rope.ROPE;
serverInstance: Rope.ROPE;
found: BOOL;
success: ComputeServerClient.RemoteSuccess ← false;
UNTIL success=true DO
SymTab.Update[x: idTable, key: forkData.id, action: Open];
IF serverInstance=NIL THEN [found, success, msg, serverInstance] ←
ComputeServerClient.StartService[
service: csCommandName,
cmdLine: cmdLine,
in: NIL, out: NIL,
queueService: TRUE]
ELSE [found, success, msg, serverInstance] ←
ComputeClientExtras.StartServiceExtra[
service: csCommandName,
cmdLine: cmdLine,
in: NIL, out: NIL,
queueService: FALSE,
serverName: serverInstance];
ntries ← ntries-1;
IF ntries=0 THEN Error[explanation: Rope.Cat["Summoner error, ", msg]];
ENDLOOP;
result ← NARROW[ReadRefFromFile[Rope.Cat["ResultData", methodName], forkData.id]];
SymTab.Update[x: idTable, key: forkData.id, action: Close];
OneFinished[];
};
Error: ERROR[explanation: Rope.ROPENIL] = CODE;
WaitForEveryOne: ENTRY PROC [id: Rope.ROPE] RETURNS [bestResult: Route.ResultData, bestMethod: RouteChannel.Method] ~ {
ENABLE UNWIND => NULL;
rs: ResultSummary ← NARROW[SymTab.Fetch[x: idTable, key: id].val];
UNTIL rs.nOut=0 DO WAIT oneFinished ENDLOOP;
bestResult ← rs.bestResult;
bestMethod ← rs.bestMethod;
[] ← SymTab.Delete[x: idTable, key: id];
};
MethodName: PROC [method: RouteChannel.Method] RETURNS [name: Rope.ROPE] ~ {
c1, c2: CHAR;
SELECT method.trackSequence FROM
start   => c1 ← 's;
outsideInTop  => c1 ← 'o;
outsideInBottom  => c1 ← 'O;
botToTop   => c1 ← 'b;
topToBot   => c1 ← 't;
ENDCASE   => ERROR;
SELECT method.directionSequence FROM
start   => c2 ← 's;
leftToRight   => c2 ← 'l;
rightToLeft   => c2 ← 'r;
alternateLeft  => c2 ← 'a;
alternateRight  => c2 ← 'A;
ENDCASE   => ERROR;
name ← IO.PutFR["-%g%g", IO.char[c1], IO.char[c2]];
};
MethodFromName: PROC [name: Rope.ROPE] RETURNS [method: RouteChannel.Method] ~ {
c1, c2: CHAR;
ts: RouteChannel.TrackSequence;
ds: RouteChannel.DirectionSequence;
IF Rope.Fetch[name, 0]#'- THEN ERROR;
c1 ← Rope.Fetch[name, 1];
c2 ← Rope.Fetch[name, 2];
SELECT c1 FROM
's  => ts ← start;
'o  => ts ← outsideInTop;
'O  => ts ← outsideInBottom;
'b  => ts ← botToTop;
't  => ts ← topToBot;
ENDCASE  => ERROR;
SELECT c2 FROM
's  => ds ← start;
'l  => ds ← leftToRight;
'r  => ds ← rightToLeft;
'a  => ds ← alternateLeft;
'A  => ds ← alternateRight;
ENDCASE  => ERROR;
method ← NEW[RouteChannel.MethodRec ← [ts, ds]];
};
RemoteRouteOne: Commander.CommandProc ~ {
sepIndex: INT ← Rope.Index[s1: cmd.commandLine, s2: "-"];
id: Rope.ROPE ← Rope.Substr[base: cmd.commandLine, len: sepIndex];
methodName: Rope.ROPE ← Rope.Substr[base: cmd.commandLine, start: sepIndex, len: 3];
method: RouteChannel.Method ← MethodFromName[methodName];
chanData: RouteChannel.ChannelData;
parms: RoutePrivate.RoutingAreaParms;
rules: Route.DesignRules;
notValid: BOOLEAN;
routeResult, bestResult: Route.ResultData;
[chanData, parms, rules, notValid] ← GetCachedArgs[id];
IF notValid THEN {
chanData ← NARROW[ReadRefFromFile["ChannelDataSource", id]];
parms ← NARROW[ReadRefFromFile["RoutingAreaParms", id]];
rules ← NARROW[ReadRefFromFile["DesignRules", id]];
CacheInputArgs[chanData, parms, rules, id];
};
routeResult ← RouteChannelTopol.RouteOneChan[chanData, parms, rules, method];
bestResult ← NARROW[ReadRefFromFile["BestResult", id]];
WriteRefOnFile[routeResult, Rope.Cat["ResultData", methodName], id];
IF RouteUtil.CompareResult[routeResult, bestResult]=less THEN
WriteRefOnFile[chanData, Rope.Cat["ChannelDataRes", methodName], id];
};
WriteRefOnFile: PROC [ref: REF, name, id: Rope.ROPE] ~ {
fileName: Rope.ROPE ← Rope.Cat[name, ".", id];
s: IO.STREAMFS.StreamOpen[fileName: fileName, accessOptions: create];
RefIO.WriteRef[s, ref];
IO.Close[s];
};
ReadRefFromFile: PROC [name, id: Rope.ROPE] RETURNS [ref: REF] ~ {
fileName: Rope.ROPE ← Rope.Cat[name, ".", id];
s: IO.STREAMFS.StreamOpen[fileName: fileName];
ref ← RefIO.ReadRef[s];
IO.Close[s];
};
FlushFile: PROC [name, id: Rope.ROPE] ~ {
fileName: Rope.ROPE ← Rope.Cat[name, ".", id];
FS.Delete[name: fileName];
};
RenameBestResult: PROC [methodName, id: Rope.ROPE] ~ {
from: Rope.ROPE ← Rope.Cat["ResultData", methodName, ".", id];
to: Rope.ROPE ← Rope.Cat["BestResult", ".", id];
FS.Rename[from: from, to: to];
};
InitMaps: PROC ~ {
daMapFile: Rope.ROPE ← "/DATools/DATools7.0/DAToolsVersionMaps/DAToolsSymbols.VersionMap";
daPrefix: Rope.ROPE ← "[DATools]<DATools7.0>";
mapList: VersionMap.MapList ← VersionMapDefaults.GetMapList[$Symbols];
UNTIL mapList=NIL DO
IF Rope.Equal[VersionMap.GetPrefix[mapList.first], daPrefix] THEN RETURN;
mapList ← mapList.rest;
ENDLOOP;
VersionMapDefaults.AddToMapList[$Symbols, VersionMap.RestoreMapFromFile[daMapFile]];
};
ComputeServerServer.Register[
key: csCommandName,
proc: RemoteRouteOne
];
}.