----------------------------------------------------------------------
-- Readers-Writers Demo, mit simpler integer-Variablen
--
-- Version 3: protected object in package =>  preference for writer,
--                                            potentially blocking ops allowed
----------------------------------------------------------------------

with Stringpack; use Stringpack;
procedure Readers_Writers3 is

   package Variable is
      procedure Write (X : Integer);
      function Read return Integer;
   end Variable;

   package body Variable is

      V : Integer := 0; -- na ja

      protected Control is
	 entry Start_Read;
	 procedure Finish_Read;
	 entry Start_Write;
	 procedure Finish_Write;
      private
	 Readers, Writers : Natural := 0;
      end Control;

      protected body Control is

                                                      -- no writer waiting or working
	 entry Start_Read when Writers = 0 and Start_Write'Count = 0 is
	 begin Readers := Readers + 1; end Start_Read;

	 procedure Finish_Read is
	 begin Readers := Readers - 1; end Finish_Read;
	 
	 entry Start_Write when Readers = 0 and Writers = 0   is   -- nobody inside
	 begin Writers := 1; end Start_Write;
	 
	 procedure Finish_Write is
	 begin Writers := 0; end Finish_Write;

      end Control;

      procedure Write (X : Integer) is
      begin
	 Control.Start_Write; 
	 V := X;
	 Control.Finish_Write; 
      end Write;

      function Read return Integer is
         X : Integer;
      begin
         Control.Start_Read;
         X := V;
         Control.Finish_Read;
         return V; 
      end Read;

   end Variable;

   task type Reader;
   task body Reader is
      Local_X : Integer;
   begin
      for I in 1..100000 loop
	 Local_X := Variable.Read;
      end loop;
      Print("> " & Local_X);
   end Reader;

   task type Writer;
   task body Writer is
      Local_X : Integer := 1;
   begin
      for I in 1..100000 loop
	 Variable.Write(Local_X);
	 Local_X := Local_X + 1;
      end loop;
   end Writer;

   Anz_R, Anz_W : Natural;

begin

   Print("give #readers, #writers"); 
   Anz_R := Getint; Anz_W := Getint;
   declare
      R : array(1..Anz_R) of Reader;
      W : array(1..Anz_W) of Writer;
   begin null; end;

end Readers_Writers3;
