VMFrameSnapshotImpl.mesa
last edited by Levin on August 25, 1983 1:27 pm
DIRECTORY
Basics USING [LongDiv],
PrincOps USING [
AV, AVItem, FrameSizeIndex, FrameVec, PDA, ProcessStateBlock, PsbHandle, StartPsb, StateVector],
PrincOpsUtils USING [
DisableInterrupts, EnableInterrupts, FrameSize, LongCOPY, PsbIndexToHandle],
Process USING [Yield],
VM USING [
AddressForPageNumber, Allocate, Free, Interval, PageCount, PagesForWords, SwapIn, Unpin, WordsForPages],
VMInternal USING [
FrameHeapPiece, FrameHeapPieceHeader, frameHeapPieceList, LargeFrame, largeFrameList],
VMSideDoor USING [FrameMarker, FramesDescriptor, StateVectorDescriptor],
VMStatistics USING [];
VMFrameSnapshotImpl: MONITOR
IMPORTS Basics, PrincOpsUtils, Process, VM, VMInternal
EXPORTS VMSideDoor, VMStatistics =
BEGIN
vm: VM.Interval;
Exports to VMStatistics
getFramesCalls, getFramesRetries: PUBLIC INT ← 0;
Exports to VMSideDoor
GetFrames: PUBLIC ENTRY PROC RETURNS [
frames: VMSideDoor.FramesDescriptor, stateVectors: VMSideDoor.StateVectorDescriptor] = {
ZeroFreeFrames: PROC = --INLINE-- {
OPEN PrincOps;
PrincOpsUtils.DisableInterrupts[];
FOR fsi: FrameSizeIndex IN FrameSizeIndex DO
FOR avItem: AVItem ← AV[fsi], avItem.link^ UNTIL avItem.tag ~= frame DO
Don't use PrincOpsUtils.ZERO, because it might trap and use up a frame (this one!)
LongBlkZ[p: avItem.frame+1, count: FrameVec[fsi]-1];
ENDLOOP;
ENDLOOP;
PrincOpsUtils.EnableInterrupts[];
};
LongBlkZ: PROC [p: LONG POINTER, count: CARDINAL] = INLINE
BEGIN
IF count#0 THEN
BEGIN
p^ ← 0;
IF count#1 THEN PrincOpsUtils.LongCOPY[from: p, to: p+1, nwords: count-1];
END;
END;
CopyFramesAndStateVectors: PROC RETURNS [pagesNeeded: INT] = --INLINE-- {
OPEN VMInternal;
base: LONG ORDERED POINTER = LOOPHOLE[VM.AddressForPageNumber[vm.page]];
limit: LONG ORDERED POINTER = base + VM.WordsForPages[vm.count];
p: LONG ORDERED POINTER ← base;
psb: PrincOps.PsbHandle ← PrincOpsUtils.PsbIndexToHandle[PrincOps.StartPsb];
wordsPerSV: CARDINAL = SIZE[PrincOps.StateVector];
svWords: LONG CARDINAL;
PrincOpsUtils.DisableInterrupts[];
THROUGH [0..PrincOps.PDA.count) DO
IF PrincOps.PDA[psb].link.vector THEN {
IF p + wordsPerSV <= limit THEN
PrincOpsUtils.LongCOPY[
from: @PrincOps.PDA[PrincOps.PDA[psb].context.state], to: p, nwords: wordsPerSV];
p ← p + wordsPerSV;
};
psb ← psb + SIZE[PrincOps.ProcessStateBlock];
ENDLOOP;
stateVectors ←
DESCRIPTOR[base, Basics.LongDiv[svWords ← p - base, wordsPerSV]];
FOR piece: FrameHeapPiece ← frameHeapPieceList, piece.next UNTIL piece = NIL DO
wordsToCopy: CARDINAL = piece.wordsInUse - SIZE[FrameHeapPieceHeader];
IF p + wordsToCopy <= limit THEN
PrincOpsUtils.LongCOPY[from: @piece.fsiFrame, to: p, nwords: wordsToCopy];
p ← p + wordsToCopy;
ENDLOOP;
FOR largeFrame: LargeFrame ← largeFrameList, largeFrame.next UNTIL largeFrame = NIL DO
wordsToCopy: CARDINAL = PrincOpsUtils.FrameSize[largeFrame.trueFsi] + SIZE[PrincOps.FrameSizeIndex];
IF p + wordsToCopy <= limit THEN {
PrincOpsUtils.LongCOPY[from: @largeFrame.fsiFrame, to: p, nwords: wordsToCopy];
p^ ← VMSideDoor.FrameMarker[frame[largeFrame.trueFsi]]; -- overwrite "LargeReturnSlot" with FrameMarker
};
p ← p + wordsToCopy;
ENDLOOP;
PrincOpsUtils.EnableInterrupts[];
frames ← DESCRIPTOR[base + svWords, p - (base + svWords)];
RETURN[VM.PagesForWords[p - base]]
};
--*stats*-- getFramesCalls ← getFramesCalls.SUCC;
DO
pagesNeeded: VM.PageCount;
VM.SwapIn[interval: vm, kill: TRUE, pin: TRUE];
ZeroFreeFrames[];
Process.Yield[];
pagesNeeded ← CopyFramesAndStateVectors[];
VM.Unpin[vm];
IF pagesNeeded <= vm.count THEN EXIT;
VM.Free[vm];
--*stats*-- getFramesRetries ← getFramesRetries.SUCC;
vm ← VM.Allocate[pagesNeeded];
ENDLOOP;
};
Initialize: PROC = {
OPEN VMInternal;
slopPages: VM.PageCount = 5; -- just a guess
wordsToCopy: INT ← 0;
PrincOpsUtils.DisableInterrupts[];
FOR piece: FrameHeapPiece ← frameHeapPieceList, piece.next UNTIL piece = NIL DO
wordsToCopy ← wordsToCopy + (piece.wordsInUse - SIZE[FrameHeapPieceHeader]);
ENDLOOP;
PrincOpsUtils.EnableInterrupts[];
vm ← VM.Allocate[count: VM.PagesForWords[wordsToCopy]+ slopPages];
};
Initialize[];
END.