--MesaRuntime>FrameImpl.mesa (December 8, 1982 9:57 pm by Levin)
DIRECTORY
CPSwapDefs USING [SwapInfo],
Environment USING [wordsPerPage],
File USING [Capability, GetAttributes, Type],
FileTypes USING [DCSFileType],
Frame USING [Alloc, Free, GetReturnFrame, SetReturnLink],
Inline USING [BITAND, COPY],
PrincOps USING [
AllocationVectorSize, AV, AVHandle, AVItem, ControlLink, CSegPrefix, EPRange,
Frame, FrameCodeBase, FrameHandle, FrameSizeIndex, FrameVec, GFTIndex,
GlobalFrameHandle, LargeReturnSlot, LastAVSlot, MainBodyIndex, NullFrame,
NullLink, NullGlobalFrame, UnboundLink],
PrincOpsRuntime USING [EmptyGFTItem, FreedGFTItem, GetFrame, GFT, GFTItem],
Process USING [GetPriority, Priority, SetPriority],
ProcessInternal USING [DisableInterrupts, EnableInterrupts],
ProcessOperations USING [Enter, IndexToHandle, LongReEnter, LongWait, Requeue],
ProcessPriorities USING [priorityFrameFault],
PSB USING [
FaultIndex, NoTimeout, PDA, PDABase, PsbHandle, Queue, QueueEmpty,
qFrameFault],
ResidentMemory USING [AllocateMDS, FreeMDS],
Runtime USING [NullProgram, UnboundProcedure, UnNew],
RuntimeInternal USING [],
RuntimePrograms USING [],
SDDefs USING [sCopy, SD, sGFTLength, sUnNew],
Space USING [
Create, Delete, Error, GetAttributes, GetHandle, GetWindow, Handle, LongPointer, Map,
PageFromLongPointer, virtualMemory, WindowOrigin],
System USING [GreenwichMeanTime];
FrameImpl: MONITOR LOCKS gftLock
IMPORTS
File, Frame, Inline, PrincOpsRuntime, Process, ProcessInternal, ProcessOperations,
ResidentMemory, Runtime, Space
EXPORTS Runtime, RuntimeInternal, RuntimePrograms =
BEGIN OPEN PrincOpsRuntime;
ControlLink: TYPE = PrincOps.ControlLink;
FrameHandle: TYPE = PrincOps.FrameHandle;
GFTIndex: TYPE = PrincOps.GFTIndex;
GlobalFrameHandle: TYPE = PrincOps.GlobalFrameHandle;
LargeReturnSlot: CARDINAL = PrincOps.LargeReturnSlot;
NullGlobalFrame: PrincOps.GlobalFrameHandle = PrincOps.NullGlobalFrame;
AV: PrincOps.AVHandle = PrincOps.AV;
NullProgram: PROGRAM = Runtime.NullProgram;
-- Public SIGNALs and ERRORs:
--Runtime.-- InvalidFrame: PUBLIC ERROR [frame: FrameHandle] = CODE;
--Runtime.-- InvalidGlobalFrame: PUBLIC ERROR [frame: GlobalFrameHandle] = CODE;
--RuntimePrograms.-- NoGlobalFrameSlots: PUBLIC SIGNAL [CARDINAL] = CODE;
gftLock: MONITORLOCK; -- This lock protects the GlobalFrameTable (and gftRover).
-- frameFaultLock protects the local frame heap (and the Frane Fault Handler's variables).
-- (However, since there is only one process that explicitly updates the frame heap,
-- this lock is only necessary to allow the frame fault process to have a monitor to
-- wait from. We use a separate lock so that the frame fault process will not be blocked
-- by other processes accessing the GFT.)
frameHeapLock: MONITORLOCK;
gftRover: CARDINAL ← 1; -- for creation of new GFT entries. (Note that 0 is reserved.)
--RuntimePrograms.--
InitializeFrameImpl: PUBLIC PROCEDURE[] =
BEGIN
throwAway: PROCESS;
priorityPrev: Process.Priority = Process.GetPriority[];
Process.SetPriority[ProcessPriorities.priorityFrameFault];
throwAway ← FORK FrameFaultProcess[]; -- no profit in detaching.
Process.SetPriority[priorityPrev];
SDDefs.SD[SDDefs.sCopy] ← Copy;
SDDefs.SD[SDDefs.sUnNew] ← zUnNew;
END;
-- Procedures: (ordered by kind {external, entry, internal}; within a kind, alphabetically)
-- External Procedures (public and private):
--RuntimeInternal.--
Codebase: PUBLIC PROC [frame: PROGRAM] RETURNS [l: LONG POINTER] =
BEGIN OPEN c: LOOPHOLE[l, PrincOps.FrameCodeBase];
c ← LOOPHOLE[frame, GlobalFrameHandle].code;
c.out ← FALSE;
END;
--RuntimeInternal.--
DeletedFrame: PUBLIC PROCEDURE [gfi: GFTIndex] RETURNS [BOOLEAN] = {
RETURN[GFT[gfi] = FreedGFTItem]};
--RuntimeInternal.--
FrameSize: PUBLIC PROCEDURE [fsi: CARDINAL] RETURNS [CARDINAL] = {
RETURN[PrincOps.FrameVec[fsi]]};
--Runtime.--
GetCaller: PUBLIC SAFE PROCEDURE RETURNS [PROGRAM] = TRUSTED {
RETURN[LOOPHOLE[Frame.GetReturnFrame[].returnlink.frame.accesslink]]; };
--Runtime.--
GetTableBase: PUBLIC PROC [frame: PROGRAM] RETURNS [l: LONG POINTER] = Codebase;
--Runtime.--
GlobalFrame: PUBLIC PROCEDURE [link: UNSPECIFIED] RETURNS [PROGRAM] =
BEGIN OPEN l: LOOPHOLE[link, ControlLink];
DO
IF l = PrincOps.UnboundLink THEN
link ← SIGNAL Runtime.UnboundProcedure[link]
ELSE
IF l.proc THEN
RETURN[
IF l.gfi IN [1..SDDefs.SD[SDDefs.sGFTLength]) THEN LOOPHOLE[GetFrame[
GFT[l.gfi]], PROGRAM] ELSE NullProgram]
ELSE
IF l.indirect THEN link ← l.link↑
ELSE -- Frame
BEGIN
IF link = 0 THEN RETURN[NullProgram];
IF ValidGlobalFrame[link] THEN RETURN[link];
RETURN[
IF ValidGlobalFrame[l.frame.accesslink] THEN
LOOPHOLE[l.frame.accesslink, PROGRAM] ELSE NullProgram];
END;
ENDLOOP;
END;
--Runtime.--
IsBound: PUBLIC PROCEDURE [link: UNSPECIFIED] RETURNS [BOOLEAN] = {
RETURN[link # PrincOps.UnboundLink AND link # PrincOps.NullLink]; };
--RuntimeInternal.--
MakeFsi: PUBLIC PROCEDURE [words: CARDINAL] RETURNS [fsi: CARDINAL] = {
FOR fsi IN [0..PrincOps.LastAVSlot) DO
IF PrincOps.FrameVec[fsi] >= words THEN RETURN; ENDLOOP;
RETURN[words]};
--Runtime.--
GetBcdTime: PUBLIC SAFE PROCEDURE RETURNS [time: System.GreenwichMeanTime] = TRUSTED
BEGIN
codeFile: File.Capability;
BEGIN
ENABLE Space.Error => GO TO noLeader;
-- don't want Pilot to depend on DCSFileTypes
tLeaderPage: File.Type = [FileTypes.DCSFileType[515]];
space: Space.Handle ← Space.GetHandle[Space.PageFromLongPointer[
Codebase[GlobalFrame[Frame.GetReturnFrame[]]]]];
DO
parent: Space.Handle;
mapped: BOOLEAN;
[parent: parent, mapped: mapped] ← Space.GetAttributes[space];
IF mapped THEN EXIT;
space ← parent;
ENDLOOP;
codeFile ← Space.GetWindow[space].file;
IF File.GetAttributes[codeFile].type ~= --DCSFileTypes.--tLeaderPage THEN GO TO noLeader;
EXITS
noLeader => RETURN[GetBuildTime[]];
END;
BEGIN
LeaderPageFront: TYPE = -- stolen from FileStreamImpl
MACHINE DEPENDENT RECORD [
versionID: CARDINAL,
dataType: --FileStream.Subtype-- WORD,
create: System.GreenwichMeanTime];
leaderSpace: Space.Handle = Space.Create[size: 1, parent: Space.virtualMemory];
leader: LONG POINTER TO LeaderPageFront = Space.LongPointer[leaderSpace];
Space.Map[leaderSpace, Space.WindowOrigin[codeFile, 0]];
time ← leader.create;
Space.Delete[leaderSpace];
END;
END;
--Runtime.--
GetBuildTime: PUBLIC SAFE PROCEDURE RETURNS [time: System.GreenwichMeanTime] = TRUSTED {
pdaDumpingGround: LONG POINTER TO CPSwapDefs.SwapInfo = LOOPHOLE[@PSB.PDA.available];
-- Assumes MakeBoot has put a copy of the boot file creation date in
-- PSB.PDA.available[3..4]. This will be available even if we were ether-booted
-- and the boot file header is no longer available. (Of course, it shouldn't have
-- to do this; the Germ should save the creation date from the header and store it
-- somewhere, but this requires changing too many interfaces.)
RETURN[LOOPHOLE[pdaDumpingGround.availableB]]
};
--Runtime.--
SelfDestruct: PUBLIC PROCEDURE[] = {
destructee: PrincOps.FrameHandle = Frame.GetReturnFrame[];
Frame.SetReturnLink[destructee.returnlink];
Runtime.UnNew[LOOPHOLE[GlobalFrame[destructee], PROGRAM]];
Frame.Free[destructee]};
-- Entry Procedures:
Copy: --PUBLIC-- ENTRY PROCEDURE [old: GlobalFrameHandle]
RETURNS [new: GlobalFrameHandle] =
-- conceptually, Copy is PUBLIC, but it is accessed via the System Dispatch table.
BEGIN
linkspace: CARDINAL;
codebase: LONG POINTER TO PrincOps.CSegPrefix;
IF ~ValGlobalFrame[old] THEN RETURN WITH ERROR InvalidGlobalFrame[old];
codebase ← Codebase[LOOPHOLE[old, PROGRAM]];
[new, linkspace] ← AllocGlobalFrame[old, codebase];
new ← new + linkspace;
new↑ ← [
gfi:, alloced: TRUE, shared: TRUE, copied: TRUE, started: FALSE,
trapxfers: FALSE, codelinks: old.codelinks, code: old.code, global:];
new.code.out ← TRUE; -- cause trap
new.global[0] ← NullGlobalFrame;
IF linkspace # 0 THEN
Inline.COPY[from: old - linkspace, to: new - linkspace, nwords: linkspace];
IF ~EntGlobalFrame[new, codebase.header.info.ngfi] THEN
RETURN WITH ERROR NoGlobalFrameSlots[codebase.header.info.ngfi];
old.shared ← TRUE;
END;
--RuntimeInternal.--
EnterGlobalFrame: PUBLIC ENTRY PROCEDURE [frame: GlobalFrameHandle, nslots: CARDINAL]
RETURNS [entryindex: GFTIndex] = {
IF ~EntGlobalFrame[frame, nslots] THEN RETURN WITH ERROR NoGlobalFrameSlots[nslots];
RETURN[frame.gfi]};
--RuntimeInternal.--
GetNextGlobalFrame: PUBLIC ENTRY PROCEDURE [frame: GlobalFrameHandle]
RETURNS [GlobalFrameHandle] = {
IF frame # NullGlobalFrame AND ~ValGlobalFrame[frame] THEN
RETURN WITH ERROR InvalidGlobalFrame[frame]
ELSE RETURN[GetNxGlobalFrame[frame]]};
--RuntimePrograms.--
RemoveGlobalFrame: PUBLIC ENTRY PROCEDURE [frame: GlobalFrameHandle] = {
RemvGlobalFrame[frame]};
zUnNew: --PUBLIC-- ENTRY PROCEDURE [frame: GlobalFrameHandle] =
-- conceptually, (z)UnNew is PUBLIC, but is accessed via the System Dispatch table.
BEGIN
sharer: GlobalFrameHandle ← NullGlobalFrame;
original: GlobalFrameHandle ← NullGlobalFrame;
copy, f: GlobalFrameHandle ← NullGlobalFrame;
codebase: LONG POINTER TO PrincOps.CSegPrefix;
nothers: CARDINAL ← 0;
nlinks: CARDINAL;
IF ~ValGlobalFrame[frame] THEN RETURN WITH ERROR InvalidGlobalFrame[frame];
codebase ← Codebase[LOOPHOLE[frame, PROGRAM]];
nlinks ← codebase.header.info.nlinks;
FOR f ← GetNxGlobalFrame[NullGlobalFrame], GetNxGlobalFrame[f] UNTIL f =
NullGlobalFrame DO
IF f # frame THEN
BEGIN
IF f.global[0] = frame AND ~f.started THEN
f.global[0] ← PrincOps.NullFrame;
IF Codebase[LOOPHOLE[f, PROGRAM]] = codebase THEN
IF f.copied THEN copy ← f ELSE original ← f;
END;
ENDLOOP;
-- To aid debugging, at present we don't delete the original copy because it has the original links:
IF original = NullGlobalFrame AND ~frame.copied AND copy # NullGlobalFrame
THEN RETURN WITH ERROR InvalidGlobalFrame[frame];
-- BEGIN OPEN LoadStateDefs;
-- config: ConfigIndex;
-- cgfi: GFTIndex;
-- copy.copied ← FALSE;
-- [] ← InputLoadState[];
-- [cgfi: cgfi, config: config] ← MapRealToConfig[frame.gfi];
-- EnterGfi[cgfi: 0, rgfi: frame.gfi, config: ConfigNull];
-- EnterGfi[cgfi: cgfi, rgfi: copy.gfi, config: config];
-- ReleaseLoadState[];
-- END;
RemvGlobalFrame[frame];
IF frame.alloced THEN {
Align: PROCEDURE [POINTER, WORD] RETURNS [POINTER] =
LOOPHOLE[Inline.BITAND];
IF frame.codelinks THEN Frame.Free[frame]
ELSE Frame.Free[Align[frame - nlinks, 177774B]]};
END;
--Runtime.--
ValidateFrame: PUBLIC PROCEDURE [frame: FrameHandle] = {
OPEN LOOPHOLE[frame, rep ControlLink];
IF proc OR indirect OR ~ValidGlobalFrame[frame.accesslink] THEN ERROR InvalidFrame[frame]};
--Runtime.--
ValidateGlobalFrame: PUBLIC PROCEDURE [g: GlobalFrameHandle] = {
IF ~ValidGlobalFrame[g] THEN ERROR InvalidGlobalFrame[g]};
ValidGlobalFrame: PRIVATE ENTRY PROCEDURE [g: GlobalFrameHandle]
RETURNS [BOOLEAN] = INLINE {RETURN[ValGlobalFrame[g]]};
-- Internal Procedures:
AllocGlobalFrame: INTERNAL PROCEDURE [
old: GlobalFrameHandle, cp: LONG POINTER TO PrincOps.CSegPrefix]
RETURNS [frame: GlobalFrameHandle, linkspace: CARDINAL] =
BEGIN
pbody: LONG POINTER =
cp + CARDINAL[cp.entry[PrincOps.MainBodyIndex].initialpc];
nlinks: CARDINAL = cp.header.info.nlinks;
linkspace ←
IF ~old.codelinks THEN
nlinks + Inline.BITAND[-LOOPHOLE[nlinks, INTEGER], 3B] ELSE 0;
frame ← Frame.Alloc[MakeFsi[(pbody - 1)↑ + linkspace]];
END;
EntGlobalFrame: INTERNAL PROCEDURE [frame: GlobalFrameHandle, nslots: CARDINAL]
RETURNS [ok: BOOLEAN] =
BEGIN
entryindex: GFTIndex;
k, kMax, n, epoffset: CARDINAL;
k ← gftRover;
kMax ← SDDefs.SD[SDDefs.sGFTLength] - nslots;
n ← 0;
DO
IF (k ← IF k >= kMax THEN 1 ELSE k + 1) = gftRover THEN RETURN[FALSE];
IF GFT[k] # EmptyGFTItem THEN n ← 0 ELSE IF (n ← n + 1) = nslots THEN EXIT;
ENDLOOP;
entryindex ← (gftRover ← k) - nslots + 1;
epoffset ← 0;
FOR k IN [entryindex..gftRover] DO
GFT[k].framePtr ← frame;
GFT[k].epbias ← epoffset;
epoffset ←
epoffset +
-- 1 with new format, 32 with old format
(IF SIZE[GFTItem] = 2 THEN PrincOps.EPRange ELSE 1);
ENDLOOP;
frame.gfi ← entryindex;
RETURN[TRUE];
END;
GetNxGlobalFrame: INTERNAL PROCEDURE [frame: GlobalFrameHandle]
RETURNS [GlobalFrameHandle] =
BEGIN
gfi: GFTIndex;
IF frame = NullGlobalFrame THEN gfi ← 1 ELSE gfi ← frame.gfi + 1;
WHILE gfi < SDDefs.SD[SDDefs.sGFTLength] DO
frame ← GetFrame[GFT[gfi]];
IF frame # NullGlobalFrame AND GFT[gfi].epbias = 0 THEN RETURN[frame];
gfi ← gfi + 1;
ENDLOOP;
RETURN[NullGlobalFrame]
END;
InGFT: INTERNAL PROCEDURE [g: GlobalFrameHandle] RETURNS [BOOLEAN] = {
FOR k: CARDINAL IN [1..SDDefs.SD[SDDefs.sGFTLength]) DO
entry: GFTItem = GFT[k];
IF entry ~= EmptyGFTItem AND entry ~= FreedGFTItem AND
GetFrame[entry] = g AND g.gfi = k THEN RETURN[TRUE];
ENDLOOP;
RETURN[FALSE]};
RemvGlobalFrame: INTERNAL PROCEDURE [frame: GlobalFrameHandle] = {
FOR k: CARDINAL ← frame.gfi, k + 1 WHILE k < SDDefs.SD[SDDefs.sGFTLength]
AND GetFrame[GFT[k]] = frame DO
GFT[k] ← IF frame.copied THEN EmptyGFTItem ELSE FreedGFTItem ENDLOOP};
ValGlobalFrame: INTERNAL PROCEDURE [g: GlobalFrameHandle] RETURNS [BOOLEAN] =
INLINE {
OPEN LOOPHOLE[g, rep ControlLink]; RETURN[~proc AND ~indirect AND InGFT[g]]};
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- Frame Allocation Fault Handler
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- The global variables below are protected by frameHeapLock.
pda: PSB.PDABase = PSB.PDA;
qFrameFault: PSB.FaultIndex = PSB.qFrameFault;
pFrameFaultCondition: LONG POINTER TO CONDITION = LOOPHOLE[@pda.fault[
qFrameFault].condition];
AnyFrameSizeIndex: TYPE = CARDINAL [0..PrincOps.AllocationVectorSize); -- note that a AnyFrameSizeIndex immediately preceeds a Frame.
NormalFrameSizeIndex: TYPE = PrincOps.FrameSizeIndex;
FsiFrame: TYPE = MACHINE DEPENDENT RECORD [
fsi(0): AnyFrameSizeIndex, -- must be at 3 MOD 4 boundary.
frame(1): local PrincOps.Frame];
FrameSegment: TYPE = POINTER TO FrameSegmentHeader;
FrameSegmentHeader: TYPE = MACHINE DEPENDENT RECORD [
link(0): FrameSegment,
pages(1): CARDINAL,
sizeIfLargeFrame(2): CARDINAL, -- (for debugging only. not used in small frame segment)
fsiFrame(3): ARRAY [0..0) OF --WORD-- FsiFrame]; -- must be at 3 MOD 4 boundary.
largeFrameThresholdFsi: NormalFrameSizeIndex = 12; -- frames this size or larger will be allocated in an integral number of pages, and reclaimed when they are freed. FrameVec[largeFrameThresholdFsi] must be < wordsPerPage.
frameListHead: FrameSegment ← NIL; -- list of all dynamically-allocated "permanent" (small) frame segments (for debugging only).
pNewFsiFrame: POINTER TO --ARRAY [0..0) OF WORD-- FsiFrame; -- storage available for building new frames.
storageRemaining: CARDINAL ← 0; -- words remaining in pNewFsiFrame↑.
FrameFaultProcess: --ENTRY-- PROCEDURE[] --LOCKS frameHeapLock-- =
BEGIN
-- "arguments":
process: PSB.PsbHandle;
fsi: NormalFrameSizeIndex; -- frame size index of frame desired.
-- "results":
pNewFrame: FrameHandle; -- the frame we will allocate and paste into the AV.
-- "temporary" variables:
frSize: CARDINAL; -- word size of frame desired, including fsi word. Guaranteed to be a multiple of 4.
k: CARDINAL;
frameSeg: FrameSegment;
UNTIL ProcessOperations.Enter[@frameHeapLock] DO NULL ENDLOOP;
--FOREVER--
DO
WHILE pda.fault[qFrameFault].queue = PSB.QueueEmpty DO -- await next Frame Fault..
ProcessOperations.LongWait[
@frameHeapLock, pFrameFaultCondition, PSB.NoTimeout];
UNTIL ProcessOperations.LongReEnter[@frameHeapLock, pFrameFaultCondition]
DO NULL ENDLOOP;
ENDLOOP;
process ← ProcessOperations.IndexToHandle[
pda.block[pda.fault[qFrameFault].queue.tail].link.next]; -- walk to tail, then to head.
fsi ← pda[pda[process].context.state].fsi;
frSize ← PrincOps.FrameVec[fsi] + SIZE[AnyFrameSizeIndex]; -- must be a multiple of 4!
-- First free any unused large frames:
-- (Note that AV[LargeReturnSlot].tag, .frame, and .link are overlaid.)
WHILE AV[LargeReturnSlot].tag = frame DO
-- Atomically remove some large frame from freelist:
ProcessInternal.DisableInterrupts[]; -- so no one frees during list delete.
frameSeg ← -- grab addr of large frame and back over overhead stuff
LOOPHOLE[AV[LargeReturnSlot].frame - SIZE[FrameSegmentHeader] - SIZE[
AnyFrameSizeIndex]];
AV[LargeReturnSlot].link ← AV[LargeReturnSlot].link↑.link;
ProcessInternal.EnableInterrupts[];
ResidentMemory.FreeMDS[frameSeg, frameSeg.pages];
ENDLOOP;
IF fsi >= largeFrameThresholdFsi THEN
BEGIN --alloc large frame--
frameSeg ← ResidentMemory.AllocateMDS[
pages: k ←
(frSize + SIZE[FrameSegmentHeader] + Environment.wordsPerPage -
1)/Environment.wordsPerPage];
frameSeg↑ ← [
link: NIL, pages: k, sizeIfLargeFrame: frSize, fsiFrame: NULL];
frameSeg.fsiFrame[0].fsi ← LargeReturnSlot; -- (a fsi never generated by the compiler.)
pNewFrame ← @frameSeg.fsiFrame[0].frame;
END -- alloc large frame
ELSE
BEGIN --alloc small frame--
IF storageRemaining < frSize THEN
BEGIN --alloc more storage for frame--
-- Use any remaining storage for a frame:
FOR k DECREASING IN [0..fsi) DO
IF CARDINAL[PrincOps.FrameVec[k] + SIZE[FrameSegmentHeader]] <=
storageRemaining THEN {
pNewFsiFrame.fsi ← k;
Frame.Free[@pNewFsiFrame.frame]; -- atomically paste onto frame heap.
EXIT}
ENDLOOP;
-- Allocate a new page from which to build frames:
frameSeg ← ResidentMemory.AllocateMDS[pages: 1];
frameSeg.link ← frameListHead;
frameListHead ← frameSeg;
frameSeg.pages ← 1;
pNewFsiFrame ← @frameSeg.fsiFrame[0]; -- must be at 3 MOD 4 boundary.
storageRemaining ← Environment.wordsPerPage - SIZE[FrameSegmentHeader];
END; --alloc more storage for frame--
-- IF storageRemaining < frSize THEN
-- RuntimeInternal.WorryCallDebugger["FrameFaultBug"L];
-- Fabricate a new frame:
pNewFsiFrame.fsi ← fsi;
pNewFrame ← @pNewFsiFrame.frame;
pNewFsiFrame ← pNewFsiFrame + frSize;
storageRemaining ← storageRemaining - frSize;
END; --alloc small frame--
-- Atomically chain the new frame onto the AV:
-- Note that we can not do a Frame.Free[] here because large frames
-- have an fsi different than that of the AV slot we put them in.
ProcessInternal.DisableInterrupts[]; -- so no one frees during the list insert.
LOOPHOLE[pNewFrame, POINTER TO PrincOps.AVItem]↑.link ← AV[fsi].link;
AV[fsi]. --link-- frame ← pNewFrame;
ProcessInternal.EnableInterrupts[];
-- Restart faulted process:
ProcessOperations.Requeue[
@pda.fault[qFrameFault].queue, @pda.ready, process];
ENDLOOP;
END;
END.
LOG
(For earlier log entries see Pilot 4.0 archive version.)
April 14, 1980 10:45 AM Knutsen Now STARTed by InitializeFrames[].
April 29, 1980 9:04 PM Forrest Put back old InGFT
May 3, 1980 11:44 AM Forrest Initial Mesa 6.0 conversion
July 20, 1980 9:03 PM Forrest PrincOpsRuntime
August 1, 1980 2:04 PM Luniewski Rename to FrameImpl
August 26, 1980 12:27 PM McJones Add GetBcdTime
January 19, 1981 9:40 AM Knutsen Frame faults, not traps. Fault handler, Codebase, GetTableBase moved here from Traps.
January 29, 1981 1:59 PM Knutsen Remove LOOPHOLEs used to get fault parameter.
February 14, 1981 5:44 PM Knutsen Leave faulted process on PDA queue.
14-Jan-82 16:57:39 Levin Improve GetBcdTime/GetBuildTime
16-Feb-82 12:15:45 Levin Fix InGFT not to consider GFT[0] (matches g=NIL!)
23-Mar-82 15:55:50 Levin Fix GetBuildTime to work on ether booting.
June 1, 1982 3:56 pm Levin New loadstate format
August 18, 1982 3:46 pm Levin Change GetBcdTime to eliminate dependence on loadstate.
August 26, 1982 11:20 am Levin Make things SAFE.
September 8, 1982 12:55 pm Levin Fix frame validate procedures to avoid address faults within monitor.
October 25, 1982 1:20 pm Levin Fix EnterGlobalFrame to set gfi in new frame before exiting monitor (for Loader).
December 8, 1982 9:57 pm Levin InGFT no longer address faults if NullGlobalFrame is passed in.