-- LockInternal.mesa
-- Last edited by
--   MBrown on January 30, 1984 12:19:25 pm PST

DIRECTORY
  AlpineEnvironment,
  AlpineInternal,
  BasicTime,
  Lock;

LockInternal: DEFINITIONS = BEGIN
  LockID: TYPE = Lock.LockID;
  LockMode: TYPE = Lock.LockMode;

  Handle: TYPE = REF Object;
  HeaderHandle: TYPE = REF Object.header;
  RequestHandle: TYPE = REF Object.request;
  GrantedRequestHandle: TYPE = REF Object.request.granted;
  WaitingRequestHandle: TYPE = REF Object.request.waiting;
  LockTransHeaderHandle: TYPE = REF Object.request.transHeader;

  ObjectType: TYPE = {header, request};
  RequestObjectType: TYPE = {granted, waiting, transHeader};
  
  Object: TYPE = RECORD [
    requestList: Handle ← NIL,
      -- circular list consisting of one Object.header, one or more Object.requests
      --with granted or waiting variant.
    body: SELECT type: ObjectType FROM
      header => [
        lockID: LockID ← TRASH,
        next: HeaderHandle ← NIL -- link field for hash table package
        ],
      request => [
        trans: AlpineInternal.TransHandle,
        transList: RequestHandle,
          -- circular list consisting of one LockObject.request.transHeader, zero or more
          --LockObject.request.granted, all with same value of trans.
          -- all waiting requests are linked into a single list, through this field.
        mode: LockMode,
        rest: SELECT type: RequestObjectType FROM
          granted => [
            count: NAT
            ],
          waiting => [
            somethingChanged: CONDITION,
            giveUp: BOOL ← FALSE,
            whyGivingUp: WhyGivingUp ← TRASH, -- meaningful only if giveUp
            isConversion: BOOL ← FALSE,
            startTime: BasicTime.GMT
            ],
          transHeader => [ -- requestList = NIL
            nLocks: NAT
            ],
          ENDCASE
        ],
      ENDCASE
    ];

  WhyGivingUp: TYPE = { abort, timeout };

  GetInfo: PROC [
    generalInfoProc: GeneralInfoProc ← NIL,
    lockEnumProc: LockEnumProc ← NIL,
    waitingRequestEnumProc: WaitingRequestEnumProc ← NIL,
    waitingRequestEnumProc2: WaitingRequestEnumProc ← NIL];
    -- Enters Lock monitor.  If generalInfoProc # NIL, calls it with current values of
    --its parameters.  On return, if lockEnumProc # NIL, enumerates the locks calling
    --lockEnumProc until it returns quit: TRUE or all locks have been enumerated.  Then
    --if waitingRequestEnumProc # NIL, enumerates the waiting requests in the same
    --fashion.  Then if waitingRequestEnumProc2 # NIL, enumerates the waiting requests
    --again, in the same fashion.  Finally returns, releasing the Lock monitor.
    -- None of the proc parameters should not call into monitors that may be held
    --while calling into the Lock monitor (including the Lock monitor itself).

  GeneralInfoProc: TYPE = PROC [nLocks, nRequests, nSetCalls, nSetCallsWaited: INT];

  LockEnumProc: TYPE = PROC [
    h: HeaderHandle] RETURNS [stop: BOOL];

  WaitingRequestEnumProc: TYPE = PROC [
    wr: WaitingRequestHandle] RETURNS [stop: BOOL];

  TimeoutWaitingRequest: PROC [wr: WaitingRequestHandle];
    -- Cause the Lock.Set call to raise Lock.Failed[timeout].

  END.