program philres1;

(* Dining Philosophers - resource version *)

  var 
    j, num: integer;

  resource forkcontrol;
  export 
    getforks,
    putforks;

    var 
      forks: array [0..4] of integer;
      i: integer;
      barrier1: boolean;

    guarded procedure waiting1(i: integer) when not barrier1; forward;
    guarded procedure waiting2(i: integer) when barrier1; forward;

    guarded procedure getforks(i: integer) when true;
    begin
      if forks[i] <> 2 then
        if barrier1 then
          requeue waiting1(i)
        else
          requeue waiting2(i);
      forks[(i+1) mod 5] := forks[(i+1) mod 5] - 1;
      forks[(i+4) mod 5] := forks[(i+4) mod 5] - 1;
      writeln('Philosopher ',i,' eats')
    end;  (* getforks *)

    procedure putforks(i: integer);
    begin
      writeln('Philosopher ',i,' finishes');
      forks[(i+1) mod 5] := forks[(i+1) mod 5] + 1;
      forks[(i+4) mod 5] := forks[(i+4) mod 5] + 1;
      barrier1 := not barrier1
    end;  (* putforks *)

    guarded procedure waiting1;
    begin
      requeue getforks(i)
    end;

    guarded procedure waiting2;
    begin
      requeue getforks(i)
    end;

  begin  (* resource body *)
    barrier1 := true;
    for i := 0 to 4 do
      forks[i] := 2
  end;  (* forkcontrol *)

  process type philtype(n: integer);

  begin
    repeat
      sleep(random(5));   (* THINKING *)
      forkcontrol.getforks(n);
      sleep(random(5));   (* EATING *)
      forkcontrol.putforks(n)
    forever
  end;  (* philosopher *)

  var
    philosopher: array[0..4] of philtype;

begin  (* main *)
  cobegin
    for num := 0 to 4 do
      philosopher[num](num)
  coend
end.