-- MMProcess.Mesa Edited by Sandman on May 18, 1979 10:17 AM -- Edited by Forrest on July 15, 1980 2:48 PM -- Last modified October 18, 1983 4:36 PM by Taft DIRECTORY ControlDefs USING [ Frame, FrameHandle, NullFrame, StateVector], FrameOps USING [Free, MyLocalFrame, SetReturnFrame], InlineDefs USING [HighHalf, LowHalf], MMInit, ProcessDefs USING [ DefaultTimeout, DisableInterrupts, EnableInterrupts, Priority, Ticks], ProcessOps USING [ Broadcast, Clean, CurrentPSB, EnableAndRequeue, Enter, Exit, FirstProcess, LastProcess, Notify, NullQueueHandle, ReadyList, ReEnter, TimerGrain, Wait], PSBDefs USING [ Condition, Empty, MonitorLock, ProcessHandle, PSB, UnlockedEmpty]; MMProcess: MONITOR LOCKS Processes IMPORTS FrameOps, InlineDefs, ProcessDefs, ProcessOps EXPORTS MMInit, ProcessDefs, ProcessOps = BEGIN OPEN ProcessDefs, ProcessOps, PSBDefs; PSBBase: CARDINAL = 0; TimedOut: PUBLIC SIGNAL = CODE; TooManyProcesses: PUBLIC ERROR = CODE; Processes: MONITORLOCK; frameReady, frameTaken, dead, rebirth: PUBLIC CONDITION; DyingFrameHandle: TYPE = POINTER TO dying ControlDefs.Frame; Fork: PUBLIC PROCEDURE [root: UNSPECIFIED] RETURNS [ProcessHandle] = BEGIN sv: ControlDefs.StateVector; self: ControlDefs.FrameHandle; Forker: PROCEDURE [ProcessHandle]; newPSB: ProcessHandle; sv _ STATE; WHILE ~Enter[@Processes] DO NULL ENDLOOP; self _ FrameOps.MyLocalFrame[]; Forker _ LOOPHOLE[self.returnlink]; IF LOOPHOLE[rebirth, Condition].queue = Empty THEN BEGIN Exit[@Processes]; ERROR TooManyProcesses; END; newPSB _ (PSBBase+LOOPHOLE[rebirth, Condition].queue).link; newPSB^ _ PSB[ link: newPSB.link, cleanup: Clean, timeout: 0, priority: CurrentPSB.priority, enterFailed: FALSE, detached: FALSE, fill:0, state: dead, -- in case of timeout before Notify (below) timeoutAllowed: TRUE, abortPending: FALSE, timeoutPending: FALSE, waitingOnCV: TRUE, frame: self]; Notify[@rebirth]; -- wake up newPSB, and set alive; DEPENDS newPSB.state _ alive; -- on new process not preempting parent... FrameOps.SetReturnFrame[ControlDefs.NullFrame]; Forker[newPSB]; -- "returns" handle to site of FORK -- Note that the lines above are executed by the forking process, while -- the lines below are executed by the forked process. Note also that the -- monitor remains LOCKED during this fancy footwork...! sv.dest _ root; sv.source _ End; Exit[@Processes]; RETURN WITH sv END; deadFrame: DyingFrameHandle _ NIL; -- only for detached processes End: PROCEDURE = BEGIN OPEN p: CurrentPSB^; sv: ControlDefs.StateVector; frame: DyingFrameHandle; sv _ STATE; WHILE ~Enter[@Processes] DO NULL ENDLOOP; frame _ LOOPHOLE[FrameOps.MyLocalFrame[]]; frame.state _ alive; p.state _ frameReady; p.abortPending _ FALSE; -- too late for Aborts: they no-op Broadcast[@frameReady]; UNTIL p.state = frameTaken OR p.detached DO Wait[@Processes, @frameTaken, LOOPHOLE[frameTaken, Condition].timeout]; WHILE ~ReEnter[@Processes, @frameTaken] DO NULL ENDLOOP; ENDLOOP; IF deadFrame # NIL THEN BEGIN FrameOps.Free[deadFrame]; deadFrame _ NIL END; IF p.detached THEN deadFrame _ frame; -- Leave our frame for freeing frame.state _ dead; p.state _ dead; Broadcast[@dead]; Wait[@Processes, @rebirth, LOOPHOLE[rebirth, Condition].timeout]; WHILE ~ReEnter[@Processes, @rebirth] DO NULL ENDLOOP; -- dying process exits here; JOINing process does below. sv.dest _ frame.returnlink; -- set to site of JOIN by Join sv.source _ 0; Exit[@Processes]; RETURN WITH sv; END; Join: PUBLIC ENTRY PROCEDURE [process: UNSPECIFIED] RETURNS [ControlDefs.FrameHandle] = BEGIN p: ProcessHandle = process; frame: DyingFrameHandle; self: ControlDefs.FrameHandle = FrameOps.MyLocalFrame[]; ValidateProcess[p]; WHILE p.state # frameReady DO WAIT frameReady ENDLOOP; -- guaranteed to be a dying frame by the time we get here frame _ LOOPHOLE[p.frame]; p.state _ frameTaken; BROADCAST frameTaken; WHILE frame.state # dead DO WAIT dead ENDLOOP; frame.returnlink _ self.returnlink; -- site of JOIN RETURN[frame] END; Detach: PUBLIC ENTRY PROCEDURE [process: UNSPECIFIED] = BEGIN p: ProcessHandle = process; ValidateProcess[p]; p.detached _ TRUE; BROADCAST frameTaken; END; Abort: PUBLIC PROCEDURE [process: UNSPECIFIED] = BEGIN p: ProcessHandle = process; ValidateProcess[p]; DisableInterrupts[]; IF p.state = alive THEN BEGIN p.abortPending _ TRUE; IF p.waitingOnCV THEN BEGIN p.waitingOnCV _ FALSE; EnableAndRequeue[NullQueueHandle, ReadyList, p]; RETURN; END; END; EnableInterrupts[]; END; ProcessTrap: PUBLIC PROCEDURE RETURNS [BOOLEAN] = BEGIN abort: BOOLEAN; CurrentPSB.waitingOnCV _ FALSE; abort _ CurrentPSB.abortPending; CurrentPSB.abortPending _ FALSE; ERROR ABORTED; END; Pause: PUBLIC ENTRY PROCEDURE [ticks: Ticks] = BEGIN condition: CONDITION; SetTimeout[@condition, ticks]; WAIT condition; END; Yield: PUBLIC PROCEDURE = BEGIN DisableInterrupts[]; EnableAndRequeue[ReadyList, ReadyList, CurrentPSB^]; RETURN END; GetCurrent: PUBLIC PROCEDURE RETURNS [UNSPECIFIED] = BEGIN RETURN[CurrentPSB^] END; GetPriority: PUBLIC PROCEDURE RETURNS [p: Priority] = BEGIN DisableInterrupts[]; p _ CurrentPSB.priority; EnableInterrupts[]; RETURN END; SetPriority: PUBLIC PROCEDURE [p: Priority] = BEGIN DisableInterrupts[]; CurrentPSB.priority _ p; EnableAndRequeue[ReadyList, ReadyList, CurrentPSB^]; END; SetTimeout: PUBLIC PROCEDURE [ condition: POINTER TO CONDITION, ticks: CARDINAL] = BEGIN LOOPHOLE[condition, POINTER TO Condition].timeout _ IF ticks # 0 THEN ticks ELSE DefaultTimeout; RETURN END; DisableTimeout: PUBLIC PROCEDURE [condition: POINTER TO CONDITION] = BEGIN LOOPHOLE[condition, POINTER TO Condition].timeout _ 0; RETURN END; SecondsToTicks: PUBLIC PROCEDURE [sec: CARDINAL] RETURNS [Ticks] = BEGIN OPEN InlineDefs; ticks: LONG INTEGER; ticks _ (LONG[sec]*LONG[1000]+TimerGrain-1)/TimerGrain; RETURN[IF HighHalf[ticks] # 0 THEN LAST[Ticks] ELSE LowHalf[ticks]]; END; MsecToTicks: PUBLIC PROCEDURE [ms: CARDINAL] RETURNS [Ticks] = BEGIN RETURN[(ms+TimerGrain-1)/TimerGrain] END; TicksToMsec: PUBLIC PROCEDURE [ticks: Ticks] RETURNS [CARDINAL] = BEGIN RETURN[ticks*TimerGrain] END; InitializeMonitor: PUBLIC PROCEDURE [monitor: POINTER TO MONITORLOCK] = BEGIN LOOPHOLE[monitor, POINTER TO MonitorLock]^ _ UnlockedEmpty; RETURN END; InitializeCondition: PUBLIC PROCEDURE [ condition: POINTER TO CONDITION, ticks: CARDINAL] = BEGIN LOOPHOLE[condition, POINTER TO Condition]^ _ Condition[no, Empty, ticks]; RETURN END; ValidateProcess: PUBLIC PROCEDURE [p: ProcessHandle] = BEGIN c: CARDINAL = LOOPHOLE[p]; IF c < LOOPHOLE[FirstProcess^, CARDINAL] OR c > LOOPHOLE[LastProcess^, CARDINAL] OR (c - LOOPHOLE[FirstProcess^, CARDINAL]) MOD SIZE[PSB] # 0 THEN SIGNAL InvalidProcess[p]; RETURN END; InvalidProcess: PUBLIC SIGNAL [process: ProcessHandle] = CODE; END.