DIRECTORY Atom USING [DottedPairNode, PropList], CedarProcess USING [ForkableProc, ForkOptions, Priority, Process, ProcessList, ProcessRep, Status], Process USING [CheckForAbort, Detach, GetCurrent, GetPriority, Priority, SetPriority], ProcessProps USING [GetPropList, PushPropList]; CedarProcessImpl: CEDAR MONITOR IMPORTS Process, ProcessProps EXPORTS CedarProcess = { ForkableProc: TYPE = CedarProcess.ForkableProc; ForkOptions: TYPE = CedarProcess.ForkOptions; Priority: TYPE = CedarProcess.Priority; ProcessRef: TYPE = CedarProcess.Process; ProcessList: TYPE = CedarProcess.ProcessList; Status: TYPE = CedarProcess.Status; busyList: CedarProcess.ProcessList ¬ NIL; busyCount: INT ¬ 0; statusChange: CONDITION; SetPriority: PUBLIC PROC [priority: Priority] = { Process.SetPriority[LOOPHOLE[priority]]; }; GetPriority: PUBLIC PROC RETURNS [priority: Priority] = { RETURN [LOOPHOLE[Process.GetPriority[]]]; }; DoWithPriority: PUBLIC PROC [priority: Priority, action: PROC] = { old: Priority ¬ GetPriority[]; SetPriority[priority]; action[ ! UNWIND => SetPriority[old]]; SetPriority[old]; }; Fork: PUBLIC PROC [action: ForkableProc, data: REF ¬ NIL, options: ForkOptions] RETURNS [ProcessRef] = TRUSTED { new: ProcessRef ¬ NEW[CedarProcess.ProcessRep ¬ [action: action, data: data]]; props: Atom.PropList ¬ ProcessProps.GetPropList[]; Process.Detach[FORK CedarProcessBase[new, props, options]]; WaitForStarted[new]; RETURN [new]; }; GetStatus: PUBLIC ENTRY PROC [process: ProcessRef] RETURNS [Status] = { IF (process ¬ DefaultMe[process]) = NIL THEN RETURN [invalid]; RETURN [process.status]; }; Join: PUBLIC ENTRY PROC [process: ProcessRef, wait: BOOL ¬ TRUE] RETURNS [status: Status, results: REF] = { IF process # NIL THEN { IF wait THEN DO SELECT process.status FROM busy, debugging => WAIT statusChange; ENDCASE => EXIT; ENDLOOP; RETURN [process.status, process.results]; }; RETURN [done, NIL]; }; Abort: PUBLIC ENTRY PROC [process: ProcessRef] = { IF process # NIL THEN { process.abortCount ¬ process.abortCount + 1; process.abortRequested ¬ TRUE; }; }; CheckAbort: PUBLIC PROC [process: ProcessRef] = { Process.CheckForAbort[]; CheckAbortEntry[process]; }; GetBusyList: PUBLIC ENTRY PROC RETURNS [head: ProcessList ¬ NIL] = { FOR each: ProcessList ¬ busyList, each.rest WHILE each # NIL DO SELECT each.first.status FROM busy, debugging => head ¬ CONS[each.first, head]; ENDCASE; ENDLOOP; }; GetBusyCount: PUBLIC ENTRY PROC RETURNS [INT] = { RETURN [busyCount]; }; CheckAbortEntry: ENTRY PROC [process: ProcessRef] = { IF (process ¬ DefaultMe[process]) # NIL AND process.abortRequested THEN { process.abortRequested ¬ FALSE; RETURN WITH ERROR ABORTED; }; }; DefaultMe: INTERNAL PROC [process: ProcessRef] RETURNS [ProcessRef] = TRUSTED { IF process = NIL THEN { me: PROCESS ¬ LOOPHOLE[Process.GetCurrent[]]; FOR each: ProcessList ¬ busyList, each.rest WHILE each # NIL DO process ¬ each.first; IF process.process = me THEN RETURN [process]; ENDLOOP; RETURN [NIL]; }; RETURN [process]; }; WaitForStarted: ENTRY PROC [process: ProcessRef] = { WHILE process.process = NIL DO WAIT statusChange; ENDLOOP; }; AdjustDebugCount: ENTRY PROC [process: ProcessRef, delta: INT] = { process.debugCount ¬ process.debugCount + delta; }; CedarProcessBase: PROC [new: ProcessRef, props: Atom.PropList, options: ForkOptions] = { innerProcessBase: PROC = TRUSTED { me: PROCESS ¬ LOOPHOLE[Process.GetCurrent[]]; AddToBusyList[new]; new.results ¬ new.action[new.data ! ABORTED => GO TO abort; ]; RemFromBusyList[new, done]; EXITS abort => RemFromBusyList[new, aborted]; }; IF options.usePriority THEN Process.SetPriority[LOOPHOLE[options.priority]]; IF NOT options.inheritProperties THEN props ¬ NIL; props ¬ CONS[NEW[Atom.DottedPairNode ¬ [$CedarProcess, new]], props]; ProcessProps.PushPropList[props, innerProcessBase]; }; AddToBusyList: ENTRY PROC [process: ProcessRef] = TRUSTED { busyList ¬ CONS[process, busyList]; process.process ¬ LOOPHOLE[Process.GetCurrent[]]; busyCount ¬ busyCount + 1; BROADCAST statusChange; }; RemFromBusyList: ENTRY PROC [process: ProcessRef, status: Status] = { SELECT TRUE FROM busyList = NIL => {}; busyList.first = process => { busyCount ¬ busyCount - 1; busyList ¬ busyList.rest; }; ENDCASE => { lag: ProcessList ¬ busyList; DO next: ProcessList ¬ lag.rest; IF next = NIL THEN EXIT; IF next.first.process = process.process THEN { busyCount ¬ busyCount - 1; lag.rest ¬ next.rest; EXIT; }; lag ¬ next; ENDLOOP; }; process.status ¬ status; BROADCAST statusChange; }; }. 8 CedarProcessImpl.mesa Copyright Σ 1985, 1986, 1987, 1990, 1991 by Xerox Corporation. All rights reserved. Russ Atkinson (RRA) January 19, 1987 7:03:28 pm PST Michael Plass, September 14, 1990 11:30 am PDT AMEvents USING [Debugged, Debugging], Loader USING [MakeGlobalFrameResident, MakeProcedureResident], Global vars Operations for the current process Sets the priority of the current process to the given priority Gets the priority of the current process Performs the action using the given priority. After the action completes the priority reverts to the priority before the call. Operations for forked processes Forks the action with the given callback data and the given options. Note that the action must NOT be a nested procedure. Monitored access to process.status. wait = TRUE AND (process.status = debugging OR process.status = busy) => wait for (process.status = done OR process.status = aborted) In all other cases, return the current results and status. a monitored call to make process.abortRequested = TRUE increments process.abortCount a monitored call to make process.abortRequested = TRUE raises ERROR ABORTED if process.abortRequested was TRUE when called Operations for all busy forked processes Returns a copy of the current busy list of processes. Returns the number of processes forked through this interface that currently have status = busy or status = debugging. Utilities AMEvents.Debugging => AdjustDebugCount[new, 1]; AMEvents.Debugged => AdjustDebugCount[new, -1]; Temporary Loader.MakeGlobalFrameResident[SetPriority]; Loader.MakeProcedureResident[SetPriority]; Loader.MakeProcedureResident[GetPriority]; CHANGE LOG Russ Atkinson (RRA) August 19, 1985 2:35:11 pm PDT in CedarProcessBase old: IF options.inheritProperties THEN props _ NIL; new: IF NOT options.inheritProperties THEN props _ NIL; Russ Atkinson (RRA) August 19, 1985 10:12:26 pm PDT in CedarProcessBase - old: AMEvents.Debugging => AdjustDebugCount[new, -1]; new: AMEvents.Debugged => AdjustDebugCount[new, -1]; Michael Plass, September 14, 1990 Removed references to AMEvents and Loader. Κκ–(cedarcode) style•NewlineDelimiter ™codešœ™Kšœ ΟeœI™TK™3K™.—˜šΟk ˜ Kšœ žœ™%Kšœžœ˜&Kšœ žœQ˜cKšœžœ2™>KšœžœI˜VKšœ žœ˜/K˜——šΟnœžœž˜Kšžœ˜Kšžœ˜K˜Kšœžœ˜/Kšœ žœ˜-Kšœ žœ˜'Kšœ žœ˜(Kšœ žœ˜-Kšœžœ˜#K˜—™ K˜Kšœ%žœ˜)Kšœ žœ˜šœž œ˜K˜——šœ"™"K˜šŸ œžœžœ˜1Kšœ>™>Kšœžœ ˜(K˜K˜—šŸ œžœžœžœ˜9Kšœ(™(Kšžœžœ˜)K˜K™—šŸœžœžœžœ˜BKšœ™Kšœ˜Kšœ˜Kšœ žœ˜&Kšœ˜K˜K™——™K˜šŸœžœžœžœžœžœžœ˜pKšœ`žœ™zKšœžœ9˜NKšœ2˜2Kšœžœ(˜;Kšœ˜Kšžœ˜ K˜K˜—š Ÿ œžœžœžœžœ ˜GKšœ#™#Kšžœ"žœžœžœ ˜>Kšžœ˜K˜K™—šŸœžœž œžœžœžœžœ˜kšœžœžœžœ™HKšœ<™<—K™:šžœ žœžœ˜šžœžœž˜šžœž˜Kšœžœ˜%Kšžœžœ˜—Kšžœ˜—Kšžœ#˜)K˜—Kšžœžœ˜K˜—K˜šŸœžœž œ˜2Kšœ2ž™6Kšœ™šžœ žœžœ˜Kšœ,˜,Kšœžœ˜K˜—K˜K˜—šŸ œžœžœ˜1Kšœ2ž™6Kšœžœžœžœ ™CKšœ˜Kšœ˜K˜K˜——™(K˜š Ÿ œžœžœžœžœžœ˜DKšœ5™5šžœ)žœžœž˜?šžœž˜Kšœžœ˜1Kšžœ˜—Kšžœ˜—K˜—K˜š Ÿ œžœžœžœžœžœ˜1Kšœv™vKšžœ ˜K˜K˜——K™ ™šŸœžœžœ˜5šžœ"žœžœ˜IKšœžœ˜Kšžœžœžœžœ˜K˜—K˜K˜—š Ÿ œžœžœžœžœ˜Ošžœ žœžœ˜Kšœžœžœ˜-šžœ)žœžœž˜?Kšœ˜Kšžœžœžœ ˜.Kšžœ˜—Kšžœžœ˜ K˜—Kšžœ ˜K˜K˜—šŸœžœžœ˜4Kš žœžœžœžœžœ˜:K˜K˜—šŸœžœžœžœ˜BKšœ0˜0K˜K˜—šŸœžœB˜Xšœžœžœ˜"Kšœžœžœ˜-K˜˜!˜K™/K™/Kšžœžœžœ˜—K˜—Kšœ˜Kšžœ(˜-K˜—Kšžœžœžœ˜LKšžœžœžœ žœ˜2Kšœžœžœ5˜EKšœ3˜3K˜K™—šŸ œžœžœžœ˜;Kšœ žœ˜#Kšœžœ˜1K˜Kšž œ˜K˜K˜—šŸœžœžœ*˜Ešžœžœž˜Kšœ žœ˜šœ˜K˜Kšœ˜K˜—šžœ˜ Kšœ˜šž˜Kšœ˜Kšžœžœžœžœ˜šžœ&žœ˜.K˜K˜Kšžœ˜K˜—K˜ Kšžœ˜—K˜——Kšœ˜Kšž œ˜K˜——K˜šœ ™ K˜Kšœ,™,Kšœ*™*Kšœ*™*K˜—K˜K™™ K™—™2šœ™Kšœžœžœ žœ™3Kš œžœžœžœ žœ™7—K™—™3Kšœ™Kšœ5™5Kšœ4™4—K™™!Kšœ*™*—K™—…—€!Ζ