CedarProcessImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Russ Atkinson (RRA) August 19, 1985 10:14:50 pm PDT
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;
Operations for the current process
SetPriority: PUBLIC PROC [priority: Priority] = {
Sets the priority of the current process to the given priority
Process.SetPriority[LOOPHOLE[priority]];
};
GetPriority: PUBLIC PROC RETURNS [priority: Priority] = {
Gets the priority of the current process
RETURN [LOOPHOLE[Process.GetPriority[]]];
};
DoWithPriority: PUBLIC PROC [priority: Priority, action: PROC] = {
Performs the action using the given priority. After the action completes the priority reverts to the priority before the call.
old: Priority ← GetPriority[];
SetPriority[priority];
action[ ! UNWIND => SetPriority[old]];
SetPriority[old];
};
Operations for forked processes
Fork: PUBLIC PROC [action: ForkableProc, data: REFNIL, options: ForkOptions] RETURNS [ProcessRef] = TRUSTED {
Forks the action with the given callback data and the given options. Note that the action must NOT be a nested procedure.
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] = {
Monitored access to process.status.
IF (process ← DefaultMe[process]) = NIL THEN RETURN [invalid];
RETURN [process.status];
};
Join: PUBLIC ENTRY PROC [process: ProcessRef, wait: BOOLTRUE] RETURNS [status: Status, results: REF] = {
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.
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] = {
a monitored call to make process.abortRequested = TRUE
increments process.abortCount
IF process # NIL THEN {
process.abortCount ← process.abortCount + 1;
process.abortRequested ← TRUE;
};
};
CheckAbort: PUBLIC PROC [process: ProcessRef] = {
a monitored call to make process.abortRequested = TRUE
raises ERROR ABORTED if process.abortRequested was TRUE when called
Process.CheckForAbort[];
CheckAbortEntry[process];
};
Operations for all busy forked processes
GetBusyList: PUBLIC ENTRY PROC RETURNS [head: ProcessList ← NIL] = {
Returns a copy of the current busy list of processes.
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] = {
Returns the number of processes forked through this interface that currently have status = busy or status = debugging.
RETURN [busyCount];
};
Utilities
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: PROCESSLOOPHOLE[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: PROCESSLOOPHOLE[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;
};
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];