-- DirectoryContextsImpl.mesa (last edited by: Keith on: January 8, 1981 2:33 PM) --

DIRECTORY
Directory,
DirectoryContexts,
DirectoryExtras,
DirectoryFiles,
DirectoryInternal,
DirectoryTrees,
File USING [Capability],
Heap USING [Create],
Space USING [Create, Delete, Handle, Unmap, PageCount, virtualMemory],
String USING [AppendChar, AppendString],
Volume USING [GetLabelString, nullID, systemID];

DirectoryContextsImpl: MONITOR
LOCKS DirectoryInternal.DirectoryLock
IMPORTS Directory, DirectoryFiles, DirectoryInternal, DirectoryTrees, Heap, Space, String, Volume
EXPORTS Directory, DirectoryContexts, DirectoryExtras =
BEGIN

--
Contexts

Context: PUBLIC TYPE = DirectoryInternal.Context;
Handle: TYPE = DirectoryContexts.Handle;
ContextSpace: PUBLIC UNCOUNTED ZONE;
contextSpaceHandle: Space.Handle;
contextHeapSize: Space.PageCount = 100;
-- size of heap used to store contexts
initialContextHeapSize: Space.PageCount = 1; --
initial size of heap... will be used for WD part

ContextTable: TYPE = ARRAY [0.. DirectoryContexts.maxContexts) OF Handle;
contextTable: PUBLIC LONG POINTER TO ContextTable ← NIL;
topContext: [0.. DirectoryContexts.maxContexts) ← 0;

defaultContextDefined: BOOLEAN ← FALSE; --
TRUE if the default context has been defined

eType: Directory.ErrorType;

--
entry and external procedures

CopyContext: PUBLIC ENTRY PROC [context: Handle] RETURNS [Handle] =
-- create a new context and initialize to the values of the passed context
BEGIN ENABLE {UNWIND => NULL; Directory.Error => {eType ← type; GOTO AnError}};
newContext: Handle;
context ← ValidateContext[context];
newContext ← NewContext[context];
RETURN [newContext]
EXITS AnError => RETURN WITH ERROR Directory.Error[eType];
END;

ForgetVolumes: PUBLIC ENTRY PROCEDURE =
-- Releases all information kept by Directory about non-system Pilot volumes
BEGIN ENABLE UNWIND => NULL;
pVT, pDC: CARDINAL;
FOR pVT IN [0.. DirectoryFiles.maxDVolumes) DO
IF (DirectoryFiles.volumeTable[pVT].volID = Volume.systemID) OR
(DirectoryFiles.volumeTable[pVT].volID = Volume.nullID) THEN LOOP;
DirectoryFiles.volumeTable[pVT].volID ← Volume.nullID;
DirectoryFiles.volumeTable[pVT].volName.length ← 0;
Space.Delete[DirectoryFiles.volumeTable[pVT].dtSpace];
FOR pDC IN [1.. DirectoryFiles.maxDCache] DO
IF (DirectoryFiles.directoryCache[pDC].pVT # pVT) OR
(DirectoryFiles.directoryCache[pDC].refCount = 0) THEN LOOP;
DirectoryFiles.directoryCache[pDC].refCount ← 0;
Space.Delete[DirectoryFiles.directoryCache[pDC].dir.space];
InvalidateContext[pDC];
ENDLOOP;
ENDLOOP;
END;

GetDefaultContext: PUBLIC ENTRY PROC RETURNS [context: Handle] =
--
Create a context with values equal to the default context
BEGIN ENABLE {UNWIND => NULL; Directory.Error => {eType ← type; GOTO AnError}};
context ← ValidateContext[Directory.defaultContext];
context ← NewContext[context];
RETURN;
EXITS AnError => RETURN WITH ERROR Directory.Error[eType];
END;

GetSPElement: PUBLIC ENTRY PROC [element: CARDINAL, pathName: LONG STRING,
context: Handle] =
--
return the search path element
BEGIN ENABLE {UNWIND => NULL; Directory.Error => {eType ← type; GOTO AnError}};
pSP: LONG POINTER TO DirectoryInternal.SPRecord;
context ← ValidateContext[context ! Directory.Error => IF type = fileNotFound THEN CONTINUE];
pSP ← context.pSP;
THROUGH [0.. element) DO
IF pSP.pSP = NIL THEN RETURN WITH ERROR Directory.OutOfBounds;
pSP ← pSP.pSP;
ENDLOOP;
DirectoryTrees.MoveLongString[from: @pSP.spName, to: pathName];
IF pathName.maxlength < pSP.spName.length THEN
RETURN WITH ERROR Directory.Error[stringTooShort];
RETURN
EXITS AnError => RETURN WITH ERROR Directory.Error[eType];
END;

GetWD: PUBLIC ENTRY PROC [context: Handle, pathName: LONG STRING] =
--
return the working directory field from the context
BEGIN ENABLE {UNWIND => NULL; Directory.Error => {eType ← type; GOTO AnError}};
context ← ValidateContext[context ! Directory.Error => IF type = fileNotFound THEN CONTINUE];
DirectoryTrees.MoveLongString[from: @context.wdName, to: pathName];
IF pathName.maxlength < context.wdName.length THEN
RETURN WITH ERROR Directory.Error[stringTooShort];
RETURN
EXITS AnError => RETURN WITH ERROR Directory.Error[eType];
END;

KillContext
: PUBLIC ENTRY PROC [context: Handle] =
--
Deletes a context
BEGIN ENABLE {UNWIND => NULL; Directory.Error => {eType ← type; GOTO AnError}};
IF context = Directory.defaultContext OR context = contextTable[0] THEN RETURN;
OldContext[ValidateContext[context ! Directory.Error => IF type = fileNotFound THEN CONTINUE]];
EXITS AnError => RETURN WITH ERROR Directory.Error[eType];
END;

SetDefaultContext: PUBLIC ENTRY PROC [context: Handle]
RETURNS [oldContext: Handle] =
--
Defines the default context
BEGIN ENABLE {UNWIND => NULL; Directory.Error => {eType ← type; GOTO AnError}};
oldContext ← contextTable[0];
IF context = Directory.defaultContext THEN DefineDefaultContext[]
ELSE contextTable[0] ← NewContext[ValidateContext[context]];
IF topContext = DirectoryContexts.maxContexts THEN ERROR;
topContext ← topContext+1;
contextTable[topContext] ← oldContext;
EXITS AnError => RETURN WITH ERROR Directory.Error[eType];
END;

--
internal procedures

DefineDefaultContext: INTERNAL PROC =
--
gives the default context the values wd = <SysVol>SysDir>, sp = WorkDir>
BEGIN
defaultHandle: Handle;
defaultSP: LONG POINTER TO withWD DirectoryInternal.SPRecord;
wdpDT: DirectoryInternal.PDT;
wdpDTNode: DirectoryInternal.PDTNode;
wdName: STRING ← [100];
sysvolLabel: STRING ← [40];
defaultContextDefined ← TRUE;
-- allocate new working directory area
defaultHandle ← contextTable[0] ← ContextSpace.NEW[Context];
wdpDT ← DirectoryFiles.volumeTable[DirectoryFiles.GetVTEntryFromID[Volume.systemID]].pDT;
wdpDTNode ← DirectoryTrees.DTFirst[wdpDT]; --
pointer to root directory
IF wdpDTNode = DirectoryInternal.pDTnil THEN ERROR Directory.VolumeError[rootNotFound, Volume.systemID];
wdpDTNode ← DirectoryTrees.DTFind[wdpDT, wdpDTNode, "SysDir"L];
IF wdpDTNode = DirectoryInternal.pDTnil THEN ERROR
Directory.VolumeError[directoryNeedsScavenging, Volume.systemID];
defaultHandle.pDC ← DirectoryFiles.GetDirectoryCache[wdpDT[wdpDTNode].cap];
defaultHandle.wdName ← [length: 0, maxlength: Directory.maxPathNameLength, text:];
defaultHandle.valid ← TRUE;
wdName.length ← 0;
String.AppendChar[wdName, ’<];
Volume.GetLabelString[Volume.systemID, sysvolLabel];
String.AppendString[wdName, sysvolLabel];
String.AppendChar[wdName, ’>];
String.AppendString[wdName, "SysDir>"];
DirectoryTrees.MoveLongString[to: @defaultHandle.wdName, from: wdName];
-- allocate new search path element area
defaultSP ← defaultHandle.pSP ← ContextSpace.NEW[withWD DirectoryInternal.SPRecord];
defaultSP.spName ← [length: 0, maxlength: Directory.maxPathNameLength, text:];
DirectoryTrees.MoveLongString[to: @defaultSP.spName, from: "WorkDir>"L];
defaultSP.pSP ← NIL;
defaultSP.pDC ← 0;
defaultSP.defined ← FALSE;
defaultSP.pWD ← contextTable[0];
defaultContextDefined ← TRUE;
RETURN
END;

NewContext: INTERNAL PROC [context: Handle] RETURNS [newContext: Handle] =
--
creates a new context with values equal to the old context
BEGIN
pSP, newSP: LONG POINTER TO DirectoryInternal.SPRecord;
IF topContext = DirectoryContexts.maxContexts THEN ERROR;
newContext ← ContextSpace.NEW[Context ← context↑];
topContext ← topContext+1;
contextTable[topContext] ← newContext;
DirectoryFiles.directoryCache[context.pDC].refCount ←
DirectoryFiles.directoryCache[context.pDC].refCount + 1;
pSP ← context.pSP;
IF pSP = NIL THEN ERROR; --this shouldn’t happen!!
newSP ← newContext.pSP ← ContextSpace.NEW[DirectoryInternal.SPRecord ← pSP↑];
IF pSP.defined THEN DirectoryFiles.directoryCache[pSP.pDC].refCount ←
DirectoryFiles.directoryCache[pSP.pDC].refCount+1;
WITH sp: newSP↑ SELECT FROM
withWD => sp.pWD ← newContext;
ENDCASE;
FOR pSP ← pSP.pSP, pSP.pSP UNTIL pSP = NIL DO
newSP.pSP ← ContextSpace.NEW[DirectoryInternal.SPRecord ← pSP↑];
IF pSP.defined THEN DirectoryFiles.directoryCache[pSP.pDC].refCount ←
DirectoryFiles.directoryCache[pSP.pDC].refCount+1;
WITH sp: newSP.pSP↑ SELECT FROM
withWD => sp.pWD ← newContext;
ENDCASE;
newSP ← newSP.pSP;
ENDLOOP;
RETURN [newContext]
END;

OldContext: INTERNAL PROC [context: Handle] =
--
Delete the context
BEGIN
startCompress: BOOLEAN ← FALSE;
pSP: LONG POINTER TO DirectoryInternal.SPRecord ← context.pSP;
nextSP: LONG POINTER TO DirectoryInternal.SPRecord;
spaceToKill: Space.Handle;
IF context.valid THEN {
DirectoryFiles.directoryCache[context.pDC].refCount ←
DirectoryFiles.directoryCache[context.pDC].refCount-1;
IF DirectoryFiles.directoryCache[context.pDC].refCount = 0 THEN {
spaceToKill ← DirectoryFiles.directoryCache[context.pDC].dir.space;
Space.Unmap[spaceToKill];
Space.Delete[spaceToKill]}};
FOR i: CARDINAL IN (0.. topContext] DO
IF startCompress THEN contextTable[i-1] ← contextTable[i]
ELSE IF contextTable[i] = context THEN startCompress ← TRUE;
ENDLOOP;
contextTable[topContext] ← NIL;
topContext ← topContext-1;
ContextSpace.FREE[@context];
WHILE pSP # NIL DO
IF pSP.defined THEN {
DirectoryFiles.directoryCache[pSP.pDC].refCount ←
DirectoryFiles.directoryCache[pSP.pDC].refCount-1;
IF DirectoryFiles.directoryCache[pSP.pDC].refCount = 0 THEN {
spaceToKill ← DirectoryFiles.directoryCache[pSP.pDC].dir.space;
Space.Unmap[spaceToKill];
Space.Delete[spaceToKill]}};
nextSP ← pSP.pSP;
ContextSpace.FREE[@pSP];
pSP ← nextSP
ENDLOOP;
END;

InvalidateContext: PUBLIC INTERNAL PROC [pDC: CARDINAL] =
--
invalidates contexts that refer to the indicated directory cache
BEGIN
wd: Handle;
sp: LONG POINTER TO DirectoryInternal.SPRecord;
FOR i: CARDINAL IN [0.. topContext] DO
wd ← contextTable[i];
IF wd.pDC = pDC THEN wd.valid ← FALSE;
sp ← wd.pSP;
WHILE sp # NIL DO
IF sp.defined AND (sp.pDC = pDC) THEN sp.defined ← FALSE;
sp ← sp.pSP;
ENDLOOP;
ENDLOOP;
RETURN
END;

ValidateContext: PUBLIC INTERNAL PROC [context: Handle] RETURNS [Handle] =
--
checks that the passed context is valid, and expands the default context
BEGIN
returnHandle: Handle;
IF ~ defaultContextDefined THEN DefineDefaultContext[];
IF context = Directory.defaultContext THEN returnHandle ← contextTable[0]
ELSE FOR i: CARDINAL IN [0.. topContext] DO
IF context = contextTable[i] THEN {returnHandle ← context; EXIT}
REPEAT FINISHED => ERROR Directory.Error[invalidContext];
ENDLOOP;
IF returnHandle.valid THEN RETURN [returnHandle] ELSE ERROR Directory.Error[fileNotFound];
END;

-- Initialization

-- Create the heap for contexts and the context table

contextSpaceHandle ← Space.Create[size: contextHeapSize, parent: Space.virtualMemory];
ContextSpace ← Heap.Create[
initial: initialContextHeapSize,
parent: contextSpaceHandle,
swapUnit: DirectoryInternal.swapUnitSize];
contextTable ← ContextSpace.NEW[ContextTable ← ALL[Directory.defaultContext]];

END.




LOG

Time: August 28, 1980 10:54 AM By: Marzullo Action: Created File

Time: October 8, 1980 10:58 PM By: Keith Action: Fixed AR 6178: WD max length too small in DefineContext.
Time: October 12, 1980 4:32 PM By: Fay Action: Changes for merge of DirectoryExtras into Directory.
Time: October 15, 1980 11:42 AM By: Keith Action: SetDefaultContext didn’t enter oldContext into contextTable and NewContext did not set pWD in search paths correctly (AR 6258)..
Time: January 7, 1981 8:11 PM By: Keith Action: Moved contextTable to hyperspace, added entry proc ForgetVolumes and fixed OldContext to correctly update contextTable.