Subprogram arguments in barrier condition

I am trying to use some subprogram argument in a protected object barrier condition and as that is not allowed by the compiler I’m wondering what’s the best way to work around that.

Consider the following arrangement:

package Barier_Parameters is

   type My_Enum_1 is (Enum_1, Enum_2, Enum_3);
   type My_Enum_2 is (Enum_4, Enum_5, Enum_6);
   
   type My_Enum_Conditions is array(My_Enum_1, My_Enum_2) of Boolean with Default_Component_Value => False;
   
   protected type Barier_Parameter is
      
      entry My_Entry_Family(My_Enum_1)(ME2: My_Enum_2);
   private
      MEC: My_Enum_Conditions;
   end Barier_Parameter;
   
end Barier_Parameters;

and an implementation where ME2 needs to be part of the barrier, as in :

package body Barier_Parameters is
   
   protected body Barier_Parameter is
      entry My_Entry_Family(for ME1 in My_Enum_1)(ME2: My_Enum_2) when MEC(ME1,ME2) is
      begin
         null; -- entry logic
      end My_Entry_Family;
   end Barier_Parameter;
   
end Barier_Parameters;

This of course doesn’t compile as non-protected-object state isn’t allowed in the barrier condition.

One way I’ve come up with is something along the lines of:

package Barier_Parameters_2 is

   type My_Enum_1 is (Enum_1, Enum_2, Enum_3);
   type My_Enum_2 is (Enum_4, Enum_5, Enum_6);
   
   type My_Enum_Conditions is array(My_Enum_1, My_Enum_2) of Boolean with Default_Component_Value => False;
   
   protected type Barier_Parameter is
      
      entry My_Entry_Family(My_Enum_1)(ME2: My_Enum_2);
   private
      entry My_Entry_Family_Req(My_Enum_1)(ME2: My_Enum_2);
      MEC: My_Enum_Conditions;
      ME2_Temp: My_Enum_2;
   end Barier_Parameter;
   
end Barier_Parameters_2;

and then:

package body Barier_Parameters_2 is

   protected body Barier_Parameter is      
      entry My_Entry_Family(for ME1 in My_Enum_1)(ME2: My_Enum_2) when True is
      begin
         ME2_Temp := ME2;
         requeue My_Entry_Family_Req(ME1);
      end My_Entry_Family;
      
      entry My_Entry_Family_Req(for ME1 in My_Enum_1)(ME2: My_Enum_2) when MEC(ME1,ME2_Temp) is
      begin
         null; -- entry logic
      end My_Entry_Family_Req;
           
   end Barier_Parameter;
end Barier_Parameters_2;

This of course will only work under the condition that the requeueing task will be given precedence over other tasks blocked on the barrier or waiting to enter the monitor for the first time (which I believe is the case?).

Is this the idiomatic way to achieve something like that? I guess an alternative approach could be for the public entry to pass a second PO in an out param and then have the caller call an entry from that (which will be updated by the first PO)

Any input appreciated. - Thanks.

Perhaps you could combine the two parameters into a single value and use it as the entry family index. E.g.

   type Enum_Combo is range 0 .. 3 * 3 - 1;
   function Combine(ME1 : My_Enum_1; ME2 : My_Enum_2) return Enum_Combo is
     (My_Enum_1'Pos(ME1) * 3 + My_Enum_2'Pos(ME2));
   function E1_Part(C : Enum_Combo) return My_Enum_1 is
     My_Enum_1'Val(C/3);
   function E2_Part(C : Enum_Combo) return My_Enum_2 is
     My_Enum_2'Val(C mod 3);
   protected type Barrier_Parameter is
      entry My_Entry_Family(Enum_Combo);
   ...
2 Likes

Yep, that would work nicely and is a very interesting solution. - Thank you.