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