Dequeue:
PROC[world: WorldVM.World, psbi:
PSBI, frame: PrincOps.FrameHandle] =
BEGIN
-- Only implemented for world = local --
This procedure will remove a process from a CV or ML queue and requeue it onto ready list.
The process must already have bee forced into a trap so it will not return from the
frame where it was waiting.
World is not frozen at entry, nor at exit.
style: { ME, MRE };
wordAddr: LONG POINTER;
offset: [0..1];
op, trap: PrincOps.op;
queue: LONG POINTER TO PrincOps.Queue;
set the tangle-trap
DO code:
LONG
POINTER = frame.accesslink.code.longbase;
pc: PrincOps.BytePC ← [frame.pc-1];
Fetch:
PROC =
BEGIN
word: PrincOps.InstWord;
wordAddr ← code + pc / 2;
offset ← pc MOD 2;
word ← wordAddr^;
op ← IF offset = 0 THEN word.evenbyte ELSE word.oddbyte;
END;
Fetch[];
SELECT op
FROM
PrincOps.zME => { style ← ME; trap ← zTrapME };
PrincOps.zMRE => { style ← MRE; trap ← zTrapMRE };
PrincOps.zMXW =>
BEGIN
style ← MRE;
trap ← zTrapMRE;
THROUGH [1..1000]
DO pc ← [pc + OpcodeLengths[op]]; Fetch[]; IF op = PrincOps.zMRE THEN EXIT;
REPEAT FINISHED => ERROR
ENDLOOP;
END;
zTrapME, zTrapMRE =>
{ Process.Pause[1]; LOOP --obscure: some other process being patched at same place--};
ENDCASE => { Clear[psbi]; RETURN }; -- process will become ready by itself --
IF WVMPrivate.Patch[world: world, addr:
LOOPHOLE[wordAddr, WorldVM.Address],
offset: offset, byte: trap] = op
THEN EXIT;
-- otherwise, someone else is patching, so look again! --
ENDLOOP;
-- call copy of victim's frame, to evaluate queue pointers --
BEGIN
newFrame: PrincOps.FrameHandle;
state: PrincOps.StateVector;
fsi: CARDINAL ← LOOPHOLE[frame-1, POINTER TO CARDINAL]^;
size: CARDINAL;
IF fsi >= PrincOps.LargeReturnSlot
THEN
BEGIN
size ← LOOPHOLE[frame-2, POINTER TO CARDINAL]^;
FOR i: PrincOps.FrameSizeIndex IN PrincOps.FrameSizeIndex
DO IF size <= PrincOps.FrameVec[i] THEN { newFrame ← PrincOpsUtils.Alloc[fsi ← i]; EXIT };
REPEAT FINISHED => ERROR
ENDLOOP;
END
ELSE { size ← PrincOps.FrameVec[fsi]; newFrame ← PrincOpsUtils.Alloc[fsi] };
PrincOpsUtils.LongCopy[from: frame, to: newFrame, nwords: PrincOps.FrameVec[fsi]];
newFrame.returnlink.frame ← PrincOpsUtils.MyLocalFrame[];
IF style = ME
THEN LOOPHOLE[newFrame, PROC[BOOL]][FALSE]
ELSE LOOPHOLE[newFrame, PROC][];
state ← STATE;
SELECT
TRUE
FROM
(style =
ME
AND state.stkptr = 1) =>
queue ← LOOPHOLE[state.stk[0],POINTER];
(style =
MRE
AND state.stkptr = 2) =>
queue ← LOOPHOLE[state.stk[1],POINTER];
(style =
ME
AND state.stkptr = 2) =>
queue
← LOOPHOLE[Basics.LongNumber[num[lowbits: state.stk[0], highbits: state.stk[1]]]];
(style =
MRE
AND state.stkptr = 4) =>
queue
← LOOPHOLE[Basics.LongNumber[num[lowbits: state.stk[2], highbits: state.stk[3]]]];
ENDCASE => ERROR;
-- Beware if the queue should be in the victim's local frame! --
BEGIN
queueCard: LONG CARDINAL = LOOPHOLE[queue];
frameBase: LONG CARDINAL = LOOPHOLE[LONG[newFrame]];
IF queueCard > frameBase AND queueCard <= frameBase + size
THEN queue ← queue - frameBase + LOOPHOLE[LONG[frame],LONG CARDINAL];
END;
END;
-- remove the tangle trap --
IF WVMPrivate.Patch[world: world, addr:
LOOPHOLE[wordAddr, WorldVM.Address],
offset: offset, byte: op] # trap
THEN ERROR;
-- Transfer the process to the ready list if it's still on the queue --
BEGIN
handle: PrincOps.PsbHandle = PrincOpsUtils.PsbIndexToHandle[psbi];
queuePage: PrincOps.PageNumber =
LOOPHOLE[queue, LONG CARDINAL] / PrincOps.wordsPerPage;
THROUGH [1..50] -- garbage check --
DO [] ← queue^;
-- queue may be non-resident --
PrincOpsUtils.DisableInterrupts[];
IF VMInternal.IsVacant[queuePage] THEN EXIT;
PrincOpsUtils.EnableInterrupts[];
REPEAT FINISHED => ERROR
ENDLOOP;
-- now disabled, with queue swapped in --
IF OnQueue[world, psbi, queue]
THEN PrincOpsUtils.EnableAndRequeue[queue, @PrincOps.PDA.ready, handle]
ELSE PrincOpsUtils.EnableInterrupts[];
END;
END--Dequeue--;
OpcodeLengths:
PACKED
ARRAY [0..255]
OF [0..3] = [
-- copied from Traps.mesa
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1,
1, 1, 1, 1, 2, 3, 2, 2, 2, 3, 0, 0, 0, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 3, 3,
2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 3, 2, 3, 1, 1, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 1, 1, 1, 2, 2, 1, 1, 1, 2, 1, 1, 1, 1, 0, 0,
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1,
1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
1, 1, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2,
0, 2, 2, 1, 0];