-- Cedar Remote Debugging: processes

-- AMProcessImpl.mesa

-- Andrew Birrell January 27, 1983 3:42 pm
-- Russ Atkinson, January 19, 1983 9:12 pm

DIRECTORY
AMBridge  USING[ GFHFromTV, SetTVFromLC, TVForFrame, TVToCardinal, GetWorld, IsRemote, RemoteGFHFromTV, RemoteGlobalFrameHandle, TVForRemoteFrame ],
AMEventsPrivate USING[ Outcome, ProvokeProcessEvent ],
AMModel  USING[ Context, ContextChildren, ContextClass, ContextWorld ],
AMProcess  USING[ nullProcess, Process, State ],
AMProcessBasic USING[ Abort, GFTable, Info, Thaw ],
AMTypes   USING[ Error, New, TVType, TypeClass ],
Convert   USING[ ValueToRope ],
Environment USING[ bitsPerWord, wordsPerPage ],
PrincOps   USING[ FrameHandle, GFTIndex, GlobalFrame ],
PSB    USING[ PDA, PsbIndex, StartPsb ],
Rope    USING[ Cat, ROPE ],
RTBasic   USING[ TV ],
Space    USING[ Create, Handle, LongPointer, Map, virtualMemory ],
SpecialSpace  USING[ MakeResident, MakeSwappable ],
WorldVM  USING[ Address, CopyRead, CurrentIncarnation, LocalWorld, Long, Read, ShortAddress, World ];

AMProcessImpl: MONITOR
IMPORTS AMBridge, AMEventsPrivate, AMModel, AMProcessBasic, AMTypes, Convert, Rope, SpecialSpace, Space, WorldVM
EXPORTS AMProcess =

BEGIN

Process: TYPE = AMProcess.Process;

nullProcess: Process = AMProcess.nullProcess;

PSBI: TYPE = PSB.PsbIndex;

PSBIToTV: PUBLIC PROC[world: WorldVM.World, psbi: PSB.PsbIndex] RETURNS[p: Process] =
BEGIN
p ← AMTypes.New[CODE[PROCESS], mutable, world];
AMBridge.SetTVFromLC[p, psbi];
END;

TVToPSBI: PUBLIC PROC[p: Process] RETURNS[world: WorldVM.World, psbi: PSBI] =
BEGIN
IF AMTypes.TypeClass[AMTypes.TVType[p]] # process
THEN ERROR AMTypes.Error[typeFault, "TV should be for a process", AMTypes.TVType[p] ];
psbi ← AMBridge.TVToCardinal[p];
world ← AMBridge.GetWorld[p];
END;

GetProcesses: PUBLIC ENTRY PROC[context: LIST OF AMModel.Context ← NIL,
states: LIST OF AMProcess.State]
RETURNS[l: LIST OF Process] =
BEGIN
ENABLE UNWIND => NULL;
world: WorldVM.World =
IF context = NIL THEN WorldVM.LocalWorld[] ELSE AMModel.ContextWorld[context.first];
count: CARDINAL = WorldVM.Read[world, LOOPHOLE[@PSB.PDA.count, WorldVM.Address]];
filter: GFTable = ContextFrames[context, world];
l ← NIL;
FOR psbi: PSBI DECREASING IN [PSB.StartPsb .. PSB.StartPsb + count)
DO state: AMProcess.State;
frame: PrincOps.FrameHandle;
[state: state, frame: frame] ←
PrincOpsInfo[world, psbi, TRUE, FALSE, TRUE, filter, states];
IF state # dead AND frame # NIL
THEN l ← CONS[first: PSBIToTV[world, psbi], rest: l];
ENDLOOP;
END;

Name: PUBLIC PROC[p: Process] RETURNS[Rope.ROPE] =
BEGIN
psbi: PSBI;
world: WorldVM.World;
[world, psbi] ← TVToPSBI[p];
RETURN[Rope.Cat["PSB ", Convert.ValueToRope[[unsigned[psbi, 8]]], "B"]]
END;

Freeze: PUBLIC PROC[processes: LIST OF Process, context: LIST OF AMModel.Context ← NIL] =
{ FreezeOrAdjust[processes, context, FALSE] };

Adjust: PUBLIC PROC[processes: LIST OF Process, context: LIST OF AMModel.Context ← NIL] =
{ FreezeOrAdjust[processes, context, TRUE] };

FreezeOrAdjust: ENTRY PROC[l: LIST OF Process, context: LIST OF AMModel.Context, thaw: BOOL] =
BEGIN
world: WorldVM.World =
IF context = NIL THEN WorldVM.LocalWorld[] ELSE AMModel.ContextWorld[context.first];
filter: GFTable = ContextFrames[context, world];
FOR this: LIST OF Process ← l, this.rest UNTIL this = NIL
DO psbi: PSBI;
pWorld: WorldVM.World;
[pWorld, psbi] ← TVToPSBI[this.first];
IF pWorld = world
THEN [] ← PrincOpsInfo[world, psbi, TRUE, thaw, FALSE, filter];
ENDLOOP;
END;

Thaw: PUBLIC PROC[l: LIST OF Process] =
BEGIN
FOR this: LIST OF Process ← l, this.rest UNTIL this = NIL
DO psbi: PSBI;
world: WorldVM.World;
[world, psbi] ← TVToPSBI[this.first];
AMProcessBasic.Thaw[world, psbi];
ENDLOOP;
END;

GetState: PUBLIC ENTRY PROC[p: Process] RETURNS[
state: AMProcess.State,
faultData: LONG CARDINAL ← 0,
priority: [0..7],
stack: RTBasic.TVNIL,
topFrame: BOOL ] =
BEGIN
ENABLE UNWIND => NULL;
psbi: PSBI;
world: WorldVM.World;
frozenFrame, current: PrincOps.FrameHandle;
[world, psbi] ← TVToPSBI[p];
[state:state, faultData:faultData, priority:priority, frozenFrame:frozenFrame, topFrame:current] ←
PrincOpsInfo[world: world, psbi: psbi, fullStatus: TRUE];
topFrame ← frozenFrame = current;
IF frozenFrame # NIL
THEN stack ← FrameToTV[world, frozenFrame]
ELSE stack ← NIL;
END;

NotImplemented: ERROR = CODE;

CallDebugger: PUBLIC PROC[p: Process, msg: Rope.ROPE] =
BEGIN
psbi: PSBI;
world: WorldVM.World;
frozenFrame: PrincOps.FrameHandle;
[world, psbi] ← TVToPSBI[p];
frozenFrame ← PrincOpsInfo[world: world, psbi: psbi].frozenFrame;
IF frozenFrame = NIL
THEN frozenFrame ← PrincOpsInfo[world: world, psbi: psbi, freeze: TRUE].frozenFrame;
IF frozenFrame # NIL
THEN BEGIN
outcome: AMEventsPrivate.Outcome ←
AMEventsPrivate.ProvokeProcessEvent[p, FrameToTV[world, frozenFrame], msg];
WITH o: outcome SELECT FROM
proceed => NULL;
quit => Abort[p];
retry, returnFrom => ERROR NotImplemented[];
ENDCASE => ERROR;
END;
END;



LocalOnly: PUBLIC ERROR = CODE;

Abort: PUBLIC PROC[p: Process] =
BEGIN
psbi: PSBI;
world: WorldVM.World;
[world, psbi] ← TVToPSBI[p];
AMProcessBasic.Abort[world, psbi];
END;

-- ReturnFrom: PUBLIC PROC[p: Process, frame: RTBasic.TV, result: RTBasic.TV] =

-- Retry: PUBLIC PROC[p: Process, frame: RTBasic.TV, args: RTBasic.TV] =



GFI
: TYPE = PrincOps.GFTIndex;
gfTableSpace: Space.Handle = Space.Create[
size: ((LAST[GFI]-FIRST[GFI]+1+Environment.bitsPerWord-1)/Environment.bitsPerWord +
Environment.wordsPerPage-1) / Environment.wordsPerPage,
parent: Space.virtualMemory];
GFTable: TYPE = AMProcessBasic.GFTable;
gfTable: GFTable = Space.LongPointer[gfTableSpace];

ContextFrames: INTERNAL PROC[context: LIST OF AMModel.Context, world: WorldVM.World]
RETURNS[filter: GFTable] =
BEGIN
Enum: PROC[child: AMModel.Context] RETURNS[stop: BOOL] =
BEGIN
IF AMBridge.IsRemote[child]
THEN BEGIN
gfh: AMBridge.RemoteGlobalFrameHandle =
AMBridge.RemoteGFHFromTV[child];
gf: PrincOps.GlobalFrame;
WorldVM.CopyRead[world: gfh.world,
from: WorldVM.Long[gfh.world, LOOPHOLE[gfh.gfh, WorldVM.ShortAddress]],
to: @gf,
nwords: SIZE[PrincOps.GlobalFrame]];
gfTable[gf.gfi] ← TRUE;
END
ELSE gfTable[AMBridge.GFHFromTV[child].gfi] ← TRUE;
stop ← FALSE;
END;
IF context = NIL
THEN filter ← NIL
ELSE BEGIN
gfTable^ ← ALL[FALSE]; filter ← gfTable;
FOR this: LIST OF AMModel.Context ← context, context.rest UNTIL this = NIL
DO IF AMModel.ContextWorld[this.first] = world
THEN SELECT AMModel.ContextClass[this.first] FROM
world => { filter ← NIL; EXIT };
model => [] ← AMModel.ContextChildren[this.first, Enum];
prog => [] ← Enum[this.first];
ENDCASE => ERROR;
ENDLOOP;
END;
END;

PrincOpsInfo: PROC[world: WorldVM.World,
psbi: CARDINAL,
freeze: BOOLFALSE,
thaw: BOOLFALSE,
fullStatus: BOOLFALSE,
filter: GFTable ← NIL,
states: LIST OF AMProcess.State ← NIL]
RETURNS[
state: AMProcess.State,
faultData: LONG CARDINAL,
priority: [0..7],
frame: PrincOps.FrameHandle,
frozenFrame: PrincOps.FrameHandle,
topFrame: PrincOps.FrameHandle] =
BEGIN
wantedStates: PACKED ARRAY AMProcess.State OF BOOLALL[FALSE];
IF states = NIL
THEN wantedStates ← ALL[TRUE]
ELSE FOR s: LIST OF AMProcess.State ← states, s.rest UNTIL s = NIL
DO wantedStates[s.first] ← TRUE ENDLOOP;
IF filter # NIL THEN SpecialSpace.MakeResident[gfTableSpace];
[state, faultData, priority, frame, frozenFrame, topFrame] ←
AMProcessBasic.Info[world, psbi, freeze, thaw, fullStatus, filter, wantedStates !
UNWIND => IF filter # NIL THEN SpecialSpace.MakeSwappable[gfTableSpace] ];
IF filter # NIL THEN SpecialSpace.MakeSwappable[gfTableSpace];
END;

FrameToTV: PROC[world: WorldVM.World, frame: PrincOps.FrameHandle] RETURNS[RTBasic.TV] =
{ RETURN[ IF frame = NIL
THEN NIL
ELSE IF world = WorldVM.LocalWorld[]
THEN AMBridge.TVForFrame[frame]
ELSE AMBridge.TVForRemoteFrame[
[world: world,
worldIncarnation: WorldVM.CurrentIncarnation[world],
fh: LOOPHOLE[frame, WorldVM.ShortAddress]] ] ] };

Space.Map[gfTableSpace];

END.