-- NewFIFOImpl.sak
-- last edited by Suzuki: 20-Apr-82 12:55:47

DIRECTORY
  FIFO: TYPE, 
  SakuraRT: TYPE;

NewFIFOImpl: MONITOR
  IMPORTS SakuraRT
  EXPORTS FIFO
  
  = BEGIN
  choice1: SakuraRT.Choice ← SakuraRT.CreateChoice[]; 
  FIFOFunc: PUBLIC PROC [size: CARDINAL, 
                         Init, WriteRequest, ReadRequest: SakuraRT.Handle, 
                         DIn: SakuraRT.Handle, 
                         SpaceAv, DataAv: SakuraRT.Handle, 
                         DOut: SakuraRT.Handle] = {
    guardian: PROC = {
      {ENABLE {ABORTED => GO TO Aborted};
       Initialized: BOOLEAN ← FALSE; 
       SakuraRT.RegisterUp[choice1, 1, Init]; 
       SakuraRT.RegisterUp[choice1, 2, ReadRequest]; 
       SakuraRT.RegisterUp[choice1, 3, WriteRequest]; 
       DO SELECT SakuraRT.GetChoice[choice1] FROM 
            1 => 
             {IF SakuraRT.GetBool[ReadRequest] OR SakuraRT.GetBool[WriteRequest] THEN 
                 ERROR; 
              Initialized ← TRUE};
            2 => 
             IF NOT Initialized OR SakuraRT.GetBool[Init] OR NOT SakuraRT.GetBool[DataAv] THEN 
                ERROR;
            3 => 
             IF NOT Initialized OR SakuraRT.GetBool[Init] OR 
                  NOT SakuraRT.GetBool[SpaceAv] THEN 
                ERROR
            ENDCASE => ERROR
          ENDLOOP; 
       SakuraRT.ProcessEnd[]}
      EXITS
        Aborted => SakuraRT.Abort[]}; 
    p: PROCESS;
    {ENABLE {ABORTED => GO TO Aborted};
     p ← SakuraRT.Fork[guardian]; 
     SakuraRT.CatalogProcId[p]; 
     {A: ARRAY INTEGER [0..37] OF CARDINAL; 
      rp, wp: CARDINAL; 
      DO SakuraRT.GetNew[Init, TRUE];
          {rp ← 1; wp ← 0; 
           SakuraRT.Put[SpaceAv, NEW[BOOLEAN ← TRUE]]; 
           SakuraRT.Put[DataAv, NEW[BOOLEAN ← FALSE]]}; 
         {st1: PROC = {
            {ENABLE {ABORTED => GO TO Aborted};
             {DO SakuraRT.GetNew[ReadRequest, TRUE];
                  {SakuraRT.Delay[1]; 
                   SakuraRT.Put[DataAv, NEW[BOOLEAN ← FALSE]]; 
                   rp ← rp + 1; 
                   SakuraRT.Put[DOut, NEW[CARDINAL ← A[rp]]]; 
                   SakuraRT.Put[SpaceAv, NEW
                     [BOOLEAN ← NOT SakuraRT.GetBool[WriteRequest] AND wp < rp + 
                                      size]]}; 
                 SakuraRT.GetNew[ReadRequest, FALSE];
                  SakuraRT.Put[DataAv, NEW[BOOLEAN ← rp <= wp]]
                 ENDLOOP; 
              SakuraRT.ProcessEnd[]}}
            EXITS
              Aborted => SakuraRT.Abort[]}; 
          st2: PROC = {
            {ENABLE {ABORTED => GO TO Aborted};
             {DO SakuraRT.GetNew[WriteRequest, TRUE];
                  {SakuraRT.Delay[1]; 
                   SakuraRT.Put[SpaceAv, NEW[BOOLEAN ← FALSE]]; 
                   wp ← wp + 1; 
                   A[wp] ← SakuraRT.GetCard[DIn]; 
                   SakuraRT.Put[DOut, NEW[CARDINAL ← A[rp]]]; 
                   SakuraRT.Put[DataAv, NEW
                     [BOOLEAN ← NOT SakuraRT.GetBool[ReadRequest] AND rp <= wp]]}; 
                 SakuraRT.GetNew[WriteRequest, FALSE];
                  SakuraRT.Put[SpaceAv, NEW[BOOLEAN ← wp < rp + size]]
                 ENDLOOP; 
              SakuraRT.ProcessEnd[]}}
            EXITS
              Aborted => SakuraRT.Abort[]}; 
          process1, process2: PROCESS; 
          process1 ← SakuraRT.Fork[st1]; 
          SakuraRT.CatalogProcId[process1]; 
          process2 ← SakuraRT.Fork[st2]; 
          SakuraRT.CatalogProcId[process2]; 
          SakuraRT.DecCurrent[]; 
          [] ← SakuraRT.Join[process1]; 
          [] ← SakuraRT.Join[process2]; 
          SakuraRT.IncCurrent[]}
         ENDLOOP}; 
     [] ← SakuraRT.Join[p]; 
     SakuraRT.ProcessEnd[]}
    EXITS
      Aborted => SakuraRT.Abort[]};
  
  NULL
  
  END.