-- VolAllocMapImpl.mesa (last edited by: Jose on: March 23, 1981 5:28 PM) DIRECTORY Environment USING [bitsPerWord, wordsPerPage], File USING [Capability, ID, PageNumber, Type], FileInternal USING [Descriptor, FilePtr, maxPermissions, PageGroup], FMPrograms, Inline USING [BITAND, BITSHIFT, BITXOR], LabelTransfer USING [VerifyLabels, WriteLabels], LogicalVolume USING [Free, Handle, PageNumber, Vam, Vfm], PhysicalVolume USING [ErrorType], PilotFileTypes USING [PilotVFileType, tFreePage], SimpleSpace USING [Create, ForceOut, Map, Page, Unmap], Space USING [Handle, WindowOrigin], Utilities USING [LongPointerFromPage, ShortCARDINAL], VolAllocMap, Volume USING [ID, nullID]; VolAllocMapImpl: MONITOR -- to protect VAM buffer; volume page is protected by callers IMPORTS Inline, LabelTransfer, LogicalVolume, SimpleSpace, Utilities EXPORTS FMPrograms, PhysicalVolume, VolAllocMap SHARES File = BEGIN OPEN Inline; -- The following is exported to PhysicalVolume as compiler "features" prevent it from -- being exported by PhysicalVolumeImpl. Error: PUBLIC ERROR [PhysicalVolume.ErrorType] = CODE; FilePtr: TYPE = FileInternal.FilePtr; GroupPtr: TYPE = POINTER TO FileInternal.PageGroup; LvHandle: TYPE = LogicalVolume.Handle; -- common buffer used by procedures to Access VAM; protected by monitor bufferHandle: Space.Handle = SimpleSpace.Create[1, hyperspace]; bufferPointer: LONG POINTER = Utilities.LongPointerFromPage[ SimpleSpace.Page[bufferHandle]]; -- Whenever lvID#Volume.nullID, the buffer is (being) mapped. Therefore, if the ID is -- wrong and non-null, one can automatically unmap. See Close, MapInternal. currentBufferContents: RECORD [ lvID: Volume.ID, page: LogicalVolume.PageNumber] ← [Volume.nullID, ]; bitsPerPage: CARDINAL = (Environment.bitsPerWord*Environment.wordsPerPage); VolAllocMapImplError: ERROR [{setSizeToZeroPageGroup}] = CODE; -- This code assumes various powers of 2 (because of the truncation). AccessVAM: PUBLIC PROCEDURE [ vol: LvHandle, volumePage: LogicalVolume.PageNumber, set: BOOLEAN, clear: BOOLEAN] RETURNS [busy: BOOLEAN] = -- set, clear or read one bit of vam, always returns the (previous) value; BEGIN bit: WORD; vamPage: LogicalVolume.PageNumber; word: LONG POINTER TO WORD; DoIt: ENTRY PROCEDURE = INLINE BEGIN MapVamPageInternal[vol.vID, vamPage, Vam[vol]]; busy ← (0 # Inline.BITAND[word↑, bit]); IF (busy AND clear) OR (~busy AND set) THEN BEGIN word↑ ← Inline.BITXOR[word↑, bit]; vol.freePageCount ← vol.freePageCount + (IF busy THEN 1 ELSE -1); END; IF clear THEN vol.lowerBound ← MIN[volumePage, vol.lowerBound]; -- keep lowerBound to help allocator IF set AND volumePage = vol.lowerBound THEN vol.lowerBound ← vol.lowerBound+1; END; -- The bit and word calculations can correctly be done by truncating first bit ← Inline.BITSHIFT[ 1, Utilities.ShortCARDINAL[volumePage] MOD Environment.bitsPerWord]; word ← bufferPointer + (Utilities.ShortCARDINAL[volumePage]/Environment.bitsPerWord) MOD Environment.wordsPerPage; vamPage ← vol.vamStart + volumePage/bitsPerPage; DoIt[]; END; -- Allocate a group of pages and write labels (group is a modifiable hint) AllocPageGroup: PUBLIC PROCEDURE [ vol: LvHandle, filePtr: FilePtr, groupPtr: GroupPtr, createFile: BOOLEAN] = BEGIN OPEN groupPtr; skip: [0..1] = IF ~createFile AND filePage = 0 THEN 1 ELSE 0; offset: LONG CARDINAL; startPage: LogicalVolume.PageNumber = MAX[volumePage, vol.lowerBound]; IF createFile OR filePage # 0 THEN BEGIN volumePage ← startPage; WHILE AccessVAM[vol, volumePage, TRUE, FALSE] DO --search for unbusy page IF (volumePage ← volumePage + 1) >= vol.volumeSize - 1 THEN volumePage ← vol.lowerBound; -- avoid the following error rather thatn backing out IF volumePage = startPage THEN ERROR; --Volume.InsufficientSpace-- ENDLOOP; END; FOR offset ← 0, offset + 1 WHILE offset < nextFilePage - filePage DO IF volumePage + offset >= vol.volumeSize THEN EXIT; IF offset # 0 THEN IF AccessVAM[vol, volumePage + offset, TRUE, FALSE] THEN EXIT; --first is set ENDLOOP; WITH filePtr SELECT FROM local => IF type IN PilotFileTypes.PilotVFileType THEN filePage ← volumePage; ENDCASE; nextFilePage ← filePage + offset; -- side effect IF createFile AND nextFilePage = 0 -- creating only the attribute label page THEN offset ← 1; [] ← LabelTransfer.VerifyLabels[ filePtr↑, FileInternal.PageGroup[0, volumePage, skip], FALSE, TRUE]; [] ← LabelTransfer.VerifyLabels[ FreeDescriptor[vol], [volumePage + skip, volumePage + skip, volumePage + offset], FALSE, TRUE]; -- set new file size WITH filePtr SELECT FROM local => size ← nextFilePage; ENDCASE => ERROR; [] ← LabelTransfer.WriteLabels[ filePtr↑, [filePage, volumePage, filePage + offset]]; END; FreeDescriptor: PROCEDURE [v: LvHandle] RETURNS [FileInternal.Descriptor] = INLINE BEGIN RETURN[ [LogicalVolume.Free[v], v.vID, local[FALSE, FALSE, v.volumeSize, PilotFileTypes.tFreePage]]]; END; -- free a page group (assumes calls to label operations with zero sizes are noops) -- This is closely related to SetSize and Delete in FileImpl, as well as VolFileMap.DeletePageGroup FreePageGroup: PUBLIC PROCEDURE [ vol: LvHandle, filePtr: FilePtr, groupPtr: GroupPtr, deleteFile: BOOLEAN] = BEGIN Blast: PROCEDURE [g: FileInternal.PageGroup] = BEGIN p, nextVolumePage: LogicalVolume.PageNumber; nextVolumePage ← g.volumePage + g.nextFilePage - g.filePage; FOR p ← g.volumePage, p + 1 WHILE p < nextVolumePage DO [] ← AccessVAM[vol, p, FALSE, TRUE]; ENDLOOP; [] ← LabelTransfer.WriteLabels[ FreeDescriptor[vol], [g.volumePage, g.volumePage, nextVolumePage]]; END; -- Always verify labels; max is for zero size file [0, ?, 0] [] ← LabelTransfer.VerifyLabels[ filePtr↑, [groupPtr.filePage, groupPtr.volumePage, MAX[groupPtr.nextFilePage, 1]], FALSE, TRUE]; WITH filePtr SELECT FROM local => size ← groupPtr.filePage; ENDCASE => ERROR; SELECT TRUE FROM groupPtr.filePage # 0 => -- if group start#0, always blast Blast[groupPtr↑]; groupPtr.nextFilePage # 0 -- AND g.filePage=0-- => -- Set to zero size BEGIN Blast[ [groupPtr.filePage + 1, groupPtr.volumePage + 1, groupPtr.nextFilePage]]; -- we could skip the write, but then we'd have to mess around with correcting -- zero size files [] ← LabelTransfer.WriteLabels[filePtr↑, [0, groupPtr.volumePage, 1]]; END; ENDCASE -- g.filePage=g.nextPage=0-- => IF deleteFile THEN Blast[[0, groupPtr.volumePage, 1]] --delete it-- ELSE ERROR VolAllocMapImplError[setSizeToZeroPageGroup]; END; Vam: PROCEDURE [v: LvHandle] RETURNS [File.ID] = INLINE { RETURN[LogicalVolume.Vam[v]]; }; Vfm: PROCEDURE [v: LvHandle] RETURNS [File.ID] = INLINE { RETURN[LogicalVolume.Vfm[v]]; }; -- ENTRY PROCEDURES (Also see local proc in AccessVAM) -- Force out/ deallocate allocation map Close: PUBLIC ENTRY PROCEDURE [final: BOOLEAN] = BEGIN IF currentBufferContents.lvID # Volume.nullID THEN IF final THEN BEGIN SimpleSpace.Unmap[bufferHandle]; currentBufferContents.lvID ← Volume.nullID; END ELSE SimpleSpace.ForceOut[bufferHandle]; END; -- INTERNAL PROCEDURE MapVamPageInternal: INTERNAL PROCEDURE [ vID: Volume.ID, vamPage: LogicalVolume.PageNumber, vamID: File.ID] = INLINE BEGIN IF currentBufferContents.lvID # vID THEN BEGIN IF currentBufferContents.lvID # Volume.nullID THEN SimpleSpace.Unmap[bufferHandle]; currentBufferContents.lvID ← vID; -- and fall through for map... END ELSE IF currentBufferContents.page # vamPage THEN SimpleSpace.Unmap[bufferHandle] -- and fall through for map... ELSE -- vids equal and pages equal, so just.... -- RETURN; currentBufferContents.page ← vamPage; SimpleSpace.Map[ bufferHandle, Space.WindowOrigin[ File.Capability[vamID, FileInternal.maxPermissions], vamPage], FALSE]; END; END. LOG Time: April 13, 1978 3:32 PM By: Purcell Action: Created file Time: June 23, 1978 12:27 PM By: Purcell Action: page 0 special case in alloc/free group Time: September 27, 1978 5:15 PM By: Purcell Action: don't raise signals and limit bound Time: October 19, 1978 2:45 PM By: Purcell Action: CR 20.103: Use FileTypes directly Time: March 20, 1979 9:30 PM By: Redell Action: Convert to Mesa 5.0 Time: August 1, 1979 3:10 PM By: Redell Action: Convert to use FilePageLabel Time: August 8, 1979 12:05 PM By: Redell Action: Bug fix: wraparound condition in AllocPageGroup was off by one: ran off end of volume. Time: August 29, 1979 10:05 AM By: Forrest Action: Changed to match new interface and new FileMgr organization. Time: September 3, 1979 12:08 PM By: Forrest Action: Used LogicalVolume.free, vam, vfm vs Opens. Time: September 4, 1979 11:04 AM By: Forrest Action: Fixed up buffer allocation/deallocation. Time: October 1, 1979 5:56 PM By: Forrest Action: Moved out Open to scavanger. Time: January 9, 1980 5:43 PM By: Gobbel Action: Change for new LabelTransfer interface: VerifyLabels now returns two values. Time: March 7, 1980 8:49 PM By: Forrest Action: Lexically change types for New Logical Volume; deleted handle from Close. Time: June 17, 1980 10:12 AM By: Luniewski Action: Exprt PhysicalVolume.Error. Time: January 12, 1981 1:37 PM By: Luniewski Action: New LabelTransfer interface. Time: March 23, 1981 5:28 PM By: Jose Action: Remove signal LabelError, remove handling of error from VerifyLabels.