DIRECTORY Atom, BasicTime, CedarProcess, CD, CDEvents USING [EventProc, RegisterEventProc, ProcessEvent, EventRegistration, RegisterEventType], CDIO, CDOps USING [DoTheDelayedRedraws], CDSequencer, CDViewer, IO, MBQueue USING [Queue, Create, QueueClientAction, Flush], Process, RefTab, Rope, RuntimeError, TerminalIO USING [WriteRope, UserAbort, WriteLn], TokenIO, UserProfile USING [CallWhenProfileChanges, ProfileChangedProc, Number], ViewerOps; CDSequencerImpl: CEDAR MONITOR IMPORTS Atom, BasicTime, CedarProcess, CD, CDEvents, CDIO, CDOps, CDViewer, IO, MBQueue, Process, RefTab, Rope, RuntimeError, TerminalIO, TokenIO, UserProfile, ViewerOps EXPORTS CDSequencer, CD = BEGIN Command: TYPE = CDSequencer.Command; CommandProc: TYPE = CDSequencer.CommandProc; QueueMethod: TYPE = CDSequencer.QueueMethod; CommDescriptor: TYPE = CDSequencer.CommDescriptor; priviledgedRefTab: RefTab.Ref = RefTab.Create[mod: 7]; -- holds commands not to be used globalRefTab: RefTab.Ref = RefTab.Create[mod: 193]; -- holds commands used in all technologies quit: ERROR [msg: Rope.ROPE] = CODE; --actually is signal, but we never return... 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 = BEGIN design.queue _ MBQueue.Create[]; designNumber _ designNumber+1; design.seqPrivate _ NEW[DesignEntry_[ lastCommand: now, lastOutput: now, num: designNumber ]]; END; UnKnownCommand: PROC [comm: CDSequencer.Command] = BEGIN TerminalIO.WriteRope["command "]; IF comm#NIL AND comm.a#NIL THEN TerminalIO.WriteRope[Atom.GetPName[comm.a]]; TerminalIO.WriteRope[" not loaded\n"]; END; TechnologyHasBeenRegistered: CDEvents.EventProc = BEGIN NARROW[x, CD.Technology].technologyCommands _ NEW[TechnologyCommandsRep _ [commandTab: RefTab.Create[mod: 41]]] END; InternalExecuteCommand: PROC [ref: REF ANY] = BEGIN ENABLE { ABORTED => GOTO Aborted; TerminalIO.UserAbort => GOTO TerminalAborted; quit => { IF Rope.Length[msg]>0 THEN { TerminalIO.WriteRope[msg]; IF Rope.Fetch[msg, Rope.Length[msg]-1]#'\n THEN TerminalIO.WriteLn[] }; GOTO finish }; }; comm: Command = NARROW[ref]; de: REF DesignEntry = comm.design.seqPrivate; CedarProcess.SetPriority[CedarProcess.Priority[normal]]; de.abort _ FALSE; IF comm.fetched.qm=dontQueue THEN comm.fetched.p[comm] ELSE { de.whileCommand _ TRUE; WHILE de.whileOutput DO TokenIO.StopWriting[]; IF de.whileOutput THEN Process.Pause[1] ENDLOOP; de.lastCommand _ now; IF comm.fetched.qm=doQueueAndMark THEN { comm.design.actual.first.changed _ TRUE; }; comm.fetched.p[comm]; de.whileCommand _ FALSE }; CDOps.DoTheDelayedRedraws[comm.design]; EXITS Aborted => {TerminalIO.WriteRope["** ABORTED\n"]}; TerminalAborted => {TerminalIO.WriteRope["** user aborted\n"]}; finish => NULL; END; QuitCommand: PUBLIC PROC [message: Rope.ROPE] = BEGIN quit[message] END; ImplementCommand: PUBLIC ENTRY PROC [a: ATOM, p: CommandProc, technology: CD.Technology_NIL, queue: QueueMethod] = BEGIN ENABLE UNWIND => NULL; ptr: REF CommDescriptor = NEW[CommDescriptor _ [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; FetchCommand: PUBLIC PROC[a: ATOM, technology: CD.Technology] RETURNS [cd: REF READONLY CommDescriptor] = BEGIN IF technology#NIL THEN { -- search first for particular technology cTab: REF TechnologyCommandsRep = technology.technologyCommands; val: RefTab.Val _ RefTab.Fetch[cTab.commandTab, a].val; IF val#NIL THEN RETURN [NARROW[val]]; }; -- search global RETURN [NARROW[RefTab.Fetch[globalRefTab, a].val]]; END; ExecuteProc: PUBLIC PROC [comm: CDSequencer.Command _ NIL, design: CD.Design _ NIL, proc: CommandProc, queue: QueueMethod _ doQueue] = BEGIN newComm: CDSequencer.Command = NEW[CDSequencer.CommandRec]; IF comm#NIL THEN newComm^ _ comm^; IF design#NIL THEN newComm.design _ design; IF proc=NIL THEN proc _ UnKnownCommand; newComm.fetched _ NEW[CommDescriptor _ [p: proc, qm: queue]]; IF queue#useDefault AND newComm.fetched.qm#queue THEN newComm.fetched _ NEW[CommDescriptor _ [p: newComm.fetched.p, qm: queue]]; IF newComm.fetched.qm#dontQueue THEN MBQueue.QueueClientAction[newComm.design.queue, InternalExecuteCommand, newComm] ELSE InternalExecuteCommand[newComm] END; ExecuteCommand: PUBLIC PROC [comm: Command, design: CD.Design, command: ATOM, queue: CDSequencer.QueueMethod] = BEGIN newComm: CDSequencer.Command = NEW[CDSequencer.CommandRec]; IF comm#NIL THEN newComm^ _ comm^; IF command#NIL THEN newComm.a _ command; IF design#NIL THEN newComm.design _ design; newComm.fetched _ FetchCommand[newComm.a, newComm.design.technology]; IF newComm.fetched=NIL THEN newComm.fetched _ NEW[CommDescriptor _ [p: UnKnownCommand, qm: dontQueue]]; IF queue#useDefault AND newComm.fetched.qm#queue THEN newComm.fetched _ NEW[CommDescriptor _ [p: newComm.fetched.p, qm: queue]]; IF newComm.fetched.qm#dontQueue THEN MBQueue.QueueClientAction[newComm.design.queue, InternalExecuteCommand, newComm] ELSE InternalExecuteCommand[newComm] END; MarkChanged: PUBLIC PROC [design: CD.Design] = BEGIN design.actual.first.changed _ TRUE END; AbortTheCommand: PUBLIC PROC [design: CD.Design] = BEGIN IF design#NIL THEN { de: REF DesignEntry = design.seqPrivate; IF de.whileCommand THEN de.abort _ TRUE }; [] _ CDEvents.ProcessEvent[abortRequest, design]; IF design#NIL THEN MBQueue.Flush[design.queue]; 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 de: REF DesignEntry = design.seqPrivate; done: BOOL _ FALSE; error: BOOL _ FALSE; done _ CDIO.WriteDesign[design: design, to: IO.PutFR["///temp/ChipNDale/saved/%01g%01g%01g.dale", IO.rope[CDIO.MakeShortName[design]], IO.int[de.num], IO.char[IF de.parity THEN 'A ELSE 'B]], quiet: TRUE, emergency: FALSE ! TokenIO.WritingStopped, RuntimeError.UNCAUGHT => {error_TRUE; CONTINUE} ]; IF error THEN TokenIO.ReleaseWriter[] ELSE IF done THEN { de.lastOutput _ BasicTime.Now[]; de.parity _ ~de.parity; } END; EmergencySaveProcess: PROC = BEGIN SaveAViewer: ViewerOps.EnumProc -- PROC [v: Viewer] RETURNS [BOOL _ TRUE] -- = BEGIN ENABLE RuntimeError.UNCAUGHT => GOTO oops; --give the next viewer a chance design: CD.Design; Process.Pause[1]; --make it a little bit slower for the benefit of the viewer redraw 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 { CedarProcess.SetPriority[CedarProcess.Priority[normal]]; de.whileOutput _ TRUE; IF NOT de.whileCommand THEN { SaveOneDesign[design]; } }; IF de#NIL THEN de.whileOutput _ FALSE; CedarProcess.SetPriority[CedarProcess.Priority[background]]; --speed no more necessary }; EXITS oops => NULL; END; DO -- forever now _ BasicTime.Now[]; Process.Pause[Process.SecondsToTicks[8]]; 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; abortRequest: CDEvents.EventRegistration = CDEvents.RegisterEventType[$Abort]; CDEvents.RegisterEventProc[$RegisterTechnology, TechnologyHasBeenRegistered]; CDEvents.RegisterEventProc[$CreateNewDesign, DesignHasBeenCreated]; UserProfile.CallWhenProfileChanges[NoteProfileChange]; TRUSTED {Process.Detach[FORK EmergencySaveProcess[]]}; END. ΞCDSequencerImpl.mesa (part of ChipNDale) Copyright c 1983, 1986 by Xerox Corporation. All rights reserved. by Christian Jacobi, June 22, 1983 6:02 pm last edited by Christian Jacobi, January 2, 1986 3:41:52 pm PST --caller must guarantee: comm.fetched#NIL --write message and terminates execution of the command of this process --never returns -- 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 --if design#NIL replaces comm.design --if command#NIL replaces comm.a --if design#NIL replaces comm.design --IF Aborted[design] THEN SIGNAL TerminalIO.UserAbort --set priority high enough to stop quickly if necessary --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) --EmergencySaveProcess Κ Ϊ˜codešœ*™*Kšœ Οmœ7™BKšœ,™,Kšœ@™@K˜—šΟk ˜ K˜Kšœ ˜ Kšœ ˜ Kšžœ˜Kšœ žœT˜bKšœ˜Kšœžœ˜"Kšœ ˜ Kšœ ˜ Kšœ˜Kšœžœ+˜8Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ žœ!˜1Kšœ˜Kšœ žœ6˜GKšœ ˜ —K˜šΠblœžœžœ˜Kšžœ žœ žœžœ\˜ͺKšžœžœ˜—Kšž˜K˜Kšœ žœ˜$Kšœ žœ˜,Kšœ žœ˜,Kšœžœ˜2K˜Kšœ7Οc ˜WKšœ4 *˜^Kšœžœ žœžœ ,˜QKšœžœ˜K˜šœ žœžœ˜Kšœžœžœ :˜TKšœ žœžœ 3˜LKšœžœžœ˜Kšœžœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜ Kšœ˜—K˜Kšœžœžœ˜2Kšœžœ˜'Kšœžœ˜%šœžœžœžœ˜-K˜K˜—K˜šΟbœ˜*Kšž˜Kšœ ˜ Kšœ˜šœžœ˜%Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšžœ˜—K˜šΟnœžœ˜2Kšž˜Kšœ!˜!Kš žœžœžœžœžœ-˜LKšœ&˜&Kšžœ˜—K˜š‘œ˜1Kšž˜Kšžœžœ"žœ>˜oKšžœ˜—K˜š’œžœžœžœ˜-Kšœ)™)Kšž˜šžœ˜Kšžœžœ ˜Kšœžœ˜-šœ ˜ šžœžœ˜Kšœ˜Kšžœ)žœ˜DKšœ˜—Kšžœ˜ Kšœ˜—Kšœ˜—Kšœžœ˜Kšœžœ&˜-Kšœ8˜8Kšœ žœ˜Kšžœžœ˜6šžœ˜Kšœžœ˜šžœž˜Kšœ˜Kšžœžœ˜'Kšžœ˜—Kšœ˜šžœ žœ˜(Kšœ#žœ˜(Kšœ˜—Kšœ˜Kšœž˜Kšœ˜—Kšœ'˜'šž˜K˜2K˜?Kšœ žœ˜—Kšžœ˜—K˜š’ œžœžœžœ˜/KšœG™GKšœ™Kšž˜Kšœ ˜ Kšžœ˜—K˜š’œžœžœžœžœžœ žœ˜tKšœ7™7Kšœ=™=KšœZ™ZKšœR™RKšœ?™?KšœL™LKšœP™Pšž˜Kšžœžœžœ˜—Kšœžœžœ%˜BK˜$Kšœ+™+Kšžœžœžœ8žœ˜Lšžœžœ*žœ˜6Kšžœžœžœžœ4˜H—Kšœ™šžœ žœžœ˜Kšœžœ7˜HK˜#Kšœ˜—K˜#Kšžœ˜—K˜š’ œž œžœžœ žœžœžœ˜iKšž˜šžœ žœžœ )˜BKšœžœ7˜@Kšœ7˜7Kš žœžœžœžœžœ˜%Kšœ˜—Kš ˜Kšžœžœ%˜3Kšžœ˜—K˜š ’ œž œžœ žœ žœ4˜†Kšœ$™$Kšž˜Kšœžœ˜;Kšžœžœžœ˜"Kšžœžœžœ˜+Kšžœžœžœ˜'Kšœžœ(˜=šžœžœž˜5Kšœžœ5˜J—šžœžœ˜%KšœP˜P—Kšžœ!˜%Kšžœ˜—K˜š ’œžœžœžœžœ#˜oKšœ ™ Kšœ%™%Kšž˜Kšœžœ˜;Kšžœžœžœ˜"Kšžœ žœžœ˜(Kšžœžœžœ˜+KšœE˜Ešžœžœžœ˜Kšœžœ6˜K—šžœžœž˜5Kšœžœ5˜J—šžœžœ˜%KšœP˜P—Kšžœ!˜%Kšžœ˜—K˜š’ œžœžœ žœ ˜.Kšž˜Kšœž˜"Kšžœ˜—K˜š’œžœžœ žœ ˜2Kšž˜šžœžœžœ˜Kšœžœ!˜(Kšžœžœ ž˜'K˜—Kšœ1˜1Kšžœžœžœ˜/Kšžœ˜—K˜š ’œžœžœ žœ žœžœ˜9Kšž˜Kšœžœ!˜(Kšžœ ˜Kšžœ˜—K˜š’ œžœžœ žœ ˜0Kš 5™5Kšž˜Kšœžœ!˜(Kšžœ žœžœ˜,Kšžœ˜K™—š’ œžœ žœ ˜)Kšž˜Kšœžœ!˜(Kšœžœžœ˜Kšœžœžœ˜šœžœ˜(Kšœžœ4žœžœžœžœžœ žœžœ˜™Kšœžœ˜ Kšœ ž˜Kšœ'žœ žœžœ˜IKšœ˜—Kšžœžœ˜%šžœžœžœ˜Kšœ ˜ Kšœ˜K˜—Kšžœ˜K˜—š’œžœ˜Kšž˜K˜š‘ œ ,œ˜Nšž˜Kšžœžœžœ ˜J—Kšœžœ˜Kšœ B˜TKšœ' ˜:šžœžœžœ˜Kšœžœ"˜)šžœžœžœžœ˜"Kšžœ4˜7KšžœF˜I—šžœ˜šœ9˜9Kšœ7™7—Kšœžœ˜šœ™KšœL™LKšœI™IKšœE™EKšœ8™8—šžœžœžœ˜Kšœ˜K˜—K˜—Kšžœžœžœž˜&Kšœ= ˜VKšœ˜—Kšžœ žœ˜Kšžœ˜—K˜Kšœ™šžœ  ˜ Kšœ˜Kšœ)˜)Kšžœžœ(˜=Kšžœ˜—Kšžœ˜K˜—Kšœ žœ˜š‘œ! 'œ˜[Kšž˜KšœI˜IKšžœ˜—K˜KšœN˜NKšœM˜MK˜CKšœ6˜6Kšžœžœ˜6Kšžœ˜K˜K˜—…—!t3