-- FIFOImpl.sak
-- last edited by Suzuki: 20-Nov-81 16:02:15

DIRECTORY
  Connector: TYPE, 
  FIFO: TYPE, 
  Process: TYPE,
  Scheduler: TYPE;

FIFOImpl: MONITOR
  IMPORTS Connector, Process, Scheduler
  EXPORTS FIFO
  
  = BEGIN
  choice1: Connector.Choice ← Connector.CreateChoice[]; 
  FIFOFunc: PUBLIC PROC [size: CARDINAL, 
                  Init, WriteRequest, ReadRequest: Connector.Handle, 
                  DIn: Connector.Handle, 
                  SpaceAv, DataAv: Connector.Handle, 
                  DOut: Connector.Handle] = {
    guardian: PROC = 
      {{Initialized: BOOLEAN ← FALSE; 
        DO SELECT Connector.GetChoice[choice1] FROM 
             1 => 
              {IF NARROW[Connector.Get[ReadRequest], REF BOOLEAN]↑ OR 
                    NARROW[Connector.Get[WriteRequest], REF BOOLEAN]↑ THEN ERROR; 
               Initialized ← TRUE};
             2 => 
              IF NOT Initialized OR NARROW[Connector.Get[Init], REF BOOLEAN]↑ OR 
                   NOT NARROW[Connector.Get[DataAv], REF BOOLEAN]↑ THEN 
                 ERROR;
             3 => 
              IF NOT Initialized OR NARROW[Connector.Get[Init], REF BOOLEAN]↑ OR 
                   NOT NARROW[Connector.Get[SpaceAv], REF BOOLEAN]↑ THEN 
                 ERROR
             ENDCASE => ERROR
           ENDLOOP}}; 
    p: PROCESS;
    Scheduler.IncCurrent[];
    Process.Yield[];
    p ← Scheduler.Fork[guardian]; 
    Connector.RegisterUp[choice1, 1, Init]; 
    Connector.RegisterUp[choice1, 2, ReadRequest]; 
    Connector.RegisterUp[choice1, 3, WriteRequest]; 
    {A: ARRAY INTEGER [1..37] OF CARDINAL; rp, wp: CARDINAL; 
     DO Connector.GetNew[Init, TRUE]; rp ← wp ← 0; 
        A[rp] ← NARROW[Connector.Get[DIn], REF CARDINAL]↑; 
        Connector.Put[DOut, NEW[CARDINAL ← A[wp]]]; 
        Connector.Put[SpaceAv, NEW[BOOLEAN ← FALSE]]; 
        Connector.Put[DataAv, NEW[BOOLEAN ← FALSE]]; 
        {d1: PROC = {Connector.GetNew[Init, TRUE]; NULL; 
                     Process.Abort[p2]}; 
         d2: PROC = {
           {ENABLE {ABORTED => GO TO End};
            {st1: PROC = 
               {DO Connector.GetNew[ReadRequest, TRUE];
                    {Connector.Put[DataAv, NEW[BOOLEAN ← FALSE]]; rp ← rp + 1; 
                     A[rp] ← NARROW[Connector.Get[DIn], REF CARDINAL]↑; 
                     Connector.Put[DOut, NEW[CARDINAL ← A[wp]]]; 
                     Connector.Put[SpaceAv, NEW
                       [BOOLEAN ← 
                          NOT NARROW[Connector.Get[WriteRequest], REF BOOLEAN]↑ AND 
                            wp < rp + size]]}; 
                   Connector.GetNew[ReadRequest, FALSE];
                    Connector.Put[DataAv, NEW[BOOLEAN ← rp < wp]]
                   ENDLOOP}; 
             process1: PROCESS; 
             process1 ← Scheduler.Fork[st1]; 
             DO Connector.GetNew[WriteRequest, TRUE];
                 {Connector.Put[SpaceAv, NEW[BOOLEAN ← FALSE]]; wp ← wp + 1; 
                  Connector.Put[DOut, NEW[CARDINAL ← A[wp]]]; 
                  Connector.Put[DataAv, NEW
                    [BOOLEAN ← 
                       NOT NARROW[Connector.Get[ReadRequest], REF BOOLEAN]↑ AND rp < 
                           wp]]}; 
                Connector.GetNew[WriteRequest, FALSE];
                 Connector.Put[SpaceAv, NEW[BOOLEAN ← wp < rp + size]]
                ENDLOOP; 
             [] ← Scheduler.Join[process1]}
            EXITS
              End => NULL}}; 
         p1, p2: PROCESS; 
         p1 ← Scheduler.Fork[d1]; 
         p2 ← Scheduler.Fork[d2]; 
         [] ← Scheduler.Join[p1]; 
         [] ← Scheduler.Join[p2]}
        ENDLOOP}; 
    [] ← Scheduler.Join[p]};
  
  NULL;
  
  END.