-- SegmentsA.Mesa Edited by Sandman on August 18, 1980 3:33 PM -- Copyright Xerox Corporation 1979, 1980 DIRECTORY AltoDefs USING [MaxMDSPage, PageSize], AltoFileDefs USING [CFA, eofDA, FA, FP, vDA], DiskDefs USING [DiskCheckError, DiskPageDesc, DiskRequest, nSectors, SwapPages], InlineDefs USING [BITAND, DIVMOD, HighHalf, LongDiv, LowHalf], NucleusOps USING [], ProcessDefs USING [DisableInterrupts, EnableInterrupts], Region USING [Index, Page, PagesPerRegion], SegmentDefs USING [ AccessOptions, AddressFromPage, AllocInfo, Append, DataSegmentAddress, DataSegmentHandle, DefaultAccess, DefaultBase, DefaultPages, DeleteDataSegment, EasyDown, EnumerateFileSegments, FileAccessError, FileError, FileHandle, FileHint, FileSegmentClass, FileSegmentHandle, GetEndOfFile, MakeDataSegment, MaxRefs, MaxSegs, NewDataSegment, Object, ObjectHandle, ObjectType, OpenFile, PageFromAddress, PageCount, PageNumber, Read, RefCount, ReleaseFile, SegCount, SegLockCount, SegmentHandle, SegmentLocation, SegmentType, SetFileAccess, SwapError, SwapOut, Write], SwapperOps USING [AllocateObject, LiberateObject, regions, UpdateVM]; SegmentsA: PROGRAM IMPORTS SwapperOps, DiskDefs, InlineDefs, ProcessDefs, SegmentDefs EXPORTS SwapperOps, SegmentDefs, NucleusOps SHARES SegmentDefs = BEGIN OPEN AltoFileDefs, SwapperOps, SegmentDefs; InvalidSegmentSize: PUBLIC SIGNAL [pages: PageCount] = CODE; NewFileSegment: PUBLIC PROCEDURE [ file: FileHandle, base: PageNumber, pages: PageCount, access: AccessOptions] RETURNS [seg: FileSegmentHandle] = BEGIN OPEN InlineDefs; IF access = DefaultAccess THEN access ← Read; IF file.segcount = MaxSegs THEN ERROR FileError[file]; IF BITAND[access, Append] # 0 THEN ERROR FileAccessError[file]; IF base = DefaultBase THEN base ← 1; IF pages = DefaultPages THEN pages ← GetEndOfFile[file].page - base + 1; IF pages ~IN (0..AltoDefs.MaxMDSPage + 1] THEN ERROR InvalidSegmentSize[pages]; SetFileAccess[file, access]; seg ← LOOPHOLE[AllocateObject[SIZE[file segment Object]]]; seg↑ ← Object[ busy: FALSE, body: segment[ VMpage: 0, info: file[ swappedin: FALSE, write: BITAND[access, Write] # 0, class: other, inuse: FALSE, lock: 0, file: file, base: base, pages: pages, location: disk[FileHint[eofDA, 0]]]]]; file.segcount ← file.segcount + 1; RETURN END; DeleteFileSegment: PUBLIC PROCEDURE [seg: FileSegmentHandle] = BEGIN file: FileHandle ← seg.file; SwapOut[seg]; LiberateObject[seg]; file.segcount ← file.segcount - 1; IF file.segcount = 0 THEN ReleaseFile[file]; RETURN END; FileSegmentAddress: PUBLIC PROCEDURE [seg: FileSegmentHandle] RETURNS [POINTER] = BEGIN IF ~seg.swappedin THEN ERROR SwapError[seg]; RETURN[AddressFromPage[seg.VMpage]] END; -- Segment Positioning PositionSeg: PUBLIC PROCEDURE [seg: FileSegmentHandle, useseg: BOOLEAN] RETURNS [BOOLEAN] = BEGIN -- returns TRUE if it read a non-null page into the segment. cfa: CFA; buf: DataSegmentHandle; buffer: POINTER; WITH s: seg SELECT FROM disk => BEGIN IF s.hint.da = eofDA AND s.base > 8 AND s.file.segcount > 1 THEN FindSegHint[@s]; IF s.hint.da = eofDA OR s.hint.page # s.base THEN BEGIN buffer ← IF useseg THEN AddressFromPage[s.VMpage] ELSE DataSegmentAddress[buf ← NewDataSegment[DefaultBase, 1]]; cfa.fp ← s.file.fp; cfa.fa ← FA[s.hint.da, s.hint.page, 0]; [] ← JumpToPage[ @cfa, s.base, buffer ! UNWIND => IF ~useseg THEN DeleteDataSegment[buf]]; IF ~useseg THEN DeleteDataSegment[buf]; IF cfa.fa.page # s.base THEN ERROR SwapError[@s]; s.hint ← FileHint[cfa.fa.da, cfa.fa.page]; RETURN[useseg AND cfa.fa.byte # 0]; END; END; ENDCASE; RETURN[FALSE] END; FindSegHint: PUBLIC PROCEDURE [seg: FileSegmentHandle] = BEGIN CheckHint: PROCEDURE [other: FileSegmentHandle] RETURNS [BOOLEAN] = BEGIN WITH o: other SELECT FROM disk => BEGIN IF o.file = seg.file AND o.hint.da # eofDA AND o.hint.page IN (hint.page..seg.base] THEN hint ← o.hint; RETURN[hint.page = seg.base] END; ENDCASE; RETURN[FALSE] END; hint: FileHint; WITH s: seg SELECT FROM disk => BEGIN hint ← s.hint; [] ← EnumerateFileSegments[CheckHint]; s.hint ← hint; END; ENDCASE; RETURN END; GetFileSegmentDA: PUBLIC PROCEDURE [seg: FileSegmentHandle] RETURNS [vDA] = BEGIN WITH s: seg SELECT FROM disk => BEGIN [] ← PositionSeg[seg, FALSE]; RETURN[s.hint.da]; END; ENDCASE; RETURN[AltoFileDefs.eofDA] END; SetFileSegmentDA: PUBLIC PROCEDURE [seg: FileSegmentHandle, da: vDA] = BEGIN WITH s: seg SELECT FROM disk => s.hint ← FileHint[da, s.base]; ENDCASE; RETURN END; -- File Positioning jump: INTEGER = 10*DiskDefs.nSectors; InvalidFP: PUBLIC SIGNAL [fp: POINTER TO FP] = CODE; JumpToPage: PUBLIC PROCEDURE [ cfa: POINTER TO CFA, page: PageNumber, buf: POINTER] RETURNS [prev, next: vDA] = BEGIN OPEN DiskDefs; desc: DiskPageDesc; da: vDA ← cfa.fa.da; startpage: PageNumber; direction: INTEGER ← 1; firstpage: PageNumber ← cfa.fa.page; arg: swap DiskRequest ← DiskRequest[ buf, @da, , , @cfa.fp, TRUE, ReadD, ReadD, TRUE, swap[@desc]]; BEGIN IF da = eofDA THEN GO TO reset; SELECT firstpage - page FROM <= 0 => NULL; = 1, < firstpage/10 => direction ← -1; ENDCASE => GO TO reset; EXITS reset => BEGIN firstpage ← 0; da ← cfa.fp.leaderDA; END; END; BEGIN ENABLE DiskCheckError --[page]-- => BEGIN IF page # startpage THEN RESUME ; IF startpage = 0 THEN GO TO failed; firstpage ← 0; da ← cfa.fp.leaderDA; direction ← 1; RETRY; END; IF da = eofDA THEN GO TO failed; startpage ← firstpage; UNTIL da = eofDA DO arg.firstPage ← firstpage; arg.lastPage ← IF direction < 0 THEN firstpage ELSE MIN[page, firstpage + jump - 1]; [] ← SwapPages[@arg]; IF desc.page = page THEN EXIT; da ← IF direction < 0 THEN desc.prev ELSE desc.next; firstpage ← desc.page + direction; ENDLOOP; cfa.fa ← FA[desc.this, desc.page, desc.bytes]; RETURN[desc.prev, desc.next]; EXITS failed => ERROR InvalidFP[@cfa.fp]; END; END; ChangeDataToFileSegment: PUBLIC PROCEDURE [ dataseg: DataSegmentHandle, fileseg: FileSegmentHandle] = BEGIN IF dataseg.pages # fileseg.pages OR ~fileseg.write OR fileseg.swappedin OR fileseg.file.swapcount = MaxRefs THEN SIGNAL SwapError[fileseg]; IF ~fileseg.file.open THEN OpenFile[fileseg.file]; ProcessDefs.DisableInterrupts[]; fileseg.swappedin ← TRUE; fileseg.lock ← fileseg.lock + 1; fileseg.file.swapcount ← fileseg.file.swapcount + 1; SwapperOps.UpdateVM[ base: fileseg.VMpage ← dataseg.VMpage, pages: fileseg.pages, seg: fileseg]; ProcessDefs.EnableInterrupts[]; SwapperOps.LiberateObject[dataseg]; END; InvalidLongPointer: PUBLIC ERROR [lp: LONG UNSPECIFIED] = CODE; ValidateLongPointer: PUBLIC PROCEDURE [a: LONG UNSPECIFIED] = BEGIN page: PageNumber; index: Region.Index; IF InlineDefs.HighHalf[a] > LAST[Region.Index] THEN ERROR InvalidLongPointer[a]; page ← InlineDefs.LongDiv[a, AltoDefs.PageSize]; [quotient: index] ← InlineDefs.DIVMOD[page, Region.PagesPerRegion]; IF regions[index] = NIL THEN ERROR InvalidLongPointer[a]; END; LongVMtoSegment: PUBLIC PROCEDURE [a: LONG POINTER] RETURNS [SegmentHandle] = BEGIN relPage: Region.Page; ValidateLongPointer[a]; relPage ← PageFromAddress[InlineDefs.LowHalf[a]]; RETURN[regions[InlineDefs.HighHalf[a]].status[relPage].seg] END; LongVMtoFileSegment: PUBLIC PROCEDURE [a: LONG POINTER] RETURNS [FileSegmentHandle] = BEGIN seg: SegmentHandle ← LongVMtoSegment[a]; IF seg = NIL THEN RETURN[NIL]; WITH s: seg SELECT FROM file => RETURN[@s]; ENDCASE; RETURN[NIL]; END; END.