-- Copyright (C) 1983  by Xerox Corporation. All rights reserved. 
-- BootServersB.mesa, HGM, 23-Sep-83  3:27:13 

DIRECTORY
  File USING [nullFile],
  Space USING [nullInterval],
  String USING [Equivalent],

  BootServerFriends USING [
    ActivateFile, BootFile, BootFileNumber, BootFileObject,
    BootFileType, DeactivateFile, KillSpace, MachineType,
    timeNotKnown],
  ServerHeap USING [CopyString, Free, FreeString, Node];

BootServersB: MONITOR
  IMPORTS String, BootServerFriends, ServerHeap EXPORTS BootServerFriends =
  BEGIN

  BootFile: TYPE = BootServerFriends.BootFile;
  BootFileNumber: TYPE = BootServerFriends.BootFileNumber;

  UseCountConfusion: ERROR = CODE;
  DanglingFile: ERROR = CODE;

  first: BootFile ← NIL;
  waitingForLock: CONDITION;


  FindBootFile: PUBLIC ENTRY PROCEDURE [code: BootFileNumber]
    RETURNS [bf: BootFile] =
    BEGIN
    previous: BootFile ← NIL;
    FOR bf ← first, bf.next UNTIL bf = NIL DO
      IF bf.code = code AND ~bf.unknown THEN EXIT;
      previous ← bf;
      REPEAT FINISHED => RETURN;
      ENDLOOP;
    IF previous # NIL THEN
      BEGIN previous.next ← bf.next; bf.next ← first; first ← bf; END;
    END;

  FindBootFileByName: PUBLIC ENTRY PROCEDURE [name: LONG STRING]
    RETURNS [bf: BootFile] =
    BEGIN
    previous: BootFile ← NIL;
    FOR bf ← first, bf.next UNTIL bf = NIL DO
      IF ~bf.unknown AND String.Equivalent[name, bf.fileName] THEN EXIT;
      previous ← bf;
      REPEAT FINISHED => RETURN;
      ENDLOOP;
    IF previous # NIL THEN
      BEGIN previous.next ← bf.next; bf.next ← first; first ← bf; END;
    END;

  EnumerateBootTable: PUBLIC ENTRY PROCEDURE [proc: PROCEDURE [BootFile]] =
    BEGIN
    FOR bf: BootFile ← first, bf.next UNTIL bf = NIL DO proc[bf]; ENDLOOP;
    END;

  GetPointerToBootTable: PUBLIC PROCEDURE RETURNS [LONG POINTER TO BootFile] =
    BEGIN RETURN[@first]; END;

  LockFileRead: PUBLIC ENTRY PROCEDURE [bf: BootFile] RETURNS [BOOLEAN] =
    BEGIN
    IF bf.useCount > 50 THEN ERROR UseCountConfusion;
    IF bf.handle = NIL THEN RETURN[FALSE];
    bf.useCount ← bf.useCount + 1;
    RETURN[TRUE];
    END;

  UnlockFile: PUBLIC ENTRY PROCEDURE [bf: BootFile] =
    BEGIN
    IF bf.useCount = 0 THEN ERROR UseCountConfusion;
    bf.useCount ← bf.useCount - 1;
    BROADCAST waitingForLock;
    END;

  AddBootFile: PUBLIC ENTRY PROCEDURE [
    code: BootFileNumber, fileName: LONG STRING,
    fileType: BootServerFriends.BootFileType,
    machineType: BootServerFriends.MachineType, pup: BOOLEAN] =
    BEGIN
    bf: BootFile ← ServerHeap.Node[SIZE[BootServerFriends.BootFileObject]];
    last: BootFile;
    bf↑ ← [
      next: NIL, code: code, create: BootServerFriends.timeNotKnown,
      file: File.nullFile, handle: NIL, space: Space.nullInterval,
      fileName: ServerHeap.CopyString[fileName], ms: 0, count: 0, pages: 0,
      bytes: 0, useCount: 0, tries: 0, pup: pup, fileType: fileType,
      machineType: machineType, unknown: TRUE, inTransit: FALSE];
    IF first = NIL THEN first ← bf
    ELSE
      BEGIN
      FOR last ← first, last.next UNTIL last.next = NIL DO ENDLOOP;
      last.next ← bf;
      END;
    END;

  ActivateFiles: PUBLIC ENTRY PROCEDURE =
    BEGIN
    FOR bf: BootFile ← first, bf.next UNTIL bf = NIL DO
      BootServerFriends.ActivateFile[bf]; ENDLOOP;
    END;

  DeactivateFiles: PUBLIC ENTRY PROCEDURE =
    BEGIN
    FOR bf: BootFile ← first, bf.next UNTIL bf = NIL DO
      IF bf.space # Space.nullInterval THEN BootServerFriends.KillSpace[bf];
      BootServerFriends.DeactivateFile[bf];
      ENDLOOP;
    END;

  DeleteBootFileTable: PUBLIC ENTRY PROCEDURE =
    BEGIN
    UNTIL first = NIL DO
      bf: BootServerFriends.BootFile ← first;
      IF bf.handle # NIL OR bf.useCount # 0 THEN ERROR DanglingFile;
      first ← bf.next;
      ServerHeap.FreeString[bf.fileName];
      ServerHeap.Free[bf];
      ENDLOOP;
    END;

  ReleaseFile: PUBLIC ENTRY PROCEDURE [bf: BootFile] =
    BEGIN
    UNTIL bf.useCount = 0 DO WAIT waitingForLock; ENDLOOP;
    IF bf.space # Space.nullInterval THEN BootServerFriends.KillSpace[bf];
    bf.handle ← NIL;
    bf.unknown ← bf.inTransit ← TRUE;
    END;

  END.