MakeDoDownCmds.Mesa
Last Edited by: Spreitzer, September 4, 1985 11:48:58 pm PDT
Carl Hauser, April 11, 1985 3:43:34 pm PST
DIRECTORY Basics, BasicTime, CedarProcess, Commander, CommandTool, FileNames, FileViewerOps, FS, IO, List, MakeDo, MakeDoPrivate, RedBlackTree, ProcessProps, Rope, TimeStamp;
MakeDoDownCmds: CEDAR MONITOR
LOCKS c.down USING c: Command
IMPORTS CommandTool, IO, MakeDo, MakeDoPrivate, Rope
EXPORTS MakeDo, MakeDoPrivate
=
BEGIN OPEN MakeDo, MakeDoPrivate;
NodeRep: PUBLIC TYPE = MakeDoPrivate.NodeRep;
CommandRep: PUBLIC TYPE = MakeDoPrivate.CommandRep;
Enter: ENTRY PROC [c: Command] = {
ENABLE UNWIND => {};
WHILE c.down.locked DO WAIT c.down.change ENDLOOP;
c.down.locked ← TRUE;
};
MayEnterDownCmd: PUBLIC ENTRY PROC [c: Command] RETURNS [in: BOOL] = {
ENABLE UNWIND => {};
in ← NOT c.down.locked;
IF in THEN c.down.locked ← TRUE;
};
ExitDownCmd: PUBLIC ENTRY PROC [c: Command] = {
ENABLE UNWIND => {};
c.down.locked ← FALSE;
BROADCAST c.down.change;
};
DoIn: PROC [c: Command, p: --INTERNAL-- PROC [Command]] = {
Enter[c];
{ENABLE UNWIND => ExitDownCmd[c];
p[c];
};
ExitDownCmd[c];
};
PublicPartsOfCommand: PUBLIC PROC [c: Command] RETURNS [cmd: ROPE, foundData: REF ANY, failed: BOOL, reasonWhyLastDone: ROPE] = {
RETURN [
cmd: c.cmd,
foundData: c.foundData,
failed: c.failed,
reasonWhyLastDone: c.reasonWhyLastDone
];
};
EnumerateSources: PUBLIC --ENTRY-- PROC [c: Command, which: CmdDep, to: PROC [n: Node, which: CmdDep, optional: BOOL]] = {
Inner: --INTERNAL-- PROC [c: Command] = {
InnerEnumerateSources[c, which, to];
};
DoIn[c, Inner];
};
InnerEnumerateSources: PUBLIC --INTERNAL-- PROC [c: Command, which: CmdDep, to: PROC [n: Node, which: CmdDep, optional: BOOL]] = {
which ← which;
FOR e: Edge ← c.from[which].first, e.cNext WHILE e # NIL DO
IF e.c # c THEN ERROR;
to[e.n, which, e.optional];
ENDLOOP;
which ← which;
};
AddConsumption: PUBLIC --ENTRY-- PROC [c: Command, nl: NodeList, which: CmdDep, optional: BOOL] = {
Inner: --INTERNAL-- PROC [c: Command] = {
InnerAddConsumption[c, nl, which, optional];
};
DoIn[c, Inner];
};
InnerAddConsumption: --INTERNAL-- PROC [c: Command, nl: NodeList, which: CmdDep, optional: BOOL] = {
suspect: BOOL ← which = data;
FOR nl ← nl, nl.rest WHILE nl # NIL DO
n: Node ← nl.first;
SELECT which FROM
data => {
[c.from[data], n.to[data]] ← Link[c, c.from[data], n, n.to[data], optional, suspect];
IF (NOT optional) AND NOT Exists[n] THEN {
c.missedSources ← CONS[n, c.missedSources];
};
};
cmd => {
[c.from[cmd], n.to[cmd]] ← Link[c, c.from[cmd], n, n.to[cmd], optional, suspect];
};
ENDCASE => ERROR;
ENDLOOP;
nl ← nl;
};
Link: PUBLIC PROC [c: Command, ch: EdgeRingHead, n: Node, nh: EdgeRingHead, optional, suspect: BOOL] RETURNS [chNew, nhNew: EdgeRingHead] = {
e: Edge ← NEW [EdgeRep ← [
c: c,
n: n,
cNext: ch.first,
cPrev: NIL,
nNext: nh.first,
nPrev: NIL,
optional: optional,
traverseCreated: SELECT suspect FROM
TRUE => unknownTime,
FALSE => GetCreated[n],
ENDCASE => ERROR
]];
ch.first ← nh.first ← e;
IF e.cNext # NIL THEN e.cNext.cPrev ← e ELSE ch.last ← e;
IF e.nNext # NIL THEN e.nNext.nPrev ← e ELSE nh.last ← e;
chNew ← ch;
nhNew ← nh;
};
RemoveConsumption: PUBLIC --ENTRY-- PROC [c: Command, which: CmdDep] = {
Inner: --INTERNAL-- PROC [c: Command] = {InnerRemoveConsumption[c, which]};
DoIn[c, Inner];
};
InnerRemoveConsumption: --INTERNAL-- PROC [c: Command, which: CmdDep] = {
ch: EdgeRingHead ← c.from[which];
cNext: Edge;
FOR e: Edge ← ch.first, cNext WHILE e # NIL DO
n: Node ← e.n;
IF e.c # c THEN ERROR;
cNext ← e.cNext;
e.cNext ← e.cPrev ← NIL;
UnlinkToFrom[e, which];
ENDLOOP;
c.from[which] ← emptyHead;
};
Recurse: --INTERNAL-- PROC [parent: CWork, which: CmdDep, Cont: Continuation] RETURNS [Subgoal] = {
OPEN parent;
sg: Subgoal ← NEW [SubgoalRep ← [
job: job,
toDo: NewWorkTable[],
parent: parent,
PerFinish: ReturnFromSub,
AllDone: Cont
]];
change ← FALSE;
FOR e: Edge ← c.from[which].first, e.cNext WHILE e # NIL DO
sn: Node ← e.n;
sub: NWork ← NEW [WorkRec.node ← [
job: job,
depth: depth+1,
e: e,
subject: node[sn]
]];
InsertWork[sg.toDo, sub];
ENDLOOP;
RETURN [sg];
};
ReturnFromSub: PROC [parent, sub: WorkRef] = {
created: Time;
e: Edge = sub.e;
sn: Node = e.n;
created ← GetCreated[sn];
IF e.traverseCreated # created THEN {
IF parent.job.do THEN e.traverseCreated ← created;
parent.change ← TRUE;
};
};
PostAmble: PROC [cw: CWork, msg: ROPE] = {
IF debugging THEN {OPEN cw;
Log[depth, "EWc <- %g %g", IO.rope[c.cmd], IO.rope[msg]];
};
};
CmdWork: PUBLIC --INTERNAL-- PROC [cWork: CWork] RETURNS [Subgoal] = {
OPEN cWork;
ENABLE UNWIND => c.aborted ← TRUE;
previousNNeed: BOOL = NodeNeededInJob[job, possibleNewNeed];
c.aborted ← FALSE;
IF debugging THEN Log[depth, "EWc -> %g", IO.rope[c.cmd]];
possibleNewNeed.lastVisit ← job.visit;
possibleNewNeed.needed ← TRUE;
IF NOT previousNNeed THEN c.suspectNeed ← TRUE;
c.dataRecurse ← ShouldRemakeCmd[c, data, job.do];
IF NOT (c.dataRecurse OR c.suspectNeed) THEN {
PostAmble[cWork, "not suspected"];
RETURN [NIL]};
dChange ← FALSE;
RETURN[FirstEnsureCmdCorrect[cWork]];
};
FirstEnsureCmdCorrect: --INTERNAL-- PROC [parent: WorkRef] RETURNS [Subgoal] = {
cWork: CWork = NARROW[parent];
{OPEN cWork;
RETURN[
IF ShouldRemakeCmd[c, cmd, job.do] THEN Recurse[cWork, cmd, FinishCmdRecursion]
ELSE IF c.dataRecurse THEN Recurse[cWork, data, FinishCmdExecution]
ELSE FinishCmdExecution[parent]
];
}};
RestEnsureCmdCorrect: --INTERNAL-- PROC [parent: WorkRef] RETURNS [Subgoal] = {
cWork: CWork = NARROW[parent];
{OPEN cWork;
RETURN[
IF job.do AND ShouldRemakeCmd[c, cmd, job.do] THEN Recurse[cWork, cmd, FinishCmdRecursion]
ELSE IF c.dataRecurse THEN Recurse[cWork, data, FinishCmdExecution]
ELSE FinishCmdExecution[parent]
];
}};
FinishCmdRecursion: --INTERNAL-- PROC [parent: WorkRef] RETURNS [Subgoal] = {
cWork: CWork = NARROW[parent];
{OPEN cWork;
cChange ← parent.change;
[] ← ShouldRemakeCmd[c, cmd, job.do];
IF cChange AND job.do THEN {
oldCmd: ROPE ← c.cmd;
from: From;
InnerUnaskOutdated[c];
InnerRemoveConsumption[c, data];
c.missedSources ← NIL;
[from, c.cmd] ← c.class.Rederive[c];
IF NOT oldCmd.Equal[c.cmd] THEN dChange ← TRUE;
InnerAddConsumption[c, from.mustHave, data, FALSE];
InnerAddConsumption[c, from.optional, data, TRUE];
};
RETURN[RestEnsureCmdCorrect[parent]];
}};
FinishCmdExecution: --INTERNAL-- PROC [parent: WorkRef] RETURNS [Subgoal] = {
cWork: CWork = NARROW[parent];
{OPEN cWork;
ch: Commander.Handle ← NIL;
IF change THEN dChange ← TRUE;
[] ← ShouldRemakeCmd[c, data, job.do];
{ClearRemake: PROC [made: Node] = {[] ← ShouldRemakeNode[made, job.do]};
IF job.do THEN EnumerateResults[c, ClearRemake];
};
IF dChange OR c.suspectNeed OR job.assumeAllInconsistent THEN {
resultStack: Table = NewRefTable[];
FreeResult: --INTERNAL-- PROC [made: Node] = {
ReallySuspectNodeChange[made, unforceNotExist, resultStack];
};
KillResult: --INTERNAL-- PROC [made: Node] = {
ReallySuspectNodeChange[made, forceNotExist, resultStack];
};
needsToBeDone, outdated, makesACertainlyModifiable: BOOL;
bitch: BOOLFALSE;
missedResults: NodeList;
whyOutdated: ROPE;
makesACertainlyModifiable ← MakesACertainlyModifiable[job, c];
IF dChange OR job.assumeAllInconsistent THEN {
c.missedSources ← NIL;
FOR e: Edge ← c.from[data].first, e.cNext WHILE e # NIL DO
sn: Node ← e.n;
created: Time ← e.traverseCreated;
IF NOT (e.optional OR created#notExistTime) THEN {
c.missedSources ← CONS[sn, c.missedSources];
IF JustOutsideCertainlyModifiable[job, makesACertainlyModifiable, sn] THEN bitch ← TRUE;
};
ENDLOOP;
InnerUnaskOutdated[c];
};
c.canBeDone ← c.missedSources = NIL;
c.suspectNeed ← FALSE;
[missedResults, outdated, whyOutdated] ← InnerNeedsToBeDone[job, c];
needsToBeDone ← (missedResults#NIL) OR outdated OR job.assumeAllInconsistent;
IF needsToBeDone THEN {
IF c.canBeDone THEN {
IF job.record THEN {
firstCVisit: BOOL = job.visit # c.lastVisit;
c.lastVisit ← job.visit;
IF firstCVisit THEN AddCommand[job, c.cmd];
};
IF job.do THEN {
c.reasonWhyLastDone ← SELECT TRUE FROM
missedResults#NIL => Rope.Cat["results ", EnglishList[missedResults].el, " missed"],
outdated => whyOutdated,
job.assumeAllInconsistent => "I was told to assume everything inconsistent",
ENDCASE => ERROR;
IF ch = NIL THEN ch ← GetCommanderHandle[];
IF debugging THEN Confirm[depth, c.cmd];
IncrementStepCount[job];
c.failed ← CommandTool.DoCommand[c.cmd, ch] = $Failure;
c.succeeded ← NOT c.failed;
IF c.failed THEN AddFailedCmd[job, c]
ELSE EnumerateResults[c, FreeResult];
InnerUnaskOutdated[c];
}
ELSE c.succeeded ← c.failed ← FALSE;
}
ELSE {
c.succeeded ← FALSE;
c.failed ← makesACertainlyModifiable;
};
}
ELSE {
c.succeeded ← FALSE;
c.failed ← makesACertainlyModifiable AND NOT c.canBeDone;
};
IF c.failed THEN EnumerateResults[c, KillResult];
IF bitch AND dChange THEN {
SIGNAL Warning[IO.PutFR[
"Couldn't %g%g because %g missing or unmakeable.\n",
IO.rope[IF needsToBeDone THEN "" ELSE "check consistency of "],
IO.rope[c.cmd],
IO.rope[EnglishList[c.missedSources].el]]];
};
};
PostAmble[cWork, "end"];
RETURN [NIL];
}};
NeedsToBeDone: PUBLIC --ENTRY-- PROC [job: Job, c: Command, alwaysAsk: BOOL] RETURNS [missedResults: NodeList, outdated: BOOL] = {
Inner: --INTERNAL-- PROC [c: Command] = {
IF alwaysAsk THEN InnerUnaskOutdated[c];
[missedResults, outdated] ← InnerNeedsToBeDone[job, c];
};
DoIn[c, Inner];
};
InnerNeedsToBeDone: --INTERNAL-- PROC [job: Job, c: Command] RETURNS [missedResults: NodeList, outdated: BOOL, whyOutdated: ROPE] = {
PerResult: --INTERNAL-- PROC [made: Node] = {
IF NodeNeededInJob[job, made] AND NOT Exists[made] THEN missedResults ← CONS[made, missedResults];
};
missedResults ← NIL;
EnumerateResults[c, PerResult];
IF NOT c.outdatedAsked THEN {
NeededForMe: PROC [n: Node] RETURNS [BOOL] = {
RETURN [NodeNeededInJob[job, n]]};
c.outdatedAsked ← TRUE;
IF debugging THEN Log[0, "?Outdated[%g]", IO.rope[c.cmd]];
c.whyOutdated ← c.class.NotCurrent[c, NeededForMe];
c.outdated ← c.whyOutdated # NIL;
IF debugging THEN Log[0, "Outdated[%g]=%g", IO.rope[c.cmd], IO.bool[c.outdated]];
};
whyOutdated ← c.whyOutdated;
outdated ← c.outdated;
};
InnerUnaskOutdated: --INTERNAL-- PROC [c: Command] = {
c.outdatedAsked ← FALSE;
c.whyOutdated ← "Nobody should ever see this";
};
NodeNeededInJob: --INTERNAL-- PROC [job: Job, n: Node] RETURNS [BOOL] = {
ENABLE UNWIND => {};
RETURN [n.lastVisit = job.visit AND n.needed];
};
FoundCertainlyModifiableResult: ERROR = CODE;
MakesACertainlyModifiable: --INTERNAL-- PROC [job: Job, c: Command] RETURNS [ans: BOOL] = {
TestResult: PROC [n: Node] = {
IF CertainlyModifiable[job, n] THEN ERROR FoundCertainlyModifiableResult;
};
ans ← FALSE;
EnumerateResults[c, TestResult !
FoundCertainlyModifiableResult => {ans ← TRUE; CONTINUE}
];
ans ← ans;
};
CertainlyModifiable: PROC [job: Job, n: Node] RETURNS [certainly: BOOL] = {
certainly ← IsRootGoal[job, n] OR (job.boundaryKnown AND NodeInTable[n, job.modifiable]);
};
JustOutsideCertainlyModifiable: PROC [job: Job, makesACertainlyModifiable: BOOL, n: Node] RETURNS [BOOL] = {
IF NOT makesACertainlyModifiable THEN RETURN [FALSE];
IF CertainlyModifiable[job, n] THEN RETURN [FALSE];
RETURN [TRUE];
};
END.