--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