-- RTOSImpl.Mesa -- last edit by Paul Rovner, December 17, 1982 8:48 am DIRECTORY CachedSpace USING[Handle], CedarSnapshot USING[Register, After], Directory USING[Lookup], Environment USING[wordsPerPage, Long], File USING [read, write, Capability, nullCapability, GetSize], Heap USING [Create], PrincOps USING [GlobalFrameHandle, NullGlobalFrame, FrameCodeBase], PrincOpsRuntime USING [GetFrame, GFT, GFTItem], RTFlags USING [checking], RTOS USING [EVRange, CodeMatch], RTQuanta USING[PagesPerQuantum, QuantumCount, QuantumIndex], RTSponge USING [Enable, Disable], RTZones USING [MapPtrZf, mzVacant], SDDefs USING [SD, sGFTLength], Space USING [Create, CreateUniformSwapUnits, nullHandle, InsufficientSpace, defaultWindow, Delete, GetWindow, GetHandle, Handle, Kill, LongPointer, Map, PageNumber, PageCount, PageFromLongPointer, mds, virtualMemory, GetAttributes, WindowOrigin, DeleteSwapUnits], SpecialSpace: TYPE USING [CreateForCode, MakeResident, CreateAligned], UnsafeStorage USING [NewUZone], Volume USING[InsufficientSpace]; RTOSImpl: MONITOR IMPORTS CedarSnapshot, Directory, File, Heap, PrincOpsRuntime, RTSponge, RTZones, Space, SpecialSpace, UnsafeStorage, Volume EXPORTS RTOS = BEGIN OPEN RTQuanta; PageSize: CARDINAL = Environment.wordsPerPage; GlobalFrameHandle: TYPE = PrincOps.GlobalFrameHandle; NullGlobalFrame: GlobalFrameHandle = PrincOps.NullGlobalFrame; EVRange: TYPE = RTOS.EVRange; --Public signals InsufficientVM: PUBLIC SIGNAL = CODE; --Public variables UZHandle: TYPE = LONG POINTER TO UZObject; UZObject: TYPE = MACHINE DEPENDENT RECORD [ procs(0:0..31): LONG POINTER TO UZProcs ]; UZProcs: TYPE = MACHINE DEPENDENT RECORD [ new(0): PROC[self: UZHandle, size: CARDINAL] RETURNS[LONG POINTER], free(1): PROC[self: UZHandle, object: LONG POINTER] ]; DummySequenceType: TYPE = RECORD[seq: SEQUENCE length: CARDINAL OF UNSPECIFIED]; shzProcs: UZProcs _ [new: SHZNew, free: SHZFree]; shzObject: UZObject _ [procs: @shzProcs]; SHZNew: PROC[self: UZHandle, size: CARDINAL] RETURNS[LONG POINTER] = { size _ size - SIZE[DummySequenceType]; IF allocStarted THEN RETURN[cedarHeapZone.NEW[DummySequenceType[size]]] ELSE RETURN[pilotHeapZone.NEW[DummySequenceType[size]]]; }; SHZFree: ENTRY PROC[self: UZHandle, object: LONG POINTER] = {IF RTZones.MapPtrZf[object] = RTZones.mzVacant THEN pilotHeapZone.FREE[@object] ELSE cedarHeapZone.FREE[@object]}; fszProcs: UZProcs _ [new: FSZNew, free: FSZFree]; fszObject: UZObject _ [procs: @fszProcs]; FSZNew: PROC[self: UZHandle, size: CARDINAL] RETURNS[LONG POINTER] = { RETURN[GetDataPagesFromNewSpace[(size + PageSize - 1)/PageSize]]; }; FSZFree: ENTRY PROC[self: UZHandle, object: LONG POINTER] = {space: Space.Handle; WHILE checkPointing DO WAIT finishedCheckpointing ENDLOOP; space _ UnRavelUSUs[Space.GetHandle[Space.PageFromLongPointer[object]]]; IF SpaceInCedarVM[space] THEN RemoveFromCedarVMSpaces[space] ELSE {Space.Kill[space]; Space.Delete[space]; nSpaces _ nSpaces - 1}}; ppzProcs: UZProcs _ [new: PPZNew, free: NIL]; ppzObject: UZObject _ [procs: @ppzProcs]; PPZNew: PROC[self: UZHandle, size: CARDINAL] RETURNS[LONG POINTER] = { RETURN[GetPermanentDataPages[(size + PageSize - 1)/PageSize]]; }; FreeableSpaceZone: PUBLIC UNCOUNTED ZONE _ LOOPHOLE[LONG[@fszObject]]; PermanentPageZone: PUBLIC UNCOUNTED ZONE _ LOOPHOLE[LONG[@ppzObject]]; PrivateHeapZone: PUBLIC UNCOUNTED ZONE _ LOOPHOLE[LONG[@shzObject]]; pilotHeapZone: UNCOUNTED ZONE; cedarHeapZone: UNCOUNTED ZONE; --Other parameters nSpaces: CARDINAL _ 0; -- # of spaces used thru this module SwapUnitSize: CARDINAL = 4; -- for data quanta largeSwapUnitSize: CARDINAL = 16; -- for larger stuff, e.g. the reference-count table allocStarted: BOOLEAN _ FALSE; discardedSpaces: ARRAY [1..maxNDiscardedSpaces] OF Space.Handle _ ALL[Space.nullHandle]; maxNDiscardedSpaces: CARDINAL = 30; nDiscarded: [0..maxNDiscardedSpaces] _ 0; spaceLost: BOOLEAN _ FALSE; nextCedarVMFilePage: CARDINAL _ 0; cedarVMFilePages: LONG INTEGER _ 0; cedarVMFile: File.Capability _ File.nullCapability; cedarVMSpaces: SDHandle _ NIL; cedarVMSpaceCache: SDHandle _ NIL; SDHandle: TYPE = LONG POINTER TO SDRec; SDRec: TYPE = RECORD[space: Space.Handle, next: SDHandle, firstCedarVMPage, nPages: NAT]; checkPointing: BOOLEAN _ FALSE; finishedCheckpointing: CONDITION; --Public procedures UnRavelUSUs: PUBLIC PROC[space: Space.Handle] RETURNS[Space.Handle] = { DO parent: Space.Handle; mapped: BOOLEAN; IF space = Space.mds OR space = Space.virtualMemory THEN ERROR; [parent: parent, mapped: mapped] _ Space.GetAttributes[space]; IF mapped THEN EXIT; space _ parent; ENDLOOP; RETURN[space]}; NotifyAllocatorReady: PUBLIC PROC = {cedarHeapZone _ UnsafeStorage.NewUZone[initialSize: 100000B--words--]; allocStarted _ TRUE}; IsAllocatorReady: PUBLIC PROC RETURNS[BOOLEAN] = {RETURN[allocStarted]}; -- PROCs for allocating blocks of data pages SpaceInCedarVM: PUBLIC PROC[sh: Space.Handle] RETURNS[BOOLEAN] = {file: File.Capability; sh _ UnRavelUSUs[sh]; file _ Space.GetWindow[sh].file; RETURN[cedarVMFilePages>0 AND file = cedarVMFile]}; GetPermanentDataPages: PUBLIC ENTRY PROC[nPages: CARDINAL, createUniformSwapUnits: BOOLEAN _ TRUE] RETURNS[LONG POINTER] = { ENABLE UNWIND => NULL; spH: Space.Handle; WHILE checkPointing DO WAIT finishedCheckpointing ENDLOOP; nPages _ ((nPages+PagesPerQuantum-1)/PagesPerQuantum)*PagesPerQuantum; spH _ FindCedarVMSpace[nPages]; IF spH = Space.nullHandle THEN {spH _ SpecialSpace.CreateAligned[nPages, Space.virtualMemory, PagesPerQuantum]; IF cedarVMFilePages>0 AND nPages <= (cedarVMFilePages-nextCedarVMFilePage) THEN {window: Space.WindowOrigin = [file: cedarVMFile, base: nextCedarVMFilePage]; nextCedarVMFilePage _ nextCedarVMFilePage + nPages; Space.Map[spH, window ! UNWIND => Space.Delete[spH]]; InsertInCedarVMSpaces[spH, window.base, nPages]} ELSE Space.Map[spH, Space.defaultWindow ! UNWIND => Space.Delete[spH]]; nSpaces _ nSpaces + 1}; IF createUniformSwapUnits AND nPages > largeSwapUnitSize THEN Space.CreateUniformSwapUnits[largeSwapUnitSize, spH ! UNWIND => Space.Delete[spH]]; RETURN[Space.LongPointer[spH]]}; GetCollectibleQuanta: PUBLIC ENTRY PROC[desired, needed: QuantumCount] RETURNS[qi: QuantumIndex, qc: QuantumCount] = { OPEN Space; ENABLE UNWIND => NULL; space: Handle; WHILE checkPointing DO WAIT finishedCheckpointing ENDLOOP; space _ FindCedarVMSpace[needed*PagesPerQuantum, TRUE]; IF space = Space.nullHandle THEN {qc _ desired; WHILE cedarVMFilePages>0 AND desired*PagesPerQuantum > (cedarVMFilePages-nextCedarVMFilePage) AND needed*PagesPerQuantum <= (cedarVMFilePages-nextCedarVMFilePage) DO qc _ desired _ MAX[needed, desired/2] ENDLOOP; {space _ SpecialSpace.CreateAligned[size: qc*PagesPerQuantum, parent: virtualMemory, alignment: PagesPerQuantum ! Space.InsufficientSpace => IF INTEGER[available] >= INTEGER[needed*PagesPerQuantum] THEN {qc _ available/PagesPerQuantum; RETRY} ELSE GOTO insufficientVM]; EXITS insufficientVM => RETURN WITH ERROR InsufficientVM}; IF qc*PagesPerQuantum > SwapUnitSize THEN CreateUniformSwapUnits[SwapUnitSize, space]; IF cedarVMFilePages>0 AND qc*PagesPerQuantum <= (cedarVMFilePages-nextCedarVMFilePage) THEN {window: Space.WindowOrigin = [file: cedarVMFile, base: nextCedarVMFilePage]; nextCedarVMFilePage _ nextCedarVMFilePage + qc*PagesPerQuantum; Space.Map[space, window ! Volume.InsufficientSpace => {Space.Delete[space]; ERROR InsufficientVM}]; InsertInCedarVMSpaces[space, window.base, qc*PagesPerQuantum]} ELSE Space.Map[space, Space.defaultWindow ! Volume.InsufficientSpace => {Space.Delete[space]; ERROR InsufficientVM}]; nSpaces _ nSpaces + 1} ELSE -- space # Space.nullHandle qc _ Space.GetAttributes[space].size/PagesPerQuantum; IF RTFlags.checking AND LOOPHOLE[space, CachedSpace.Handle].page MOD PagesPerQuantum # 0 THEN ERROR; qi _ LOOPHOLE[space, CachedSpace.Handle].page/PagesPerQuantum; RETURN[qi, qc]}; GetDataPagesFromNewSpace: PUBLIC ENTRY PROC[nPages: CARDINAL, createUniformSwapUnits: BOOLEAN _ TRUE] RETURNS[LONG POINTER] = { ENABLE UNWIND => NULL; spH: Space.Handle; WHILE checkPointing DO WAIT finishedCheckpointing ENDLOOP; nPages _ ((nPages+PagesPerQuantum-1)/PagesPerQuantum)*PagesPerQuantum; spH _ FindCedarVMSpace[nPages]; IF spH = Space.nullHandle THEN {spH _ SpecialSpace.CreateAligned[size: nPages, parent: Space.virtualMemory, alignment: PagesPerQuantum]; IF cedarVMFilePages>0 AND nPages <= (cedarVMFilePages-nextCedarVMFilePage) THEN {window: Space.WindowOrigin = [file: cedarVMFile, base: nextCedarVMFilePage]; nextCedarVMFilePage _ nextCedarVMFilePage + nPages; Space.Map[spH, window ! UNWIND => Space.Delete[spH]]; InsertInCedarVMSpaces[spH, window.base, nPages]} ELSE Space.Map[spH, Space.defaultWindow ! UNWIND => Space.Delete[spH]]; nSpaces _ nSpaces + 1}; IF createUniformSwapUnits AND nPages > largeSwapUnitSize THEN Space.CreateUniformSwapUnits[largeSwapUnitSize, spH ! UNWIND => Space.Delete[spH]]; RETURN[Space.LongPointer[spH]]}; -- used in RTBasesImpl for GetSubspaceQuanta (for NewCollectibleSubspace) GetQuantaFromNewSpace: PUBLIC ENTRY PROC[nQ: QuantumCount, createUniformSwapUnits: BOOLEAN _ TRUE] RETURNS[qi: QuantumIndex] = { OPEN Space; ENABLE UNWIND => NULL; space: Handle; WHILE checkPointing DO WAIT finishedCheckpointing ENDLOOP; space _ SpecialSpace.CreateAligned[nQ*PagesPerQuantum, virtualMemory, PagesPerQuantum ! Space.InsufficientSpace => ERROR InsufficientVM]; IF createUniformSwapUnits AND nQ*PagesPerQuantum > SwapUnitSize THEN CreateUniformSwapUnits[SwapUnitSize, space]; Map[space, defaultWindow ! Volume.InsufficientSpace => {Space.Delete[space]; ERROR InsufficientVM}]; nSpaces _ nSpaces + 1; qi _ LOOPHOLE[space, CachedSpace.Handle].page/PagesPerQuantum; RETURN[qi]}; GetDataPagesForGCTables: PUBLIC ENTRY PROC RETURNS[LONG POINTER] = -- get it on a 64K boundary { OPEN Space; np: PageCount _ 256; spHs: Handle; --swappable space spHp: Handle; --pinned space spH: Handle; WHILE checkPointing DO WAIT finishedCheckpointing ENDLOOP; spH _ SpecialSpace.CreateForCode[np, virtualMemory ! InsufficientSpace => ERROR InsufficientVM]; spHp_ Space.Create[1, spH, 0]; -- first page is a space by itself spHs_ Space.Create[np-1, spH, 1]; -- the rest IF cedarVMFilePages>0 AND 1 <= (cedarVMFilePages-nextCedarVMFilePage) THEN {window: Space.WindowOrigin = [file: cedarVMFile, base: nextCedarVMFilePage]; nextCedarVMFilePage _ nextCedarVMFilePage + 1; Space.Map[spHp, window ! Volume.InsufficientSpace => {Space.Delete[spH]; ERROR InsufficientVM}]; InsertInCedarVMSpaces[spHp, window.base, 1]} ELSE Space.Map[spHp, Space.defaultWindow ! Volume.InsufficientSpace => {Space.Delete[spH]; ERROR InsufficientVM}]; SpecialSpace.MakeResident[spHp]; IF np-1 > largeSwapUnitSize THEN Space.CreateUniformSwapUnits[largeSwapUnitSize, spHs ! UNWIND => Space.Delete[spH]]; IF cedarVMFilePages>0 AND np-1 <= (cedarVMFilePages-nextCedarVMFilePage) THEN {window: Space.WindowOrigin = [file: cedarVMFile, base: nextCedarVMFilePage]; nextCedarVMFilePage _ nextCedarVMFilePage + np-1; Space.Map[spHs, window ! Volume.InsufficientSpace => {Space.Delete[spH]; ERROR InsufficientVM}]; InsertInCedarVMSpaces[spHs, window.base, np-1]} ELSE Space.Map[spHs, Space.defaultWindow ! Volume.InsufficientSpace => {Space.Delete[spH]; ERROR InsufficientVM}]; nSpaces _ nSpaces + 3; RETURN[LongPointer[spH]]}; FindCedarVMSpace: INTERNAL PROC[np: Space.PageCount, minimum: BOOLEAN _ FALSE] RETURNS[Space.Handle] = { prev: SDHandle _ NIL; FOR p: SDHandle _ cedarVMSpaceCache, p.next UNTIL p = NIL DO IF (IF minimum THEN (np <= p.nPages) ELSE (np = p.nPages)) THEN {p.space _ SpecialSpace.CreateAligned[size: p.nPages, parent: Space.virtualMemory, alignment: PagesPerQuantum ! ANY => CONTINUE]; IF p.space = Space.nullHandle THEN RETURN[Space.nullHandle]; nSpaces _ nSpaces + 1; IF prev = NIL THEN cedarVMSpaceCache _ p.next ELSE prev.next _ p.next; p.next _ cedarVMSpaces; cedarVMSpaces _ p; Space.Map[p.space, [file: cedarVMFile, base: p.firstCedarVMPage]]; Space.Kill[p.space]; RETURN[p.space]} ELSE prev _ p; ENDLOOP; RETURN[Space.nullHandle] }; InsertInCedarVMSpaces: INTERNAL PROC[space: Space.Handle, firstPage, nPages: NAT] = { space _ UnRavelUSUs[space]; Space.Kill[space]; cedarVMSpaces _ pilotHeapZone.NEW[SDRec _ [space: space, next: cedarVMSpaces, firstCedarVMPage: firstPage, nPages: nPages]]}; CheckpointCedarVM: ENTRY PROC[p: PROC[Space.Handle]] = { ENABLE UNWIND => NULL; FOR sdh: SDHandle _ cedarVMSpaces, sdh.next UNTIL sdh = NIL DO p[sdh.space] ENDLOOP; RTSponge.Disable[]; --acquire the sponge. checkPointing _ TRUE}; RollbackCedarVM: ENTRY PROC[after: CedarSnapshot.After] = { RTSponge.Enable[]; -- release the sponge. checkPointing _ FALSE; BROADCAST finishedCheckpointing}; RemoveFromCedarVMSpaces: INTERNAL PROC[space: Space.Handle] = { prev: SDHandle _ NIL; FOR p: SDHandle _ cedarVMSpaces, p.next UNTIL p = NIL DO IF p.space = space THEN {IF prev = NIL THEN cedarVMSpaces _ p.next ELSE prev.next _ p.next; Space.DeleteSwapUnits[space]; p.next _ cedarVMSpaceCache; cedarVMSpaceCache _ p; nSpaces _ nSpaces - 1; Space.Kill[p.space]; Space.Delete[p.space]; p.space _ Space.nullHandle; RETURN} ELSE prev _ p; ENDLOOP; ERROR}; DeleteSpace: PUBLIC ENTRY PROC[space: Space.Handle] = { ENABLE UNWIND => NULL; WHILE checkPointing DO WAIT finishedCheckpointing ENDLOOP; IF SpaceInCedarVM[space] THEN RemoveFromCedarVMSpaces[UnRavelUSUs[space]] ELSE {nSpaces _ nSpaces - 1; Space.Kill[space]; Space.Delete[space]}}; -- PROCs for dealing with frames EnumerateGlobalFrames: PUBLIC PROC[proc: PROC[GlobalFrameHandle] RETURNS[BOOLEAN]] RETURNS[GlobalFrameHandle] = { FOR i: CARDINAL IN [1..SDDefs.SD[SDDefs.sGFTLength]] DO item: PrincOpsRuntime.GFTItem _ PrincOpsRuntime.GFT[LOOPHOLE[i]]; frame: GlobalFrameHandle _ PrincOpsRuntime.GetFrame[item]; IF frame # NullGlobalFrame AND item.epbias = 0 THEN {IF proc[frame] THEN RETURN[frame]}; ENDLOOP; RETURN[NullGlobalFrame]}; -- PROCs for dealing with RTProcesses SameCode: PUBLIC PROC [f1, f2: GlobalFrameHandle] RETURNS [RTOS.CodeMatch] = { fcb1, fcb2: PrincOps.FrameCodeBase; fcb1 _ f1.code; fcb2 _ f2.code; fcb1.out _ fcb2.out _ FALSE; RETURN[IF fcb1 = fcb2 THEN identical ELSE different]}; EstablishCedarVMFile: PUBLIC PROC[fc: File.Capability] = { IF cedarVMFile # File.nullCapability THEN ERROR; cedarVMFile _ fc; IF cedarVMFile # File.nullCapability THEN cedarVMFilePages _ File.GetSize[cedarVMFile]}; -- shortcuts PageFromLongPointer: PROC[lp: LONG POINTER] RETURNS [page: Space.PageNumber] = INLINE { OPEN LOOPHOLE[lp, num Environment.Long]; RETURN[highbits*Environment.wordsPerPage+lowbits/Environment.wordsPerPage]}; -- START HERE EstablishCedarVMFile[Directory.Lookup[fileName: "CedarVM.DontDeleteMe", permissions: File.read + File.write ! ANY => CONTINUE]]; pilotHeapZone _ Heap.Create[initial: 10--pages--, parent: Space.Create[100, Space.virtualMemory], increment: 10, swapUnit: 1]; CedarSnapshot.Register[CheckpointCedarVM, RollbackCedarVM]; END. ΚV– "Mesa" style˜Iprocš„ΟcHœΟk œžœžœžœžœžœ<žœžœHžœ žœžœžœžœ"žœ:žœžœ žœžœžœ»žœžœ?žœžœ žœžœ‘žœžœžœžœžœ2žœmžœžœ œžœžœžœœ žœžœžœžœžœžœž œžœžœžœžœ"žœžœž œžœžœžœžœžœžœžœžœžœ%žœžœžœ žœžœž œeΟnœžœžœžœžœžœžœžœžœžœžœ&žœžœžœ,Ÿœžœžœžœžœ žœ5žœžœžœžœoŸœžœžœžœžœžœžœMŸœžœžœžœžœ'žœžœžœžœYžœžœ(žœŽžœ1Ÿœžœžœžœžœžœžœ\žœž œžœžœžœ$žœž œžœžœžœ#žœž œžœžœžœ!ž œžœž œžœœ žœ %œžœœžœ4œžœžœžœžœžœ+žœ@žœžœžœžœžœYžœ"žœžœžœžœžœžœžœ@žœžœžœž œœŸ œžœžœžœžœ(žœ žœžœžœžœSžœžœžœ#žœžœŸœžœžœC œžœŸœžœžœžœžœ žœ-œŸœžœžœžœžœfžœžœŸœžœžœžœ žœEžœžœžœžœžœ žœžœžœ!žœžœžœžœ‚žœžœbžœžœCžœžœtžœ&žœFžœžœ#žœ7žœžœŸœžœžœžœ&žœ-žœžœžœžœžœžœžœžœ:žœžœžœžœžœLžœKžœžœžœ»žœžœžœ8žœ"žœ!žœžœžœžœžœžœžœ,žœ6žœžœGžœηžœnžœržœ9žœœEžœžœžœ!žœžœžœ žœ8žœŸœžœžœžœ žœHžœžœžœžœžœ žœžœžœ"žœžœžœžœ|žœžœλžœžœCžœΟžœtžœ&žœFžœžœ#žœ7žœžœ JœŸœžœžœžœhžœžœžœžœžœžœžœžœžœžœžœ“žœžœžœ*žœžœ;žœ8žœ Ÿœžœžœžœžœžœžœ œžœFœ#œžœžœžœžœžœF#œ/ œžœžœ4žœΕžœWžœ΅žœBžœ!žœQžœžœžœ7žœ±žœZžœ΅žœ6žœŸœžœžœžœžœ žœ(žœžœ)žœžœ žœžœžœ žœžœžœœžœžœžœžœžœWžœžœžœ3žœ†žœžœžœžœ!Ÿœžœžœ)žœcžœžŸœžœžœžœžœžœžœžœ)žœžœ žœžœœžœ Ÿœžœžœ9œžœž œ Ÿœžœžœ/žœžœ%žœžœ žœžœžœžœžœžœ.žœνžœžœžœžœ Ÿ œžœžœžœžœžœžœžœžœžœžœžœžœ4žœj!œŸœžœžœžœžœžœ žœžœžœžœ žœžœ9žœžœQžœžœžœ žœ žœžœžœžœ&œŸœžœžœžœžœxžœžœžœ žœ žœŸœžœžœžœ#žœžœžœ(žœ7 œŸœžœžœžœžœžœžœžœ žœJœΏžœžœ, œσžœ˜ς”—…—JtRΠ