-- LockTestImpl.mesa
-- Last edited by
--   MBrown on January 11, 1983 11:17 pm

DIRECTORY
  AlpineEnvironment,
  AlpineInternal,
  Lock,
  LockControl,
  LockWatchdog,
  Process,
  TransactionMap;

LockTestImpl: MONITOR
  IMPORTS
    Lock,
    LockControl,
    LockWatchdog,
    Process
  EXPORTS
    AlpineInternal,
    TransactionMap
  = BEGIN
  LockID: TYPE = Lock.LockID;
  LockMode: TYPE = Lock.LockMode;

  TransObject: PUBLIC TYPE = RECORD [
    -- AlpineInternal.TransObject
    id: NAT,
    locks: AlpineInternal.LockTransHeaderHandle ← NIL
    ];

  Handle: TYPE =  REF TransObject;

  GetLockHeader: PUBLIC PROC [self: Handle]
    RETURNS [lockHeader: AlpineInternal.LockTransHeaderHandle] = {
    -- TransactionMap.GetLockHeader
    RETURN[self.locks];
    };

  AbortUnilaterally: PUBLIC PROC [self: Handle, why: AlpineEnvironment.LockFailure] = {
    -- TransactionMap.AbortUnilaterally
    LockControl.AbortWaitingRequests[self, why];
    };

  ConsTrans: PROC [id: NAT] RETURNS [Handle] = {
    h: Handle ← NEW[TransObject ← [id: id]];
    h.locks ← LockControl.ConsTransHeader[h];
    RETURN[h];
    };

  seq: LONG CARDINAL ← 1;

  GenerateLockID: PROC [] RETURNS [LockID] = {
    ID4: TYPE = RECORD [a, b, c, d: LONG CARDINAL];
    id: ID4 ← [0, 0, 0, seq];
    seq ← seq + 1;
    RETURN [LOOPHOLE[id]];
    };

  LockSetProcessResult: TYPE = {ok, aborting, conflict, deadlock, timeout};

  LockSetProcess: PROC [
    trans: AlpineInternal.TransHandle, lock: LockID, mode: LockMode, wait: BOOL ← TRUE]
    RETURNS [result: LockSetProcessResult] = {
    result ← ok;
    [] ← Lock.Set[trans, lock, mode, wait ! Lock.Failed => {
      SELECT why FROM
        aborting => result ← aborting;
        conflict => result ← conflict;
        deadlock => result ← deadlock;
        timeout => result ← timeout;
        ENDCASE;
      CONTINUE }];
    };

  LockTestHere: SIGNAL = CODE;

  Test: PROC [] = {
    LockControl.Initialize[lockZoneInitialSize: 0, hashArraySize: 32];
    LockWatchdog.Initialize[
      deadlockCheckingPeriod: Process.SecondsToTicks[5],
      timeoutCheckingPeriod: Process.SecondsToTicks[5],
      abortWaitingTransInterval: 60
      ];
    {
      p0, p1, p2, p3, p4, p5, p6: PROCESS RETURNS [LockSetProcessResult];
      r0, r1, r2, r3, r4, r5, r6: LockSetProcessResult;
      t1: Handle = ConsTrans[1];
      t2: Handle = ConsTrans[2];
      t3: Handle = ConsTrans[3];
      t4: Handle = ConsTrans[4];
      t5: Handle = ConsTrans[5];
      t6: Handle = ConsTrans[6];
      l1: LockID = GenerateLockID[];
      l2: LockID = GenerateLockID[];
      l3: LockID = GenerateLockID[];
      l4: LockID = GenerateLockID[];
      l5: LockID = GenerateLockID[];
          
      [] ← Lock.Set[t1, l1, write];
      [] ← Lock.Set[t2, l2, write];
      [] ← Lock.Set[t3, l3, write];
      [] ← Lock.Set[t4, l4, write];
      [] ← Lock.Set[t5, l5, write];
  
      p6 ← FORK LockSetProcess[t6, l1, read];  Process.Pause[2];
      p5 ← FORK LockSetProcess[t1, l2, read];  Process.Pause[2];
      p4 ← FORK LockSetProcess[t2, l3, read];  Process.Pause[2];
      p3 ← FORK LockSetProcess[t2, l4, read];  Process.Pause[2];
      p2 ← FORK LockSetProcess[t4, l3, read];  Process.Pause[2];
      p1 ← FORK LockSetProcess[t4, l1, read];  Process.Pause[2];
      p0 ← FORK LockSetProcess[t3, l5, read];  Process.Pause[2];
      
      SIGNAL LockTestHere;
      
      r0 ← JOIN p0;
      r1 ← JOIN p1;
      r2 ← JOIN p2;
      r3 ← JOIN p3;
      r4 ← JOIN p4;
      r5 ← JOIN p5;
      r6 ← JOIN p6;
      };
    };

  
  END.--LockTestImpl