DIRECTORY Atom, BasicTime, CD, CDEvents USING [EventProc, RegisterEventProc], CDIO, CDOps USING [DoTheDelayedRedraws], CDSequencer, CDViewer, IO, MBQueue USING [Queue, Create, QueueClientAction], Process, RefTab, Rope, RuntimeError, TerminalIO USING [WriteRope, UserAbort], TokenIO, UserProfile USING [CallWhenProfileChanges, ProfileChangedProc, Number], ViewerOps; CDSequencerImpl: CEDAR MONITOR IMPORTS Atom, BasicTime, CD, CDEvents, CDIO, CDOps, CDViewer, IO, MBQueue, Process, RefTab, RuntimeError, TerminalIO, TokenIO, UserProfile, ViewerOps EXPORTS CDSequencer, CD = BEGIN Command: TYPE = CDSequencer.Command; CommandProc: TYPE = CDSequencer.CommandProc; QueueMethod: TYPE = CDSequencer.QueueMethod; CommandPrivate: TYPE = CDSequencer.CommandPrivate; priviledgedRefTab: RefTab.Ref = RefTab.Create[mod: 17]; -- holds commands not to be used globalRefTab: RefTab.Ref = RefTab.Create[mod: 53]; -- holds commands used in all technologies designNumber: INT_0; DesignEntry: TYPE = RECORD [ whileCommand: BOOL_FALSE, --modifyed exclusively by the monitored command procedures whileOutput: BOOL_FALSE, --modifyed exclusively by one single output process parity: BOOL_TRUE, abort: BOOL_FALSE, lastCommand: BasicTime.GMT, lastOutput: BasicTime.GMT, num: INT_0 ]; SequencerDesignPrivate: PUBLIC TYPE = DesignEntry; start: BasicTime.GMT = BasicTime.Now[]; now: BasicTime.GMT _ BasicTime.Now[]; TechnologyCommandsRep: PUBLIC TYPE = RECORD [ commandTab: RefTab.Ref ]; DesignHasBeenCreated: CDEvents.EventProc ={ design.queue _ MBQueue.Create[]; designNumber _ designNumber+1; design.seqPrivate _ NEW[DesignEntry_[lastCommand: now, lastOutput: now, num: designNumber]]; }; TechnologyHasBeenRegistered: CDEvents.EventProc = BEGIN tech: CD.Technology ~ NARROW[x]; tech.technologyCommands _ NEW[TechnologyCommandsRep _ [commandTab: RefTab.Create[mod: 31]]] END; InternalExecuteCommand: PROC [ref: REF ANY] = BEGIN ENABLE { ABORTED => GOTO Aborted; TerminalIO.UserAbort => GOTO TerminalAborted; }; comm: Command = NARROW[ref]; de: REF DesignEntry = comm.design.seqPrivate; de.abort _ FALSE; IF comm.private.p#NIL THEN { IF comm.private.qm#dontQueue THEN { de.whileCommand _ TRUE; WHILE de.whileOutput DO TokenIO.StopWriting[]; IF de.whileOutput THEN Process.Pause[Process.MsecToTicks[1]] ENDLOOP; de.lastCommand _ now; IF comm.private.qm=doQueueAndMark THEN { comm.design.actual.first.changed _ TRUE; }; comm.private.p[comm]; de.whileCommand _ FALSE } ELSE comm.private.p[comm]; CDOps.DoTheDelayedRedraws[comm.design]; } ELSE { TerminalIO.WriteRope["command "]; TerminalIO.WriteRope[Atom.GetPName[comm.a]]; TerminalIO.WriteRope[" not loaded\n"]; }; EXITS Aborted => {TerminalIO.WriteRope["** ABORTED\n"]}; TerminalAborted => {TerminalIO.WriteRope["** user aborted\n"]}; END; ImplementCommand: PUBLIC ENTRY PROC [a: ATOM, p: CommandProc, technology: CD.Technology_NIL, queue: QueueMethod] = BEGIN ENABLE UNWIND => NULL; ptr: REF CommandPrivate ~ NEW[CommandPrivate_[p: p, qm: queue]]; myRefTab: RefTab.Ref _ globalRefTab; IF p=NIL THEN {[] _ RefTab.Insert[priviledgedRefTab, a, technology]; RETURN} ELSE IF RefTab.Fetch[priviledgedRefTab, a].found THEN RETURN WITH ERROR CD.Error[doubleRegistration, "This atom is reserved"]; IF technology#NIL THEN { techCommands: REF TechnologyCommandsRep ~ technology.technologyCommands; myRefTab _ techCommands.commandTab; }; [] _ RefTab.Store[myRefTab, a, ptr] END; ExecuteCommand: PUBLIC PROC [comm: Command, design: CD.Design, as: ATOM, queue: CDSequencer.QueueMethod] = BEGIN BuildCommandPrivate: PROC[] = INLINE BEGIN found: BOOLEAN _ FALSE; val: RefTab.Val; IF newComm.design.technology#NIL THEN { -- search first for particular technology cTab: REF TechnologyCommandsRep = newComm.design.technology.technologyCommands; [found, val] _ RefTab.Fetch[cTab.commandTab, newComm.a]; }; IF NOT found THEN [found, val] _ RefTab.Fetch[globalRefTab, newComm.a]; -- search global IF found THEN newComm.private _ NARROW[val, REF CommandPrivate] ELSE newComm.private _ NEW[CommandPrivate _ [p: NIL, qm: queue]] --usually END; newComm: CDSequencer.Command ~ NEW[CDSequencer.CommandRec_comm^]; IF as#NIL THEN newComm.a _ as; IF design#design THEN newComm.design _ design; IF newComm.design=NIL THEN ERROR; BuildCommandPrivate[]; IF queue#useDefault AND newComm.private.qm#queue THEN newComm.private _ NEW[CommandPrivate _ [p: newComm.private.p, qm: queue]]; IF newComm.private.qm#dontQueue THEN MBQueue.QueueClientAction[newComm.design.queue, InternalExecuteCommand, newComm] ELSE InternalExecuteCommand[newComm] END; AbortTheCommand: PUBLIC PROC [design: CD.Design] = BEGIN de: REF DesignEntry = design.seqPrivate; IF de.whileCommand THEN de.abort _ TRUE END; Aborted: PUBLIC PROC [design: CD.Design] RETURNS [BOOL] = BEGIN de: REF DesignEntry = design.seqPrivate; RETURN [de.abort] END; CheckAborted: PUBLIC PROC [design: CD.Design] = BEGIN de: REF DesignEntry = design.seqPrivate; IF de.abort THEN SIGNAL TerminalIO.UserAbort END; SaveOneDesign: PROC [design: CD.Design] = BEGIN ENABLE { TokenIO.WritingStopped => GOTO end; RuntimeError.UNCAUGHT => GOTO end; }; de: REF DesignEntry = design.seqPrivate; saveOn: Rope.ROPE; done: BOOL; IF de.parity THEN saveOn _ IO.PutFR["///temp/chipndale/saved%01gA.dale", IO.int[de.num]] ELSE saveOn _ IO.PutFR["///temp/chipndale/saved%01gB.dale", IO.int[de.num]]; done _ CDIO.WriteDesign[design: design, to: saveOn, quiet: TRUE, emergency: FALSE]; IF done THEN { de.lastOutput _ BasicTime.Now[]; de.parity _ ~de.parity; }; TokenIO.ReleaseWriter[]; EXITS end => NULL END; EmergencySaveProcess: PROC = BEGIN SaveAViewer: ViewerOps.EnumProc -- PROC [v: Viewer] RETURNS [BOOL _ TRUE] -- = BEGIN design: CD.Design = CDViewer.DesignOf[v].design; -- is not monitored IF design#NIL THEN { de: REF DesignEntry = design.seqPrivate; IF de#NIL AND NOT de.whileCommand AND BasicTime.Period[from: de.lastCommand, to: now]>15 AND BasicTime.Period[from: de.lastOutput, to: de.lastCommand]>savePeriod THEN { de.whileOutput _ TRUE; IF NOT de.whileCommand THEN SaveOneDesign[design]; }; IF de#NIL THEN de.whileOutput _ FALSE } END; DO -- forever now _ BasicTime.Now[]; Process.Pause[Process.SecondsToTicks[10]]; IF savePeriod>=0 THEN ViewerOps.EnumerateViewers[SaveAViewer] ENDLOOP; END; savePeriod: INT _ 0; NoteProfileChange: UserProfile.ProfileChangedProc -- PROC [reason: ProfileChangeReason]-- = BEGIN savePeriod _ UserProfile.Number[key: "Chipndale.SavePeriod", default: 0]; END; CDEvents.RegisterEventProc[$RegisterTechnology, TechnologyHasBeenRegistered]; CDEvents.RegisterEventProc[$CreateNewDesign, DesignHasBeenCreated]; UserProfile.CallWhenProfileChanges[NoteProfileChange]; TRUSTED {Process.Detach[FORK EmergencySaveProcess[]]}; END. ®CDSequencerImpl.mesa (part of Chipndale) by Christian Jacobi June 22, 1983 6:02 pm last edited by Christian Jacobi February 16, 1984 5:05 pm --caller must guarantee: comm.private#NIL -- If technology is NIL implement for all technologies. -- There is a (finite, short) list of atoms you MUST NOT use. -- Reimplementing the same atom in a technology it already exists overwrites the command; -- If the same atom is specified for a particular technology and all technologies, -- the more specific implementation wins independent of order. -- Don't fool with NIL CommandProc's if you don't know EXACTLY what it does. -- (NIL CommandProc's serves too install the list of commands you MUST NOT use.) -- check if is reserved atom not to be used -- do implementation OldQueueCommand: PUBLIC PROC[design: CD.Design_NIL, comm: Command] = -- oldy, for speed reason don't call ExecuteCommand BEGIN IF design=NIL THEN design _ comm.design; comm.design _ design; IF design=NIL THEN ERROR; MBQueue.QueueClientAction[design.queue, InternalExecuteCommand, comm]; END; -- if as#NIL replaces comm.a -- if design#NIL replaces comm.design --uses globals newCom and queue --we queue the message for unknown command; take it from queue --IF Aborted[design] THEN SIGNAL TerminalIO.UserAbort -- make garbage collection possible IF CDViewer.ViewersOf[design]=NIL THEN [] _ RefTab.Delete[designTable, design]; --Hint for correctness proof: --this (above) assignment statement to de.whileOutput happens either before --or after an assgnment to de.whileCommand or there is no conflict at all --If this before: in command process we wait until outout is finished --If this after: we skip the output (next if statement) Ê ï˜Jšœ*™*Jšœ,™,Jšœ;™;J˜šÏk ˜ J˜Jšœ ˜ Jšœ˜Jšœ œ ˜.Jšœ˜Jšœœ˜"Jšœ ˜ Jšœ ˜ Jšœ˜Jšœœ$˜1Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ œ˜(Jšœ˜Jšœ œ6˜GJšœ ˜ J˜—šÏbœœœ˜Jš œœœœœT˜–Jšœœ˜—Jš˜J˜Jšœ œ˜$Jšœ œ˜,Jšœ œ˜,Jšœœ˜2J˜Jšœ8Ïc ˜XJšœ3Ÿ*˜]J˜Jšœœ˜šœ œœ˜JšœœœŸ:˜TJšœ œœŸ3˜LJšœœœ˜Jšœœœ˜Jšœœ˜Jšœœ˜Jšœœ˜ Jšœ˜—Jšœœœ˜2Jšœœ˜'Jšœœ˜%šœœœœ˜-J˜J˜—J˜šžœ˜+Jšœ ˜ Jšœ˜JšœœE˜\Jšœ˜—J˜šžœ˜1Jš˜Jšœœœ˜ šœœ˜4Jšœ'˜'—Jšœ˜—J˜šÏnœœœœ˜-Jšœ)™)Jš˜šœ˜Jšœœ ˜Jšœœ˜-J˜—Jšœœ˜Jšœœ&˜-Jšœ œ˜šœœœ˜šœœ˜#Jšœœ˜šœ˜Jšœ˜Jšœœ&˜™>—Jšœ˜—J˜Jšœœ˜AJšœœœ˜Jšœœ˜.Jšœœœœ˜!Jšœ˜šœœ˜5Jšœœ5˜J—šœœ˜%JšœP˜P—Jšœ ˜$Jšœ˜—J˜J˜š œ œ œ ˜2Jš˜Jšœœ!˜(Jšœœ ˜'Jšœ˜—J˜š  œœœ œ œœ˜9Jš˜Jšœœ!˜(Jšœ ˜Jšœ˜—J˜š  œœœ œ ˜0JšŸ5™5Jš˜Jšœœ!˜(Jšœ œœ˜,Jšœ˜J™—š  œœ œ ˜)Jš˜šœ˜Jšœœ˜#Jšœ œœ˜"J˜—Jšœœ!˜(Jšœ œ˜Jšœœ˜ šœ ˜Jšœ œ;˜F—Jšœ œ<˜LJšœœ0œ œ˜Sšœœ˜Jšœ ˜ Jšœ˜Jšœ#™#Jšœœœ)™OJ˜—Jšœ˜š˜Jšœ˜ —Jšœ˜J˜—š œœ˜Jš˜šž œŸ,œ˜NJš˜Jšœœ(Ÿ˜Ešœœœ˜Jšœœ"˜)šœœœœ˜"Jšœ4˜7JšœF˜I—šœ˜Jšœœ˜šœ™JšœL™LJšœI™IJšœE™EJšœ8™8—Jšœœœ˜2J˜—Jšœœœ˜%Jšœ˜—Jšœ˜—šœŸ ˜ Jšœ˜Jšœ*˜*Jšœœ(˜=Jšœ˜—Jšœ˜J˜—Jšœ œ˜šžœ!Ÿ'œ˜[Jš˜JšœI˜IJšœ˜—J˜JšœM˜MJ˜CJšœ6˜6Jšœœ˜6Jšœ˜J˜J˜—…—H*å