<<>> <> <> <> <> 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 ! < AdjustDebugCount[new, 1];>> < AdjustDebugCount[new, -1];>> 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; }; <> <> <> <> }. <<>> <> <<>> <> <> <> <> <<>> <> <> < AdjustDebugCount[new, -1];>> < AdjustDebugCount[new, -1];>> <<>> <> <> <<>>