-- SegmentsA.Mesa Edited by Sandman on September 4, 1980 5:59 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, LongCOPY], NucleusOps USING [], Region USING [Index, Page], SegmentDefs USING [ AccessOptions, AddressFromPage, AllocInfo, Append, ChangeDataToFileSegment, DataSegmentAddress, DataSegmentHandle, DefaultAccess, DefaultBase, DefaultMDSBase, DefaultPages, DeleteDataSegment, DeleteFileSegment, EasyDown, EnumerateFileSegments, FileAccessError, FileError, FileHandle, FileHint, FileSegmentClass, FileSegmentHandle, GetEndOfFile, HardDown, LongAddressFromPage, MakeDataSegment, MaxSegs, NewDataSegment, Object, ObjectHandle, ObjectType, PageCount, PageNumber, Read, SegCount, SegLockCount, SegmentHandle, SegmentLocation, SegmentType, SetFileAccess, SwapError, Unlock, Write], Storage USING [PagesForWords], SwapperOps USING [ AllocateObject, MapVM, mdsIndex, regions, ValidateObject], SystemDefs USING []; SegmentsA: PROGRAM IMPORTS SwapperOps, DiskDefs, InlineDefs, SegmentDefs, Storage EXPORTS SwapperOps, SegmentDefs, NucleusOps, Storage, SystemDefs 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; FileSegmentAddress: PUBLIC PROCEDURE [seg: FileSegmentHandle] RETURNS [POINTER] = BEGIN IF ~seg.swappedin THEN ERROR SwapError[seg]; RETURN[AddressFromPage[seg.VMpage]] END; SwapUp: PUBLIC PROCEDURE [seg: FileSegmentHandle] = BEGIN OPEN AltoDefs, seg; SwapperOps.ValidateObject[seg]; IF swappedin AND write THEN WITH s: seg SELECT FROM disk => IF s.VMpage <= MaxMDSPage THEN BEGIN IF s.hint.page # base OR s.hint.da = AltoFileDefs.eofDA THEN [] _ PositionSeg[@s, FALSE]; SwapperOps.MapVM[@s, WriteD]; END ELSE BEGIN pages: CARDINAL = s.pages; mdsFileSeg: FileSegmentHandle _ NewFileSegment[ file, s.base, pages, Read + Write]; mdsDataSeg: DataSegmentHandle _ MakeDataSegment[ DefaultMDSBase, pages, EasyDown]; InlineDefs.LongCOPY[ from: LongAddressFromPage[s.VMpage], to: LongAddressFromPage[mdsDataSeg.VMpage], nwords: pages*PageSize]; SegmentDefs.ChangeDataToFileSegment[mdsDataSeg, mdsFileSeg]; Unlock[mdsFileSeg]; DeleteFileSegment[mdsFileSeg]; END; remote => s.proc[@s, 1]; ENDCASE; RETURN 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; -- 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; GetPages: PROCEDURE [npages: CARDINAL, info: AllocInfo] RETURNS [POINTER] = BEGIN RETURN[DataSegmentAddress[MakeDataSegment[DefaultMDSBase, npages, info]]] END; AllocatePages: PUBLIC PROCEDURE [npages: CARDINAL] RETURNS [POINTER] = BEGIN RETURN[GetPages[npages, EasyDown]] END; Pages, AllocateResidentPages: PUBLIC PROC [npages: CARDINAL] RETURNS [POINTER] = BEGIN RETURN[GetPages[npages, HardDown]] END; AllocateSegment: PUBLIC PROCEDURE [nwords: CARDINAL] RETURNS [POINTER] = BEGIN RETURN[GetPages[Storage.PagesForWords[nwords], EasyDown]] END; Words, AllocateResidentSegment: PUBLIC PROC [nwords: CARDINAL] RETURNS [POINTER] = BEGIN RETURN[GetPages[Storage.PagesForWords[nwords], HardDown]] END; SegmentSize: PUBLIC PROCEDURE [base: POINTER] RETURNS [CARDINAL] = BEGIN seg: DataSegmentHandle = VMtoDataSegment[base]; RETURN[IF seg = NIL THEN 0 ELSE seg.pages*AltoDefs.PageSize] END; FreePages, FreeSegment, FreeWords: PUBLIC PROCEDURE [base: POINTER] = BEGIN seg: DataSegmentHandle = VMtoDataSegment[base]; IF seg # NIL THEN DeleteDataSegment[seg]; RETURN END; VMtoDataSegment: PUBLIC PROCEDURE [a: POINTER] RETURNS [DataSegmentHandle] = BEGIN seg: SegmentHandle _ VMtoSegment[a]; IF seg = NIL THEN RETURN[NIL]; WITH s: seg SELECT FROM data => RETURN[@s]; ENDCASE; RETURN[NIL]; END; VMtoSegment: PUBLIC PROCEDURE [a: POINTER] RETURNS [SegmentHandle] = BEGIN pg: PageNumber = LOOPHOLE[a, CARDINAL]/AltoDefs.PageSize; IF a = NIL THEN RETURN[NIL]; RETURN[regions[mdsIndex].status[pg].seg]; END; END.