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.ROPE ← NIL,
bestResult: Route.ResultData,
bestMethod: RouteChannel.Method
];
oneFinished: CONDITION;
nForked: NAT ← 0;
maxForkedPossible: NAT ← 8;
idTable: SymTab.Ref ← SymTab.Create[];
csCommandName: Rope.ROPE ← "ChannelRoute";
debug: BOOLEAN ← FALSE;
okToFlush: BOOLEAN ← FALSE;
okToRemoteSubmit: BOOLEAN ← FALSE;
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:
REF ←
NIL] ~ {
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.
ROPE ←
NIL] =
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.STREAM ← FS.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.STREAM ← FS.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
];
}.