DIRECTORY Atom, BasicTime, CD, CDEvents USING [EventProc, RegisterEventProc, ProcessEvent, EventRegistration, RegisterEventType], CDIO, CDOps USING [DoTheDelayedRedraws], CDSequencer, CDValue, CDViewer, FileNames, IO, MBQueue USING [Queue, Create, QueueClientAction, Flush], 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, CDValue, CDViewer, FileNames, 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; 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; TRUSTED {Process.SetPriority[Process.priorityNormal]}; 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 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; MakeShortName: PROC [design: CD.Design] RETURNS [name: Rope.ROPE _ NIL] = BEGIN TrailingDot: PROC [base: Rope.ROPE] RETURNS [INT] = { len: INT _ Rope.Length[base]; pos: INT _ len; WHILE pos > 0 DO SELECT Rope.Fetch[base, pos _ pos - 1] FROM '. => RETURN [pos]; '!, '], '>, '/ => EXIT; ENDCASE; ENDLOOP; RETURN [len]; }; SuggestedModule: PROC [base: Rope.ROPE] RETURNS [Rope.ROPE] = { len, dot: INT; base _ FileNames.GetShortName[base]; len _ Rope.Length[base]; dot _ TrailingDot[base]; IF len>dot AND Rope.Equal[Rope.Substr[base, dot+1], "dale", FALSE] THEN base _ Rope.Substr[base, 0, dot]; RETURN [base] }; WITH CDValue.Fetch[boundTo: design, key: $CDxFromFile] SELECT FROM r: Rope.ROPE => name _ SuggestedModule[r]; ENDCASE => NULL; IF name=NIL THEN name _ design.name; IF name=NIL THEN name _ "noname" END; SaveOneDesign: PROC [design: CD.Design] = BEGIN de: REF DesignEntry = design.seqPrivate; done: BOOL _ FALSE; error: BOOL _ FALSE; shortName: Rope.ROPE _ MakeShortName[design]; code: CHAR = IF de.parity THEN 'A ELSE 'B; fileName: Rope.ROPE = IO.PutFR["///temp/chipndale/saved/%01g%01g%01g.dale", IO.rope[shortName], IO.int[de.num], IO.char[code]]; done _ CDIO.WriteDesign[design: design, to: fileName, 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 exit; --give the next viewer a chance 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 } EXITS exit => NULL; END; TRUSTED {Process.SetPriority[Process.priorityBackground]}; 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; 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, 1984 by Xerox Corporation. All rights reserved. by Christian Jacobi June 22, 1983 6:02 pm last edited by Christian Jacobi October 25, 1984 4:56:45 pm PDT --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 -- 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 --position of last dot --given a filename, suggests a modulename --MakeShortName --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šœ Ïmœ7™BJšœ,™,JšœA™A—J˜šÏk ˜ J˜Jšœ ˜ Jšžœ˜Jšœ žœT˜bJšœ˜Jšœžœ˜"Jšœ ˜ Jšœ˜Jšœ ˜ Jšœ ˜ Jšœ˜Jšœžœ+˜8Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ žœ˜(Jšœ˜Jšœ žœ6˜GJšœ ˜ J˜—šÏbœžœžœ˜Jšžœžœ žœ'žœ\˜°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šžœ/˜6Jšœ žœ˜šžœžœžœ˜šžœžœ˜#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šœ1˜1Jšžœžœžœ˜/Jšžœ˜—J˜š ¡œžœžœ žœ žœžœ˜9Jšž˜Jšœžœ!˜(Jšžœ ˜Jšžœ˜—J˜š¡ œžœžœ žœ ˜0Jš 5™5Jšž˜Jšœžœ!˜(Jšžœ žœžœ˜,Jšžœ˜J™—š ¡ œžœ žœ žœ žœžœ˜IJšž˜J˜š ¡ œžœ žœžœžœ˜5Jšœ™Jšœžœ˜Jšœžœ˜šžœ ž˜šžœ!ž˜+Jšœžœ˜Jšœžœ˜Jšžœ˜—Jšžœ˜—Jšžœ˜ J˜J˜—š ¡œžœ žœžœžœ˜?Jšœ)™)Jšœ žœ˜Jšœ$˜$Jšœ˜Jšœ˜šžœ žœ.žœžœ˜HJšœ!˜!—Jšžœ˜ J˜—J˜Jšœ™šžœ3žœžœ˜CJšœžœ˜*Jšžœžœ˜—Jšžœžœžœ˜$Jšžœžœžœ˜ Jšžœ˜J˜—š¡ œžœ žœ ˜)Jšž˜Jšœžœ!˜(Jšœžœžœ˜Jšœžœžœ˜Jšœžœ˜-Jš œžœžœ žœžœ˜*Jš œžœžœ4žœžœžœ ˜šœžœ2žœ ž˜SJšœ'žœ žœžœ˜IJšœ˜—Jšžœžœ˜%šžœžœžœ˜Jšœ ˜ Jšœ˜J˜—Jšžœ˜J˜—š¡œžœ˜Jšž˜šŸ œ ,œ˜Nšž˜Jšžœžœžœ ˜J—Jšœžœ( ˜Ešžœžœžœ˜Jšœžœ"˜)šžœžœžœžœ˜"Jšžœ4˜7JšžœF˜I—šžœ˜Jšœžœ˜šœ™JšœL™LJšœI™IJšœE™EJšœ8™8—šžœžœžœ˜Jšœ˜J˜—J˜—Jšžœžœžœž˜%Jšœ˜—Jšžœ žœ˜Jšžœ˜—Jšžœ3˜:šžœ  ˜ Jšœ˜Jšœ*˜*Jšžœžœ(˜=Jšžœ˜—Jšžœ˜J˜—Jšœ žœ˜šŸœ! 'œ˜[Jšž˜JšœI˜IJšžœ˜—J˜JšœN˜NJšœM˜MJ˜CJšœ6˜6Jšžœžœ˜6Jšžœ˜J˜J˜—…—¶0è