DIRECTORY Atom, BasicTime, CedarProcess, CD, CDEnvironment USING [ExecFileEntry], CDEvents USING [EventProc, RegisterEventProc, ProcessEvent, EventRegistration, RegisterEventType], CDIO, CDOps USING [DoTheDelayedRedraws], CDPrivate, CDProperties, CDSequencer, IO, MBQueue USING [Queue, Create, QueueClientAction, Flush], MessageWindow, PopUpSelection, Process, RefTab, Rope, RuntimeError USING [UNCAUGHT], TerminalIO, TokenIO, UserProfile; CDSequencerImpl: CEDAR MONITOR IMPORTS Atom, BasicTime, CedarProcess, CD, CDEvents, CDEnvironment, CDIO, CDOps, CDPrivate, CDProperties, IO, MBQueue, MessageWindow, PopUpSelection, Process, RefTab, Rope, RuntimeError, TerminalIO, TokenIO, UserProfile EXPORTS CDSequencer, CD = BEGIN Message: PROC [r: Rope.ROPE] = { MessageWindow.Append[r, TRUE]; MessageWindow.Blink[]; }; ErrorChangeReadOnlyDesign: PROC [d: CD.Design_NIL] = TRUSTED { Process.Detach[FORK Message[Rope.Cat["design """, IF d=NIL THEN "" ELSE d.name, """ readonly"]] ]; ERROR CD.Error[designMutability]; }; Command: TYPE = CDSequencer.Command; CommandProc: TYPE = CDSequencer.CommandProc; QueueMethod: TYPE = CDSequencer.QueueMethod; PrivateSequencerDRep: PUBLIC TYPE = RECORD [ queue: MBQueue.Queue, whileCommand: INT_0, --modifyed by monitored procedures inside single call proc whileOutput: BOOL_FALSE, --Set monitored, cleared by one single output process stopWrite: REF BOOL, abort: BOOL_FALSE, abortFlags: LIST OF REF BOOL_NIL, notInit: BOOL_TRUE, lastCommand: BasicTime.GMT, lastOutput: BasicTime.GMT, num: INT_0 ]; PrivateSequencerTRep: PUBLIC TYPE = RECORD [ commandTab: RefTab.Ref ]; Registration: TYPE = REF RegistrationRec; RegistrationRec: TYPE = RECORD [p: CommandProc, qm: QueueMethod, registrationData: REF_NIL]; InternalRec: TYPE = RECORD [comm: Command, qm: QueueMethod, proc: CommandProc]; globalTab: 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; now: BasicTime.GMT _ BasicTime.Now[]; --lags behind savePeriod: INT _ 0; reCheck: CONDITION _ [timeout: Process.MsecToTicks[1000]]; EnterCommand: ENTRY PROC [x: REF PrivateSequencerDRep] = INLINE { ENABLE UNWIND => NULL; x.whileCommand _ x.whileCommand+1; }; LeaveCommand: ENTRY PROC [x: REF PrivateSequencerDRep] = INLINE { ENABLE UNWIND => NULL; x.whileCommand _ x.whileCommand-1; }; EnterOutput: ENTRY PROC [x: REF PrivateSequencerDRep] RETURNS [enter: BOOL_FALSE] = { ENABLE UNWIND => NULL; IF enter_(x.whileCommand=0) THEN { IF x.stopWrite=NIL THEN x.stopWrite_NEW[BOOL]; x.stopWrite^ _ FALSE; x.whileOutput _ TRUE } }; DesignRegistrationEvent: CDEvents.EventProc = { data: REF PrivateSequencerDRep _ NEW[PrivateSequencerDRep_[ queue: MBQueue.Create[], stopWrite: NEW[BOOL_FALSE], lastCommand: now, lastOutput: now, num: designNumber ]]; designNumber _ designNumber+1; design.cdSequencerPriv _ data; design.cdSequencerPriv.notInit _ FALSE; }; TechRegistrationEvent: CDEvents.EventProc = { tech: CD.Technology = NARROW[x]; tech.cdSequencerPriv _ NEW[PrivateSequencerTRep _ [commandTab: RefTab.Create[mod: 41]]] }; UnKnownCommand: PROC [comm: CDSequencer.Command] = { key: ATOM _ IF comm.key#NIL THEN comm.key ELSE $NIL; r: Rope.ROPE _ IO.PutFR["command %g not known", [atom[key]]]; Message[r]; TerminalIO.PutRopes[r, "\n"]; }; TriedChangingReadonlyDesignCommand: PROC [comm: CDSequencer.Command] = { key: ATOM _ IF comm.key#NIL THEN comm.key ELSE $NIL; TerminalIO.PutF["command %g tries to change design ""%g"", but design is readonly\n", [atom[key]], [rope[CD.DesignName[comm.design]]] ]; }; WriteMsg: PROC [r: Rope.ROPE] = { IF Rope.Length[r]>0 THEN { IF Rope.Fetch[r, Rope.Length[r]-1]#'\n THEN r _ Rope.Concat[r, "\n"]; TerminalIO.PutRope[r]; }; }; InternalExec: PROC [ref: REF ANY] = { --type good for MBQueue.QueueClientAction ENABLE { ABORTED => {WriteMsg["** ABORTED"]; GOTO Oops}; quit => {WriteMsg[msg]; GOTO Oops}; CD.Error => IF ec=designMutability THEN { WriteMsg["** aborted try to change readonly design"]; GOTO Oops }; TerminalIO.UserAbort => {WriteMsg["** aborted interactive input"]; GOTO Oops}; }; ic: REF InternalRec = NARROW[ref]; IF ic.qm=dontQueue THEN ic.proc[ic.comm ! RuntimeError.UNCAUGHT => IF ShouldDebug[LOOPHOLE[signal]] THEN REJECT ELSE CONTINUE ] ELSE { de: REF PrivateSequencerDRep = ic.comm.design.cdSequencerPriv; Protected: PROC [de: REF PrivateSequencerDRep] ~ { ENABLE UNWIND => LeaveCommand[de]; WHILE de.whileOutput DO stop: REF BOOL _ de.stopWrite; IF stop#NIL THEN stop^ _ TRUE; IF de.whileOutput THEN Process.Pause[1] ENDLOOP; de.lastCommand _ now; IF ic.qm=doQueueAndMark THEN { IF ~ic.comm.design.changedSinceSaving OR ~ic.comm.design.actual.first.specific.changed THEN MarkChanged[ic.comm.design ! CD.Error => IF ec=designMutability THEN { ic.proc _ TriedChangingReadonlyDesignCommand; CONTINUE; }; ]; }; IF Process.GetPriority[]>Process.priorityNormal THEN CedarProcess.SetPriority[CedarProcess.Priority[normal]]; de.abort _ FALSE; ic.proc[ic.comm ! RuntimeError.UNCAUGHT => IF ShouldDebug[LOOPHOLE[signal]] THEN REJECT ELSE CONTINUE ]; de.abortFlags _ NIL; LeaveCommand[de] };--END Protected IF de=NIL THEN ERROR CD.Error[programming]; EnterCommand[de]; Protected[de]; }; CDOps.DoTheDelayedRedraws[ic.comm.design]; EXITS Oops => NULL }; ShouldDebug: PROC [signal: SIGNAL ANY RETURNS ANY] RETURNS [debug: BOOL_TRUE] = { WITH CDProperties.GetAtomProp[$CDDebugPrivate, $CDDebugPrivate] SELECT FROM rs: REF SIGNAL ANY RETURNS ANY => IF signal=rs^ THEN RETURN [TRUE]; ENDCASE => NULL; IF UserProfile.Boolean["ChipNDale.OpenEventViewers", FALSE] THEN RETURN [TRUE]; DO SELECT PopUpSelection.Request[ header: "ERROR", choice: LIST["continue with ChipNDale", "debug"], headerDoc: "error while executing ChipNDale command", choiceDoc: LIST["usually ok", "land in debugger (abort will continue ChipNDale)"] ] FROM 1 => RETURN [FALSE]; 2 => RETURN [TRUE]; ENDCASE => NULL; TerminalIO.PutRope["don't skip this!\n"]; ENDLOOP }; Quit: PUBLIC PROC [message: Rope.ROPE] = { ERROR quit[message] }; ImplementCommand: PUBLIC ENTRY PROC [key: ATOM, proc: CommandProc, technology: CD.Technology, queue: QueueMethod, registrationData: REF_NIL] = { ENABLE UNWIND => NULL; table: RefTab.Ref _ globalTab; IF technology#NIL THEN table _ technology.cdSequencerPriv.commandTab; [] _ RefTab.Store[table, key, NEW[RegistrationRec _ [p: proc, qm: queue, registrationData: registrationData]]]; }; FetchCommand: PUBLIC PROC[key: ATOM, technology: CD.Technology, load: BOOL_TRUE] RETURNS [proc: CommandProc_NIL, qm: QueueMethod_dontQueue, registrationData: REF_NIL] = { FetchRegistration: PROC[key: ATOM, technology: CD.Technology] RETURNS [cd: Registration] = INLINE { IF technology#NIL THEN { -- search first for particular technology cTab: REF PrivateSequencerTRep = technology.cdSequencerPriv; val: RefTab.Val _ RefTab.Fetch[cTab.commandTab, key].val; IF val#NIL THEN RETURN [NARROW[val]]; }; RETURN [NARROW[RefTab.Fetch[globalTab, key].val]]; }; cd: Registration _ FetchRegistration[key, technology]; IF cd=NIL AND load THEN { CDEnvironment.ExecFileEntry[Atom.GetPName[key], technology, "cmds", FALSE, FALSE ! ABORTED => CONTINUE; RuntimeError.UNCAUGHT => SELECT PopUpSelection.Request[ header: "ERROR", choice: LIST["continue with ChipNDale", "debug"], headerDoc: "error while executing command file", choiceDoc: LIST["usually ok", "land in debugger (abort will continue ChipNDale)"] ] FROM 1 => CONTINUE; 2 => REJECT; ENDCASE => CONTINUE; ]; cd _ FetchRegistration[key, technology]; }; IF cd#NIL THEN {proc_cd.p; qm_cd.qm; registrationData_cd.registrationData}; }; Call: PROC [ic: REF InternalRec] = INLINE { IF ic.qm=dontQueue THEN InternalExec[ic] ELSE { WHILE ic.comm.design.cdSequencerPriv.notInit DO WaitInitialization[ic.comm.design.cdSequencerPriv] ENDLOOP; MBQueue.QueueClientAction[ic.comm.design.cdSequencerPriv.queue, InternalExec, ic] } }; ExecuteProc: PUBLIC PROC [proc: CommandProc, design: CD.Design, queue: QueueMethod, comm: CDSequencer.Command] = { ic: REF InternalRec _ NEW[InternalRec_[ comm: NEW[CDSequencer.CommandRec], proc: IF proc=NIL THEN UnKnownCommand ELSE proc, qm: queue ]]; IF comm#NIL THEN ic.comm^ _ comm^; IF design#NIL THEN ic.comm.design _ design; Call[ic] }; ExecuteCommand: PUBLIC PROC [key: ATOM, design: CD.Design, queue: QueueMethod, comm: CDSequencer.Command] = { ic: REF InternalRec _ NEW[InternalRec_[ comm: NEW[CDSequencer.CommandRec], proc: NIL, qm: useDefault ]]; IF comm#NIL THEN ic.comm^ _ comm^; IF key#NIL THEN ic.comm.key _ key; IF design#NIL THEN ic.comm.design _ design; [proc: ic.proc, qm: ic.qm] _ FetchCommand[ic.comm.key, ic.comm.design.technology, TRUE]; IF ic.proc=NIL THEN { ic.proc _ UnKnownCommand; ic.qm _ dontQueue; }; IF queue#useDefault THEN ic.qm _ queue; Call[ic] }; RecheckEdited: PROC [design: CD.Design] = { [] _ CDEvents.ProcessEvent[recheckEditedRequest, design]; }; SetEdited: PUBLIC PROC [design: CD.Design, edited: BOOL] = { was: BOOL _ design.edited; IF edited THEN IF design.mutability#editable THEN ErrorChangeReadOnlyDesign[design]; design.edited _ edited; IF was#edited THEN RecheckEdited[design]; }; MarkChangedIOOnly: PUBLIC PROC [design: CD.Design] = { IF ~design.actual.first.specific.changed OR ~design.changedSinceSaving THEN { IF design.mutability#editable THEN ErrorChangeReadOnlyDesign[design]; design.changedSinceSaving _ TRUE; design.edited _ TRUE; TRUSTED {Process.Detach[FORK RecheckEdited[design]]}; } }; MarkChanged: PUBLIC PROC [design: CD.Design] = { IF ~design.actual.first.specific.changed OR ~design.changedSinceSaving THEN { IF design.mutability#editable THEN ErrorChangeReadOnlyDesign[design]; design.actual.first.specific.changed _ TRUE; design.changedSinceSaving _ TRUE; design.edited _ TRUE; TRUSTED {Process.Detach[FORK RecheckEdited[design]]}; } }; WaitInitialization: ENTRY PROC [sPriv: REF PrivateSequencerDRep] = { IF sPriv=NIL OR sPriv.notInit THEN WAIT reCheck }; AbortDesignsCommand: PUBLIC PROC [design: CD.Design, flush: BOOL] = { IF design=NIL THEN [] _ CDEvents.ProcessEvent[abortRequest, NIL] ELSE { de: REF PrivateSequencerDRep = design.cdSequencerPriv; de.abort _ TRUE; FOR bl: LIST OF REF BOOL _ de.abortFlags, bl.rest WHILE bl#NIL DO IF bl.first#NIL THEN bl.first^_TRUE ENDLOOP; [] _ CDEvents.ProcessEvent[abortRequest, design]; IF flush THEN MBQueue.Flush[de.queue]; }; }; Aborted: PUBLIC PROC [design: CD.Design] RETURNS [BOOL] = { RETURN [design.cdSequencerPriv.abort] }; CheckAborted: PUBLIC PROC [design: CD.Design] = { IF design.cdSequencerPriv.abort THEN Quit["command aborted"]; CedarProcess.CheckAbort[NIL]; }; UseAbortFlag: PUBLIC PROC [design: CD.Design, flag: REF BOOL] = { IF design=NIL OR flag=NIL THEN ERROR CD.Error[calling]; design.cdSequencerPriv.abortFlags _ CONS[flag, design.cdSequencerPriv.abortFlags]; }; BackgroundSaveProcess: PROC = { ProtectedSaveOneDesign: PROC [design: CD.Design] = { de: REF PrivateSequencerDRep = design.cdSequencerPriv; done: BOOL _ FALSE; done _ CDIO.WriteDesign[design: design, to: NIL, quiet: TRUE, emergency: FALSE, stop: de.stopWrite ! TokenIO.Stopped, RuntimeError.UNCAUGHT => GOTO oops]; IF done THEN { de.lastOutput _ BasicTime.Now[]; design.changedSinceSaving _ FALSE; } EXITS oops => NULL; }; CheckDesignForSave: CDPrivate.DesignEnumerator = { ENABLE RuntimeError.UNCAUGHT => GOTO oops; --give the next design a chance Process.Pause[1]; -- little bit slower for the benefit of the viewer redraw IF design#NIL THEN { de: REF PrivateSequencerDRep = design.cdSequencerPriv; IF design.changedSinceSaving AND de#NIL AND de.whileCommand=0 AND BasicTime.Period[from: de.lastCommand, to: now]>2 AND BasicTime.Period[from: de.lastOutput, to: de.lastCommand]>savePeriod AND CDProperties.GetDesignProp[design, $CDxDontBackgroundSave]#$TRUE THEN { IF EnterOutput[de] THEN ProtectedSaveOneDesign[design ! RuntimeError.UNCAUGHT => CONTINUE]; de.whileOutput _ FALSE; CedarProcess.SetPriority[CedarProcess.Priority[background]]; --speed no more necessary }; }; EXITS oops => NULL; }; DO -- forever now _ BasicTime.Now[]; Process.Pause[Process.SecondsToTicks[8]]; IF savePeriod>=0 THEN [] _ CDPrivate.EnumDesigns[CheckDesignForSave] ENDLOOP; }; NoteProfileChange: UserProfile.ProfileChangedProc = { savePeriod _ UserProfile.Number[key: "ChipNDale.SavePeriod", default: 0]; }; abortRequest: CDEvents.EventRegistration = CDEvents.RegisterEventType[$Abort]; recheckEditedRequest: CDEvents.EventRegistration = CDEvents.RegisterEventType[$CheckEdited]; CDEvents.RegisterEventProc[$RegisterTechnology, TechRegistrationEvent]; CDEvents.RegisterEventProc[$CreateNewDesign, DesignRegistrationEvent]; UserProfile.CallWhenProfileChanges[NoteProfileChange]; TRUSTED {Process.Detach[FORK BackgroundSaveProcess[]]}; END. ήCDSequencerImpl.mesa (part of ChipNDale) Copyright c 1983, 1986, 1987 by Xerox Corporation. All rights reserved. Created by Christian Jacobi, June 22, 1983 6:02 pm Last edited by: Christian Jacobi, April 2, 1987 2:31:43 pm PST --Message r on Message window --using a RefTab is ok: we approximately know the number of entries --not monitored: is called from inside a command --CedarProcess.SetPriority[CedarProcess.Priority[normal]]; --so stops quickly if necessary Κv˜codešœ*™*Kšœ Οmœ=™HKšœ3™3K™>K˜—šΟk ˜ K˜Kšœ ˜ Kšœ ˜ Kšžœ˜Kšœžœ˜$Kšœ žœT˜bKšœ˜Kšœžœ˜"Kšœ ˜ Kšœ ˜ Kšœ ˜ Kšœ˜Kšœžœ+˜8Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ žœžœ˜Kšœ ˜ Kšœ˜Kšœ ˜ —K˜šΟbœžœžœ˜Kšžœ;žœ žœp˜άKšžœžœ˜—Kšž˜K˜šΟnœžœ žœ˜ K™Kšœžœ˜Kšœ˜K˜—K˜š  œžœžœžœžœ˜>šœžœ˜Kš œžœžœžœžœ˜KKšœ˜—Kšžœžœ˜!Kšœ˜K˜—Kšœ žœ˜$Kšœ žœ˜,Kšœ žœ˜,K˜šœž œžœ˜,Kšœ˜KšœžœΟc:˜OKšœ žœžœ‘5˜NKšœ žœžœ˜Kšœžœžœ˜Kš œ žœžœžœžœžœ˜!Kšœ žœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜ Kšœ˜—K˜šœžœžœžœ˜,K˜K˜—K˜Kšœžœžœ˜)Kšœžœžœ5žœ˜\Kšœ žœžœ5˜OK˜šœ1‘*˜[KšœC™C—Kšœžœ žœžœ‘,˜QKšœžœ˜Kšœžœ‘˜4Kšœ žœ˜K˜Kšœ ž œ(˜:K˜š   œžœžœžœžœ˜AKšžœžœžœ˜Kšœ"˜"K˜—K˜š   œžœžœžœžœ˜AKšžœžœžœ˜Kšœ"˜"K˜—K˜š  œžœžœžœžœ žœžœ˜UKšžœžœžœ˜šžœžœ˜"Kš žœ žœžœ žœžœ˜.Kšœžœ˜Kšœž˜K˜—K˜—K˜šΠbnœ˜/šœžœžœ˜;Kšœ˜Kšœ žœžœžœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšœ˜Kšœ˜Kšœ!žœ˜'Kšœ˜—K˜šŸœ˜-Kšœžœžœ˜ Kšœžœ=˜WKšœ˜—K˜š œžœ ˜4Kš œžœžœ žœžœ žœ˜4Kšœžœžœ,˜=Kšœ ˜ Kšœ˜Kšœ˜—K˜š "œžœ ˜HKš œžœžœ žœžœ žœ˜4šœV˜VKšœ/˜/Kšœ˜—Kšœ˜—K˜š œžœ žœ˜!šžœžœ˜Kšžœ%žœ˜EKšœ˜Kšœ˜—K˜—K˜š   œžœžœžœ‘)˜Ošžœ˜Kšžœžœ˜/Kšœžœ˜#šžœ žœžœ˜)Kšœ6žœ˜?Kšœ˜—KšœCžœ˜NKšœ˜—Kšœžœžœ˜"šžœžœ˜šœžœžœ˜LKšžœžœ˜ Kšžœž˜ Kšœ˜——šžœ˜Kšœžœ7˜>š  œžœžœ˜2Kšžœžœ˜"šžœž˜Kšœžœžœ˜Kšžœžœžœ žœ˜Kšžœžœ˜'Kšžœ˜—Kšœ˜šžœžœ˜šžœ$žœ/žœ˜\šœ˜šœžœ ˜šžœžœ˜Kšœ.žœ˜7K˜——Kšœ˜——Kšœ˜—Kšžœ.žœ9˜mKšœ žœ˜šœžœžœ žœ ˜LKšžœžœ˜ Kšžœž˜ Kšœ˜—Kšœžœ˜Kšœ˜Kšœ‘˜—Kš žœžœžœžœžœ˜+Kšœ˜Kšœ˜Kšœ˜—Kšœ*˜*Kšžœ ž˜Kšœ˜—K˜š  œžœ žœžœžœžœžœ žœžœ˜Qšžœ<žœž˜KKšœžœžœžœžœžœžœ žœžœžœ˜CKšžœžœ˜—Kš žœ3žœžœžœžœ˜Ošž˜šžœ˜Kšœ˜Kšœžœ&˜2Kšœ6˜6Kšœ žœB˜QKšœž˜Kšœžœžœ˜Kšœžœžœ˜Kšžœžœ˜—K˜)Kšž˜—Kšœ˜—K˜š œžœžœžœ˜*Kšžœ˜Kšœ˜—K˜š œžœžœžœžœ!žœ3žœžœ˜Kšžœžœžœ˜Kšœ˜Kšžœ žœžœ/˜EKšœžœN˜oKšœ˜—K˜š  œžœžœžœžœžœžœžœžœ/žœžœ˜ͺK˜š  œžœžœžœ žœžœ˜cšžœ žœžœ‘)˜BKšœžœ3˜