--Last edited on June 1, 1982 4:00 PM by GWiliams
--store segment handle in ddMgr object now
--A DDMgr is an object for managing pages of the DiskDescriptor (DD) files
--on one or more disks. The default one is created by calling:
--ddMgr ← TFSCreateDDMgr[]
DIRECTORY
MiscDefs: FROM "miscdefs" USING [Zero],
SegmentDefs USING [NewDataSegment, DefaultBase, DeleteDataSegment, SegmentAddress],
SystemDefs: FROM "systemdefs" USING [AllocateHeapNode, FreeHeapNode],
TridentDefs: FROM "tridentdefs";
--A DDMgr is an object for managing pages of the DiskDescriptor (DD) files
-- on one or more disks. The default one is created by calling:
--ddMgr ← TFSCreateDDMgr[zone]
-- Thereafter, the following operations are defined on it:
--OpenDD[ddMgr, disk]
--Adds disk to the set of DDs managed by ddMgr.
--LockDD[ddMgr, disk]
--Locks out all other access to the DD on the specified disk.
--buf = ReadDDPage[ddMgr, disk, page]
--Returns a pointer to a copy (in memory) of the specified
--DD page on the specified disk. The TFSKD is in page 1
--and the bit map is in pages 2 through n (n is at most 5).
--Guarantees that buf will not move until either the next
--ReadDDPage or UnlockDD. The DD must be locked.
--UnlockDD[ddMgr, disk, na, dirty ]
--Unlocks a DD previously locked. If dirty is true, marks
--as dirty the page most recently read by ReadDDPage.
--FlushDD[ddMgr, disk]
--Flush any dirty DD pages out to the specified disk.
--The DD must NOT be locked.
--CloseDD[ddMgr, disk]
--Removes disk from the set of DDs managed by ddMgr.
--It is the caller’s responsibility to do a FlushDD first.
--DestroyDDMgr[ddMgr]
--Destroys ddMgr.
TfsDDmgr: PROGRAM
IMPORTS MiscDefs, SegmentDefs, SystemDefs, TridentDefs
EXPORTS TridentDefs =
BEGIN OPEN SegmentDefs, SystemDefs, TridentDefs;
TfsCreateDDmgr: PUBLIC PROCEDURE [] RETURNS [ddMgr: ddMgrPtr] =
-- This implementation of the DDMgr has the following properties:
-- (1) One page is permanently allocated to serve as a buffer for all DDs.
-- (2) There is only a single lock for the entire DDMgr, not one per DD.
-- (3) A dirty page is written out only if (a) the buffer is needed for
-- another DD page, or (b) an explicit FlushDD is done.
BEGIN
ddMgr ← AllocateHeapNode[lDDmgr];-- allocate storage for the manager
MiscDefs.Zero[ddMgr, lDDmgr];-- clear it
ddMgr.OpenDD ← Noop;
ddMgr.LockDD ← TfsLockDD;-- store the procedures
ddMgr.ReadDDPage ← TfsReadDDPage;
ddMgr.UnlockDD ← TfsUnlockDD;
ddMgr.FlushDD ← TfsFlushDD;
ddMgr.CloseDD ← TfsCloseDD;
ddMgr.DestroyDDMgr ← TfsDestroyDDMgr;
--ddMgr.buffer ← AllocateHeapNode[TFSwordsPerPage];
--get 1K words w/no overhead
ddMgr.bufferSegment ←SegmentDefs.NewDataSegment[DefaultBase, 4];
ddMgr.buffer ← SegmentDefs.SegmentAddress[ddMgr.bufferSegment];
ddMgr.zone ← NIL;-- not needed?
ddMgr.locked ← FALSE;
ddMgr.dirty ← FALSE;
ddMgr.disk ← NIL;-- This is a closeDD
RETURN [ddMgr];
END;-- of TfsCreateDDMgr
TfsLockDD: PUBLIC PROCEDURE [ddMgr: ddMgrPtr, disk: tfsdskPtr] =
-- Allow only single thread use of the DD
BEGIN
WHILE ddMgr.locked DO NULL ENDLOOP;-- wait until it’s free
ddMgr.locked ← TRUE;-- lock it for our own use
END;-- of TfsLockDD
TfsReadDDPage: PUBLIC PROCEDURE [ddMgr: ddMgrPtr, disk: tfsdskPtr, page: INTEGER] RETURNS [buffer: POINTER] =
-- If the disk or page number is not current then read it into buffer (writing current page if it’s dirty).
BEGIN
IF disk # ddMgr.disk OR page # ddMgr.page THEN
BEGIN
IF ddMgr.dirty THEN TransferDDPage[ddMgr, dcWriteD];
ddMgr.disk ← disk;
ddMgr.page ← page;
TransferDDPage[ddMgr, dcReadLD];-- read in the bit map
END;
RETURN [ddMgr.buffer];
END;-- of TfsReadDDPage
TfsUnlockDD: PUBLIC PROCEDURE [ddMgr: ddMgrPtr, disk: tfsdskPtr, dirty: BOOLEAN] =
-- Unlock the DD and optionally set it dirty regardless of it state
BEGIN
IF dirty THEN ddMgr.dirty ← TRUE;-- dirty was optional arg
ddMgr.locked ← FALSE;
END;-- of TfsUnlockDD
TfsFlushDD: PUBLIC PROCEDURE [ddMgr: ddMgrPtr, disk: tfsdskPtr] =
-- Write the bit map if its dirty
BEGIN
TfsLockDD[ddMgr, disk];-- lock the DD
IF ddMgr.dirty THEN TransferDDPage[ddMgr, dcWriteD];
TfsUnlockDD[ddMgr, disk, FALSE];
END;-- of TfsFlushDD
TfsCloseDD: PUBLIC PROCEDURE [ddMgr: ddMgrPtr, disk: tfsdskPtr] =
-- If we’re on the right disk, close it
BEGIN
IF ddMgr.disk = disk THEN ddMgr.disk ← NIL;
END;-- of TfsCloseDD
TfsDestroyDDMgr: PUBLIC PROCEDURE [ddMgr: ddMgrPtr] =
-- free the storage for the bitmap’s buffer, then free the storage for the mgr itself
BEGIN
--FreeHeapNode[ddMgr.buffer];
SegmentDefs.DeleteDataSegment[ddMgr.bufferSegment];
FreeHeapNode[ddMgr];
END;-- of TfsDestroyDDMgr
Noop: PROCEDURE [ptr: POINTER] RETURNS [ddMgr: ddMgrPtr] =
-- Dummy proc (but it works)
BEGIN
END;-- of Noop
TransferDDPage: PROCEDURE[ddMgr: ddMgrPtr, action: CARDINAL] =
-- prepare a call to TfsActOnPages to read or write the bitmap
BEGIN
numChars, page, i: INTEGER;
numcharsPtr: POINTER;
disk: tfsdskPtr;
fpTfsDD: FP;
caS: DESCRIPTOR FOR ARRAY OF POINTER;
daS: DESCRIPTOR FOR ARRAY OF PAGE;
pages: ARRAY [0..6) OF PAGE;--ARRAY of vDA
numChars ← 2048;
numcharsPtr ← @numChars;
page ← ddMgr.page;
disk ← ddMgr.disk;
-- Build an array of disk addresses for the disk descriptor
FOR i IN [0..lTfsBT] DO
--pages[i] ← disk.tfskd.vdadiskDD[i+1];---- vDA’s of DD
pages[i+1] ← disk.tfskd.vdadiskDD[i+1];-- vDA’s of DD
ENDLOOP;--change necessary because TfsActOnPages uses page as an index
daS ← DESCRIPTOR[@pages, lTfsBT+1];
-- FP for the disk descriptor
fpTfsDD ← disk.dsk.fpDiskDescriptor↑;
IF page <= 0 OR page >= lTfsDDPreamble + lTfsBT THEN ERROR BadBitMapPage;
ddMgr.dirty ← FALSE;-- page will be clean if reading or writing
[] ← TfsActOnPages[disk, caS, daS, fpTfsDD, page, page, action, numcharsPtr, action, ddMgr.buffer, DefaultTfsCleanupRtn, DefaultTfsErrorRtn, FALSE, page];
END;
BadBitMapPage: PUBLIC ERROR = CODE;-- erroneous bitmap disk address
END.-- of TfsDDMgr
--Last edited on September 1, 1981 2:17 PM by GWiliams
--changed ddMgr.buffer to get a large segment rather than allocate from heap
--changed TransferDDPage