This is a very basic protected bounded buffer in Ada, exactly as it is presented everywhere, even in text books. (This is a part of a bigger thing, but I simplified code down to bare minimum, where it reproduced the behavior). It seems to work just fine if I have 1 task feeding it and the "main" body is reading from it. But it blocks on the 1st Get if I use 2 tasks - Putter and Getter, just as below.
with Ada.Text_IO;use Ada.Text_IO;
procedure test_buffer is
maxItems : constant Positive := 10;
type Index is mod maxItems;
maxCount : constant Index := 9;
type ItemArray is array(Index) of Integer;
protected Buffer is
entry Put(X : in Integer);
entry Get(X : out Integer);
private
First, Last, Count : Index := 0;
buf : ItemArray;
end;
protected body Buffer is
entry Put(X : in Integer) when Last - First < maxCount is
begin
Put_Line("Put X="&X'Img & "; First="&First'Img&", Last="&Last'Img&", Count="&Count'Img);
buf(Last) := X;
Last := Last + 1;
Count := Count + 1;
end;
--
entry Get(X : out Integer) when Last - First > 0 is
begin
Put_Line("Get X="&X'Img & "; First="&First'Img&", Last="&Last'Img&", Count="&Count'Img);
X := buf(First);
First := First + 1;
Count := Count - 1;
end;
end;
task Putter;
task body Putter is
begin
Put_Line("Putter started");
for i in 0 ..25 loop
Buffer.Put(i);
end loop;
end;
task Getter;
task body Getter is
X : Integer;
begin
Put_Line("Getter started");
loop
Put_Line("requesting X..");
Buffer.Get(X);
Put_Line("got X="&X'Img);
end loop;
end;
-- X : Integer;
begin
-- loop
-- Buffer.Get(X);
-- Put_Line("got X="&X'Img);
-- end loop;
Null;
end test_buffer;
This spits out the following output:
$ ./test_buffer
Putter started
Put X= 0; First= 0, Last= 0, Count= 0
Put X= 1; First= 0, Last= 1, Count= 1
Put X= 2; First= 0, Last= 2, Count= 2
Put X= 3; First= 0, Last= 3, Count= 3
Getter started
Put X= 4; First= 0, Last= 4, Count= 4
Put X= 5; First= 0, Last= 5, Count= 5
Put X= 6; First= 0, Last= 6, Count= 6
Put X= 7; First= 0, Last= 7, Count= 7
Put X= 8; First= 0, Last= 8, Count= 8
^C
As you can see, Get is never getting executed, likely due to the barrier not being re-evaluated. However if I uncomment the main body and comment out the task (or even simply uncomment the main - then I get concurrent reads), it proceeds just fine with all reads and writes..
I cannot seem to find any rule that would stall the barrier on Get (2nd task is external, so no, its not the no reevaluation on internal calls of protected object).
Am I missing something obvious here or is this a bug?