<> <> <> DIRECTORY AMEvents USING [Debugged, Debugging], Atom USING [DottedPairNode, PropList], CedarProcess USING [ForkableProc, ForkOptions, Priority, Process, ProcessList, ProcessRep, Status], Loader USING [MakeGlobalFrameResident, MakeProcedureResident], Process USING [CheckForAbort, Detach, GetCurrent, GetPriority, Priority, SetPriority], ProcessProps USING [GetPropList, PushPropList]; CedarProcessImpl: CEDAR MONITOR IMPORTS AMEvents, Loader, 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 ! AMEvents.Debugging => AdjustDebugCount[new, 1]; AMEvents.Debugged => 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; }; <> Loader.MakeGlobalFrameResident[SetPriority]; Loader.MakeProcedureResident[SetPriority]; Loader.MakeProcedureResident[GetPriority]; }. <<>> <> <<>> <> <> <> <> <<>> <> <> < AdjustDebugCount[new, -1];>> < AdjustDebugCount[new, -1];>> <<>> <<>> <<>>