diff mbox

[Ada] Max_Queue_Length aspect for protected entries

Message ID 20170106103358.GA128603@adacore.com
State New
Headers show

Commit Message

Arnaud Charlet Jan. 6, 2017, 10:33 a.m. UTC
This patch implements the semantics of aspect/pragma Max_Queue_Length
which restricts the entry queue length for protected entries by allowing
the aspect and pragma Max_Queue_Length to appear directly after protected
entries followed by a single argument -- a positive integer.

To achieve the runtime support all entry queue maximums are collected into
an array of natural integers (zero denoting no maximum specified) which then
gets passed to Initialize_Protection_Entry or Initialize_Protection_Entries
in System.Tasking.Protected_Objects.Single_Entry or
System.Tasking.Protected_Objects.Entries respectivly.

------------
-- Source --
------------

--  pass.ads

with System;
package Pass is

   SOMETHING : constant Integer := 5;
   Variable : Boolean := False;

   protected type Protected_Example is

      entry A (Item : Integer)
         with Max_Queue_Length => 2;            --  OK

      entry B (Item : Integer);
      pragma Max_Queue_Length (SOMETHING);      --  OK

      entry C (Item : Integer);                 --  OK

      entry D (Item : Integer)
         with Max_Queue_Length => 4;            --  OK

      entry D (Item : Integer; Item_B : Integer)
         with Max_Queue_Length => Float'Digits; --  OK

      entry E (Item : Integer);
      pragma Max_Queue_Length (SOMETHING * 2);  --  OK

      entry E (Item : Integer; Item_B : Integer);
      pragma Max_Queue_Length (11);             --  OK

      entry F (Item : Integer; Item_B : Integer);
      pragma Pre (Variable = True);
      pragma Max_Queue_Length (11);             --  OK

      entry G (Item : Integer; Item_B : Integer)
         with Pre => (Variable = True),
              Max_Queue_Length => 11;           --  OK

   private
      Data : Boolean := True;
   end Protected_Example;

   Prot_Ex  : Protected_Example;

end Pass;

--  fail.ads

package Fail is

   --  Not near entry

   pragma Max_Queue_Length (40);                                --  ERROR

   --  Task type

   task type Task_Example is

      entry Insert (Item : in Integer)
         with Max_Queue_Length => 10;                           --  ERROR

      -- Entry family in task type

      entry A (Positive) (Item : in Integer)
         with Max_Queue_Length => 10;                           --  ERROR

   end Task_Example;

   Task_Ex : Task_Example;

   --  Aspect applied to protected type

   protected type Protected_Failure_0
      with Max_Queue_Length => 50 is                            --  ERROR

      entry A (Item : Integer);
   private
      Data : Integer := 0;
   end Protected_Failure_0;

   Protected_Failure_0_Ex : Protected_Failure_0;

   protected type Protected_Failure is
      pragma Max_Queue_Length (10);                             --  ERROR

      --  Duplicates

      entry A (Item : Integer)
         with Max_Queue_Length => 10;                           --  OK
      pragma Max_Queue_Length (4);                              --  ERROR

      entry B (Item : Integer);
      pragma Max_Queue_Length (40);                             --  OK
      pragma Max_Queue_Length (4);                              --  ERROR

      entry C (Item : Integer)
         with Max_Queue_Length => 10,                           --  OK
              Max_Queue_Length => 40;                           --  ERROR

      -- Duplicates with the same value

      entry AA (Item : Integer)
         with Max_Queue_Length => 10;                           --  OK
      pragma Max_Queue_Length (10);                             --  ERROR

      entry BB (Item : Integer);
      pragma Max_Queue_Length (40);                             --  OK
      pragma Max_Queue_Length (40);                             --  ERROR

      entry CC (Item : Integer)
         with Max_Queue_Length => 10,                           --  OK
              Max_Queue_Length => 10;                           --  ERROR

      --  On subprogram

      procedure D (Item : Integer)
         with Max_Queue_Length => 10;                           --  ERROR

      procedure E (Item : Integer);
      pragma Max_Queue_Length (4);                              --  ERROR

      function F (Item : Integer) return Integer
         with Max_Queue_Length => 10;                           --  ERROR

      function G (Item : Integer) return Integer;
      pragma Max_Queue_Length (4);                              --  ERROR

      --  Bad parameters

      entry H (Item : Integer)
         with Max_Queue_Length => 0;                            --  ERROR

      entry I (Item : Integer)
         with Max_Queue_Length => -1;                           --  ERROR

      entry J (Item : Integer)
         with Max_Queue_Length => 16#FFFF_FFFF_FFFF_FFFF_FFFF#; --  ERROR

      entry K (Item : Integer)
         with Max_Queue_Length => False;                        --  ERROR

      entry L (Item : Integer)
         with Max_Queue_Length => "JUNK";                       --  ERROR

      entry M (Item : Integer)
         with Max_Queue_Length => 1.0;                          --  ERROR

      entry N (Item : Integer)
         with Max_Queue_Length => Long_Integer'(3);             --  ERROR

      -- Entry family

      entry O (Boolean) (Item : Integer)
         with Max_Queue_Length => 5;                            --  ERROR

   private
      Data : Integer := 0;
   end Protected_Failure;

   I : Positive := 1;

   Protected_Failure_Ex : Protected_Failure;

end Fail;

----------------------------
-- Compilation and output --
----------------------------

$ gcc -c -gnatDG pass.ads
$ gcc -c fail.ads
$ grep '(2, 5, 0, 4, 6, 10, 11, 11, 11)' pass.ads.dg | wc -l
cannot generate code for file pass.ads (package spec)
fail.ads:5:04: pragma "Max_Queue_Length" must apply to a protected entry
fail.ads:12:15: aspect "Max_Queue_Length" cannot apply to task entries
fail.ads:17:15: aspect "Max_Queue_Length" cannot apply to task entries
fail.ads:26:12: aspect "Max_Queue_Length" must apply to a protected entry
fail.ads:36:07: pragma "Max_Queue_Length" must apply to a protected entry
fail.ads:42:07: pragma "Max_Queue_Length" duplicates aspect declared at line 41
fail.ads:46:07: pragma "Max_Queue_Length" duplicates pragma declared at line 45
fail.ads:50:15: aspect "Max_Queue_Length" for "C" previously given at line 49
fail.ads:56:07: pragma "Max_Queue_Length" duplicates aspect declared at line 55
fail.ads:60:07: pragma "Max_Queue_Length" duplicates pragma declared at line 59
fail.ads:64:15: aspect "Max_Queue_Length" for "CC" previously given at line 63
fail.ads:69:15: aspect "Max_Queue_Length" must apply to a protected entry
fail.ads:72:07: pragma "Max_Queue_Length" must apply to a protected entry
fail.ads:75:15: aspect "Max_Queue_Length" must apply to a protected entry
fail.ads:78:07: pragma "Max_Queue_Length" must apply to a protected entry
fail.ads:83:35: entity for aspect "Max_Queue_Length" must be positive
fail.ads:86:35: entity for aspect "Max_Queue_Length" must be positive
fail.ads:89:35: entity for aspect "Max_Queue_Length" out of range of Integer
fail.ads:92:35: expected an integer type
fail.ads:92:35: found type "Standard.Boolean"
fail.ads:95:35: expected an integer type
fail.ads:95:35: found a string type
fail.ads:98:35: expected an integer type
fail.ads:98:35: found type universal real
fail.ads:106:15: aspect "Max_Queue_Length" cannot apply to entry families
1

Tested on x86_64-pc-linux-gnu, committed on trunk

2017-01-06  Justin Squirek  <squirek@adacore.com>

	* aspects.adb: Register aspect in Canonical_Aspect.
	* aspects.ads: Associate qualities of Aspect_Max_Queue_Length
	into respective tables.
	* einfo.ads, einfo.adb: Add a new attribute for
	handling the parameters for Pragma_Max_Entry_Queue
	(Entry_Max_Queue_Lengths_Array) in E_Protected_Type. Subprograms
	for accessing and setting were added as well.
	* par-prag.adb (Prag): Register Pramga_Max_Entry_Queue.
	* exp_ch9.adb (Expand_N_Protected_Type_Declaration): Emit
	declaration for pramga arguments and store them in the protected
	type node.
	(Make_Initialize_Protection): Pass a reference to
	the Entry_Max_Queue_Lengths_Array in the protected type node to
	the runtime.
	* rtsfind.adb: Minor grammar fix.
	* rtsfind.ads: Register new types taken from the
	runtime libraries RE_Protected_Entry_Queue_Max and
	RE_Protected_Entry_Queue_Max_Array
	* s-tposen.adb, s-tpoben.adb
	(Initialize_Protection_Entry/Initialize_Protection_Entries):
	Add extra parameter and add assignment to local object.
	* s-tposen.ads, s-tpoben.ads: Add new types to
	store entry queue maximums and a field to the entry object record.
	* sem_ch13.adb (Analyze_Aspect_Specifications): Add case statement
	for Aspect_Max_Queue_Length.
	(Check_Aspect_At_Freeze_Point):
	Add aspect to list of aspects that don't require delayed analysis.
	* sem_prag.adb (Analyze_Pragma): Add case statement for
	Pragma_Max_Queue_Length, check semantics, and register arugments
	in the respective entry nodes.
	* sem_util.adb, sem_util.ads Add functions Get_Max_Queue_Length
	and Has_Max_Queue_Length
	* snames.ads-tmpl: Add constant for the new aspect-name
	Name_Max_Queue_Length and corrasponding pragma.
diff mbox

Patch

Index: exp_ch9.adb
===================================================================
--- exp_ch9.adb	(revision 244124)
+++ exp_ch9.adb	(working copy)
@@ -9045,7 +9045,7 @@ 
    --  the specs refer to this type.
 
    procedure Expand_N_Protected_Type_Declaration (N : Node_Id) is
-      Discr_Map : constant Elist_Id := New_Elmt_List;
+      Discr_Map : constant Elist_Id   := New_Elmt_List;
       Loc       : constant Source_Ptr := Sloc (N);
       Prot_Typ  : constant Entity_Id  := Defining_Identifier (N);
 
@@ -9055,17 +9055,9 @@ 
       Pdef : constant Node_Id := Protected_Definition (N);
       --  This contains two lists; one for visible and one for private decls
 
-      Body_Arr     : Node_Id;
-      Body_Id      : Entity_Id;
-      Cdecls       : List_Id;
-      Comp         : Node_Id;
       Current_Node : Node_Id := N;
       E_Count      : Int;
       Entries_Aggr : Node_Id;
-      New_Priv     : Node_Id;
-      Object_Comp  : Node_Id;
-      Priv         : Node_Id;
-      Rec_Decl     : Node_Id;
 
       procedure Check_Inlining (Subp : Entity_Id);
       --  If the original operation has a pragma Inline, propagate the flag
@@ -9295,7 +9287,17 @@ 
 
       --  Local variables
 
-      Sub : Node_Id;
+      Body_Arr     : Node_Id;
+      Body_Id      : Entity_Id;
+      Cdecls       : List_Id;
+      Comp         : Node_Id;
+      Expr         : Node_Id;
+      New_Priv     : Node_Id;
+      Obj_Def      : Node_Id;
+      Object_Comp  : Node_Id;
+      Priv         : Node_Id;
+      Rec_Decl     : Node_Id;
+      Sub          : Node_Id;
 
    --  Start of processing for Expand_N_Protected_Type_Declaration
 
@@ -9760,6 +9762,96 @@ 
          end loop;
       end if;
 
+      --  Create the declaration of an array object which contains the values
+      --  of aspect/pragma Max_Queue_Length for all entries of the protected
+      --  type. This object is later passed to the appropriate protected object
+      --  initialization routine.
+
+      declare
+         Maxs     : constant List_Id := New_List;
+         Count    : Int;
+         Item     : Entity_Id;
+         Maxs_Id  : Entity_Id;
+         Max_Vals : Node_Id;
+
+      begin
+         if Has_Entries (Prot_Typ) then
+
+            --  Gather the Max_Queue_Length values of all entries in a list. A
+            --  value of zero indicates that the entry has no limitation on its
+            --  queue length.
+
+            Count := 0;
+            Item  := First_Entity (Prot_Typ);
+            while Present (Item) loop
+               if Is_Entry (Item) then
+                  Count := Count + 1;
+
+                  Append_To (Maxs,
+                    Make_Integer_Literal (Loc,
+                      Intval => Get_Max_Queue_Length (Item)));
+               end if;
+
+               Next_Entity (Item);
+            end loop;
+
+            --  Create the declaration of the array object. Generate:
+
+            --    Maxs_Id : aliased Protected_Entry_Queue_Max_Array
+            --                        (1 .. Count) := (..., ...);
+            --      or
+            --    Maxs_Id : aliased Protected_Entry_Queue_Max := <value>;
+
+            Maxs_Id :=
+              Make_Defining_Identifier (Loc,
+                Chars => New_External_Name (Chars (Prot_Typ), 'B'));
+
+            case Corresponding_Runtime_Package (Prot_Typ) is
+               when System_Tasking_Protected_Objects_Entries =>
+                  Expr := Make_Aggregate (Loc, Maxs);
+
+                  Obj_Def :=
+                    Make_Subtype_Indication (Loc,
+                      Subtype_Mark =>
+                        New_Occurrence_Of
+                          (RTE (RE_Protected_Entry_Queue_Max_Array), Loc),
+                      Constraint   =>
+                        Make_Index_Or_Discriminant_Constraint (Loc,
+                          Constraints => New_List (
+                            Make_Range (Loc,
+                              Make_Integer_Literal (Loc, 1),
+                              Make_Integer_Literal (Loc, Count)))));
+
+               when System_Tasking_Protected_Objects_Single_Entry =>
+                  Expr := Make_Integer_Literal (Loc, Intval (First (Maxs)));
+
+                  Obj_Def :=
+                    New_Occurrence_Of
+                      (RTE (RE_Protected_Entry_Queue_Max), Loc);
+
+               when others =>
+                  raise Program_Error;
+            end case;
+
+            Max_Vals :=
+              Make_Object_Declaration (Loc,
+                Defining_Identifier => Maxs_Id,
+                Aliased_Present     => True,
+                Object_Definition   => Obj_Def,
+                Expression          => Expr);
+
+            --  A pointer to this array will be placed in the corresponding
+            --  record by its initialization procedure so this needs to be
+            --  analyzed here.
+
+            Insert_After (Current_Node, Max_Vals);
+            Current_Node := Max_Vals;
+            Analyze (Max_Vals);
+
+            Set_Entry_Max_Queue_Lengths_Array (Prot_Typ, Maxs_Id);
+         end if;
+      end;
+
       --  Emit declaration for Entry_Bodies_Array, now that the addresses of
       --  all protected subprograms have been collected.
 
@@ -9770,37 +9862,34 @@ 
 
          case Corresponding_Runtime_Package (Prot_Typ) is
             when System_Tasking_Protected_Objects_Entries =>
-               Body_Arr :=
-                 Make_Object_Declaration (Loc,
-                   Defining_Identifier => Body_Id,
-                   Aliased_Present     => True,
-                   Object_Definition   =>
-                     Make_Subtype_Indication (Loc,
-                       Subtype_Mark =>
-                         New_Occurrence_Of
-                           (RTE (RE_Protected_Entry_Body_Array), Loc),
-                       Constraint   =>
-                         Make_Index_Or_Discriminant_Constraint (Loc,
-                           Constraints => New_List (
-                              Make_Range (Loc,
-                                Make_Integer_Literal (Loc, 1),
-                                Make_Integer_Literal (Loc, E_Count))))),
-                   Expression          => Entries_Aggr);
+               Expr    := Entries_Aggr;
+               Obj_Def :=
+                  Make_Subtype_Indication (Loc,
+                    Subtype_Mark =>
+                      New_Occurrence_Of
+                        (RTE (RE_Protected_Entry_Body_Array), Loc),
+                    Constraint   =>
+                      Make_Index_Or_Discriminant_Constraint (Loc,
+                        Constraints => New_List (
+                          Make_Range (Loc,
+                            Make_Integer_Literal (Loc, 1),
+                            Make_Integer_Literal (Loc, E_Count)))));
 
             when System_Tasking_Protected_Objects_Single_Entry =>
-               Body_Arr :=
-                 Make_Object_Declaration (Loc,
-                   Defining_Identifier => Body_Id,
-                   Aliased_Present     => True,
-                   Object_Definition   =>
-                     New_Occurrence_Of (RTE (RE_Entry_Body), Loc),
-                   Expression          =>
-                     Remove_Head (Expressions (Entries_Aggr)));
+               Expr    := Remove_Head (Expressions (Entries_Aggr));
+               Obj_Def := New_Occurrence_Of (RTE (RE_Entry_Body), Loc);
 
             when others =>
                raise Program_Error;
          end case;
 
+         Body_Arr :=
+           Make_Object_Declaration (Loc,
+             Defining_Identifier => Body_Id,
+             Aliased_Present     => True,
+             Object_Definition   => Obj_Def,
+             Expression          => Expr);
+
          --  A pointer to this array will be placed in the corresponding record
          --  by its initialization procedure so this needs to be analyzed here.
 
@@ -9821,6 +9910,7 @@ 
             Sub :=
               Make_Subprogram_Declaration (Loc,
                 Specification => Build_Find_Body_Index_Spec (Prot_Typ));
+
             Insert_After (Current_Node, Sub);
             Analyze (Sub);
          end if;
@@ -14107,6 +14197,27 @@ 
                      raise Program_Error;
             end case;
 
+            --  Entry_Queue_Maxs parameter. This is a pointer to an array of
+            --  naturals representing the entry queue maximums for each entry
+            --  in the protected type. Zero represents no max.
+
+            if Has_Entry then
+               Append_To (Args,
+                 Make_Attribute_Reference (Loc,
+                   Prefix         =>
+                     New_Occurrence_Of
+                       (Entry_Max_Queue_Lengths_Array (Ptyp), Loc),
+                   Attribute_Name => Name_Unrestricted_Access));
+
+            --  Edge cases exist where entry initialization functions are
+            --  called, but no entries exist, so null is appended.
+
+            elsif Pkg_Id = System_Tasking_Protected_Objects_Single_Entry
+              or else Pkg_Id = System_Tasking_Protected_Objects_Entries
+            then
+               Append_To (Args, Make_Null (Loc));
+            end if;
+
             --  Entry_Bodies parameter. This is a pointer to an array of
             --  pointers to the entry body procedures and barrier functions of
             --  the object. If the protected type has no entries this object
Index: einfo.adb
===================================================================
--- einfo.adb	(revision 244124)
+++ einfo.adb	(working copy)
@@ -267,6 +267,7 @@ 
    --    Contract                        Node34
 
    --    Anonymous_Designated_Type       Node35
+   --    Entry_Max_Queue_Lengths_Array   Node35
    --    Import_Pragma                   Node35
 
    --    Class_Wide_Preconds             List38
@@ -1221,6 +1222,12 @@ 
       return Node18 (Id);
    end Entry_Index_Constant;
 
+   function Entry_Max_Queue_Lengths_Array (Id : E) return N is
+   begin
+      pragma Assert (Ekind (Id) = E_Protected_Type);
+      return Node35 (Id);
+   end Entry_Max_Queue_Lengths_Array;
+
    function Contains_Ignored_Ghost_Code (Id : E) return B is
    begin
       pragma Assert
@@ -4286,6 +4293,12 @@ 
       Set_Node18 (Id, V);
    end Set_Entry_Index_Constant;
 
+   procedure Set_Entry_Max_Queue_Lengths_Array (Id : E; V : E) is
+   begin
+      pragma Assert (Ekind (Id) = E_Protected_Type);
+      Set_Node35 (Id, V);
+   end Set_Entry_Max_Queue_Lengths_Array;
+
    procedure Set_Entry_Parameters_Type (Id : E; V : E) is
    begin
       Set_Node15 (Id, V);
@@ -10738,6 +10751,10 @@ 
          when E_Variable                                   =>
             Write_Str ("Anonymous_Designated_Type");
 
+         when E_Entry                                      |
+              E_Entry_Family                               =>
+            Write_Str ("Entry_Max_Queue_Lenghts_Array");
+
          when Subprogram_Kind                              =>
             Write_Str ("Import_Pragma");
 
Index: einfo.ads
===================================================================
--- einfo.ads	(revision 244124)
+++ einfo.ads	(working copy)
@@ -1154,6 +1154,11 @@ 
 --       accept statement for a member of the family, and in the prefix of
 --       'COUNT when it applies to a family member.
 
+--    Entry_Max_Queue_Lengths_Array (Node35)
+--       Defined in protected types for which Has_Entries is true. Contains the
+--       defining identifier for the array of naturals used by the runtime to
+--       limit the queue size of each entry individually.
+
 --    Entry_Parameters_Type (Node15)
 --       Defined in entries. Points to the access-to-record type that is
 --       constructed by the expander to hold a reference to the parameter
@@ -6381,6 +6386,7 @@ 
    --    Stored_Constraint                   (Elist23)
    --    Anonymous_Object                    (Node30)
    --    Contract                            (Node34)
+   --    Entry_Max_Queue_Lengths_Array       (Node35)
    --    SPARK_Pragma                        (Node40)
    --    SPARK_Aux_Pragma                    (Node41)
    --    Sec_Stack_Needed_For_Return         (Flag167)  ???
@@ -6928,6 +6934,7 @@ 
    function Entry_Formal                        (Id : E) return E;
    function Entry_Index_Constant                (Id : E) return E;
    function Entry_Index_Type                    (Id : E) return E;
+   function Entry_Max_Queue_Lengths_Array       (Id : E) return E;
    function Entry_Parameters_Type               (Id : E) return E;
    function Enum_Pos_To_Rep                     (Id : E) return E;
    function Enumeration_Pos                     (Id : E) return U;
@@ -7608,6 +7615,7 @@ 
    procedure Set_Entry_Component                 (Id : E; V : E);
    procedure Set_Entry_Formal                    (Id : E; V : E);
    procedure Set_Entry_Index_Constant            (Id : E; V : E);
+   procedure Set_Entry_Max_Queue_Lengths_Array   (Id : E; V : E);
    procedure Set_Entry_Parameters_Type           (Id : E; V : E);
    procedure Set_Enum_Pos_To_Rep                 (Id : E; V : E);
    procedure Set_Enumeration_Pos                 (Id : E; V : U);
@@ -8921,6 +8929,7 @@ 
    pragma Inline (Set_Entry_Cancel_Parameter);
    pragma Inline (Set_Entry_Component);
    pragma Inline (Set_Entry_Formal);
+   pragma Inline (Set_Entry_Max_Queue_Lengths_Array);
    pragma Inline (Set_Entry_Parameters_Type);
    pragma Inline (Set_Enum_Pos_To_Rep);
    pragma Inline (Set_Enumeration_Pos);
Index: s-tpoben.adb
===================================================================
--- s-tpoben.adb	(revision 244124)
+++ s-tpoben.adb	(working copy)
@@ -6,7 +6,7 @@ 
 --                                                                          --
 --                               B o d y                                    --
 --                                                                          --
---          Copyright (C) 1998-2014, Free Software Foundation, Inc.         --
+--          Copyright (C) 1998-2016, Free Software Foundation, Inc.         --
 --                                                                          --
 -- GNARL is free software; you can  redistribute it  and/or modify it under --
 -- terms of the  GNU General Public License as published  by the Free Soft- --
@@ -174,6 +174,7 @@ 
      (Object           : Protection_Entries_Access;
       Ceiling_Priority : Integer;
       Compiler_Info    : System.Address;
+      Entry_Queue_Maxs : Protected_Entry_Queue_Max_Access;
       Entry_Bodies     : Protected_Entry_Body_Access;
       Find_Body_Index  : Find_Body_Index_Access)
    is
@@ -211,6 +212,7 @@ 
       Object.Compiler_Info    := Compiler_Info;
       Object.Pending_Action   := False;
       Object.Call_In_Progress := null;
+      Object.Entry_Queue_Maxs := Entry_Queue_Maxs;
       Object.Entry_Bodies     := Entry_Bodies;
       Object.Find_Body_Index  := Find_Body_Index;
 
Index: s-tpoben.ads
===================================================================
--- s-tpoben.ads	(revision 244124)
+++ s-tpoben.ads	(working copy)
@@ -6,7 +6,7 @@ 
 --                                                                          --
 --                                  S p e c                                 --
 --                                                                          --
---          Copyright (C) 1992-2012, Free Software Foundation, Inc.         --
+--          Copyright (C) 1992-2016, Free Software Foundation, Inc.         --
 --                                                                          --
 -- GNARL is free software; you can  redistribute it  and/or modify it under --
 -- terms of the  GNU General Public License as published  by the Free Soft- --
@@ -66,6 +66,12 @@ 
    type Protected_Entry_Queue_Array is
      array (Protected_Entry_Index range <>) of Entry_Queue;
 
+   type Protected_Entry_Queue_Max_Array is
+     array (Positive_Protected_Entry_Index range <>) of Natural;
+
+   type Protected_Entry_Queue_Max_Access is
+     access all Protected_Entry_Queue_Max_Array;
+
    --  The following declarations define an array that contains the string
    --  names of entries and entry family members, together with an associated
    --  access type.
@@ -144,6 +150,10 @@ 
 
       Entry_Queues : Protected_Entry_Queue_Array (1 .. Num_Entries);
 
+      Entry_Queue_Maxs : Protected_Entry_Queue_Max_Access;
+      --  Access to an array of naturals representing the max value for
+      --  each entry's queue length. A value of 0 signifies no max.
+
       Entry_Names : Protected_Entry_Names_Access := null;
       --  An array of string names which denotes entry [family member] names.
       --  The structure is indexed by protected entry index and contains Num_
@@ -178,6 +188,7 @@ 
      (Object           : Protection_Entries_Access;
       Ceiling_Priority : Integer;
       Compiler_Info    : System.Address;
+      Entry_Queue_Maxs : Protected_Entry_Queue_Max_Access;
       Entry_Bodies     : Protected_Entry_Body_Access;
       Find_Body_Index  : Find_Body_Index_Access);
    --  Initialize the Object parameter so that it can be used by the runtime
Index: sem_prag.adb
===================================================================
--- sem_prag.adb	(revision 244125)
+++ sem_prag.adb	(working copy)
@@ -17659,6 +17659,86 @@ 
             end loop;
          end Main_Storage;
 
+         ----------------------
+         -- Max_Queue_Length --
+         ----------------------
+
+         --  pragma Max_Queue_Length (static_integer_EXPRESSION);
+
+         when Pragma_Max_Queue_Length => Max_Queue_Length : declare
+            Arg        : Node_Id;
+            Entry_Decl : Node_Id;
+            Entry_Id   : Entity_Id;
+            Val        : Uint;
+
+         begin
+            GNAT_Pragma;
+            Check_Arg_Count (1);
+
+            Entry_Decl :=
+              Find_Related_Declaration_Or_Body (N, Do_Checks => True);
+
+            --  Entry declaration
+
+            if Nkind (Entry_Decl) = N_Entry_Declaration then
+
+               --  Entry illegally within a task
+
+               if Nkind (Parent (N)) = N_Task_Definition then
+                  Error_Pragma ("pragma % cannot apply to task entries");
+                  return;
+               end if;
+
+               Entry_Id := Unique_Defining_Entity (Entry_Decl);
+
+               --  Pragma illegally applied to an entry family
+
+               if Ekind (Entry_Id) = E_Entry_Family then
+                  Error_Pragma ("pragma % cannot apply to entry families");
+                  return;
+               end if;
+
+            --  Otherwise the pragma is associated with an illegal construct
+
+            else
+               Error_Pragma ("pragma % must apply to a protected entry");
+               return;
+            end if;
+
+            --  Mark the pragma as Ghost if the related subprogram is also
+            --  Ghost. This also ensures that any expansion performed further
+            --  below will produce Ghost nodes.
+
+            Mark_Pragma_As_Ghost (N, Entry_Id);
+
+            --  Analyze the Integer expression
+
+            Arg := Get_Pragma_Arg (Arg1);
+            Check_Arg_Is_OK_Static_Expression (Arg, Any_Integer);
+
+            Val := Expr_Value (Arg);
+
+            if Val <= 0 then
+               Error_Pragma_Arg
+                 ("argument for pragma% must be positive", Arg1);
+
+            elsif not UI_Is_In_Int_Range (Val) then
+               Error_Pragma_Arg
+                 ("argument for pragma% out of range of Integer", Arg1);
+
+            end if;
+
+            --  Manually subsitute the expression value of the pragma argument
+            --  if it not an integer literally because this is not taken care
+            --  of automatically elsewhere.
+
+            if Nkind (Arg) /= N_Integer_Literal then
+               Rewrite (Arg, Make_Integer_Literal (Sloc (Arg), Val));
+            end if;
+
+            Record_Rep_Item (Entry_Id, N);
+         end Max_Queue_Length;
+
          -----------------
          -- Memory_Size --
          -----------------
@@ -28642,6 +28722,7 @@ 
       Pragma_Machine_Attribute              => -1,
       Pragma_Main                           => -1,
       Pragma_Main_Storage                   => -1,
+      Pragma_Max_Queue_Length               =>  0,
       Pragma_Memory_Size                    =>  0,
       Pragma_No_Return                      =>  0,
       Pragma_No_Body                        =>  0,
Index: rtsfind.adb
===================================================================
--- rtsfind.adb	(revision 244124)
+++ rtsfind.adb	(working copy)
@@ -1351,7 +1351,7 @@ 
       --  is System. If so, return the value from the already compiled
       --  declaration and otherwise do a regular find.
 
-      --  Not pleasant, but these kinds of annoying recursion when
+      --  Not pleasant, but these kinds of annoying recursion senarios when
       --  writing an Ada compiler in Ada have to be broken somewhere.
 
       if Present (Main_Unit_Entity)
Index: rtsfind.ads
===================================================================
--- rtsfind.ads	(revision 244124)
+++ rtsfind.ads	(working copy)
@@ -1684,6 +1684,7 @@ 
 
      RE_Protected_Entry_Body_Array,      -- Tasking.Protected_Objects.Entries
      RE_Protected_Entry_Names_Array,     -- Tasking.Protected_Objects.Entries
+     RE_Protected_Entry_Queue_Max_Array, -- Tasking.Protected_Objects.Entries
      RE_Protection_Entries,              -- Tasking.Protected_Objects.Entries
      RE_Protection_Entries_Access,       -- Tasking.Protected_Objects.Entries
      RE_Initialize_Protection_Entries,   -- Tasking.Protected_Objects.Entries
@@ -1716,6 +1717,7 @@ 
      RE_Service_Entry,                   -- Protected_Objects.Single_Entry
      RE_Exceptional_Complete_Single_Entry_Body,
      RE_Protected_Count_Entry,           -- Protected_Objects.Single_Entry
+     RE_Protected_Entry_Queue_Max,       -- Protected_Objects.Single_Entry
      RE_Protected_Single_Entry_Caller,   -- Protected_Objects.Single_Entry
 
      RE_Protected_Entry_Index,           -- System.Tasking.Protected_Objects
@@ -2927,6 +2929,8 @@ 
        System_Tasking_Protected_Objects_Entries,
      RE_Protected_Entry_Names_Array      =>
        System_Tasking_Protected_Objects_Entries,
+     RE_Protected_Entry_Queue_Max_Array  =>
+       System_Tasking_Protected_Objects_Entries,
      RE_Protection_Entries               =>
        System_Tasking_Protected_Objects_Entries,
      RE_Protection_Entries_Access        =>
@@ -2989,6 +2993,8 @@ 
        System_Tasking_Protected_Objects_Single_Entry,
      RE_Protected_Count_Entry            =>
        System_Tasking_Protected_Objects_Single_Entry,
+     RE_Protected_Entry_Queue_Max        =>
+       System_Tasking_Protected_Objects_Single_Entry,
      RE_Protected_Single_Entry_Caller    =>
        System_Tasking_Protected_Objects_Single_Entry,
 
Index: sem_util.adb
===================================================================
--- sem_util.adb	(revision 244124)
+++ sem_util.adb	(working copy)
@@ -8351,6 +8351,24 @@ 
       pragma Assert (Name_Buffer (Name_Len + 1) = ' ');
    end Get_Library_Unit_Name_String;
 
+   --------------------------
+   -- Get_Max_Queue_Length --
+   --------------------------
+
+   function Get_Max_Queue_Length (Id : Entity_Id) return Uint is
+      Prag : constant Entity_Id := Get_Pragma (Id, Pragma_Max_Queue_Length);
+
+   begin
+      --  A value of 0 represents no maximum specified and entries and entry
+      --  families with no Max_Queue_Length aspect or pragma defaults to it.
+
+      if not Has_Max_Queue_Length (Id) or else not Present (Prag) then
+         return Uint_0;
+      end if;
+
+      return Intval (Expression (First (Pragma_Argument_Associations (Prag))));
+   end Get_Max_Queue_Length;
+
    ------------------------
    -- Get_Name_Entity_Id --
    ------------------------
@@ -9648,15 +9666,25 @@ 
       return False;
    end Has_Interfaces;
 
+   --------------------------
+   -- Has_Max_Queue_Length --
+   --------------------------
+
+   function Has_Max_Queue_Length (Id : Entity_Id) return Boolean is
+   begin
+      return
+        Ekind (Id) = E_Entry
+          and then Present (Get_Pragma (Id, Pragma_Max_Queue_Length));
+   end Has_Max_Queue_Length;
+
    ---------------------------------
    -- Has_No_Obvious_Side_Effects --
    ---------------------------------
 
    function Has_No_Obvious_Side_Effects (N : Node_Id) return Boolean is
    begin
-      --  For now, just handle literals, constants, and non-volatile
-      --  variables and expressions combining these with operators or
-      --  short circuit forms.
+      --  For now handle literals, constants, and non-volatile variables and
+      --  expressions combining these with operators or short circuit forms.
 
       if Nkind (N) in N_Numeric_Or_String_Literal then
          return True;
Index: sem_util.ads
===================================================================
--- sem_util.ads	(revision 244124)
+++ sem_util.ads	(working copy)
@@ -931,6 +931,10 @@ 
    --  Retrieve the fully expanded name of the library unit declared by
    --  Decl_Node into the name buffer.
 
+   function Get_Max_Queue_Length (Id : Entity_Id) return Uint;
+   --  Return the argument of pragma Max_Queue_Length or zero if the annotation
+   --  is not present. It is assumed that Id denotes an entry.
+
    function Get_Name_Entity_Id (Id : Name_Id) return Entity_Id;
    pragma Inline (Get_Name_Entity_Id);
    --  An entity value is associated with each name in the name table. The
@@ -1104,6 +1108,10 @@ 
    --  Use_Full_View controls if the check is done using its full view (if
    --  available).
 
+   function Has_Max_Queue_Length (Id : Entity_Id) return Boolean;
+   --  Determine whether Id is subject to pragma Max_Queue_Length. It is
+   --  assumed that Id denotes an entry.
+
    function Has_No_Obvious_Side_Effects (N : Node_Id) return Boolean;
    --  This is a simple minded function for determining whether an expression
    --  has no obvious side effects. It is used only for determining whether
Index: aspects.adb
===================================================================
--- aspects.adb	(revision 244124)
+++ aspects.adb	(working copy)
@@ -6,7 +6,7 @@ 
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---          Copyright (C) 2010-2015, Free Software Foundation, Inc.         --
+--          Copyright (C) 2010-2016, Free Software Foundation, Inc.         --
 --                                                                          --
 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
 -- terms of the  GNU General Public License as published  by the Free Soft- --
@@ -568,6 +568,7 @@ 
     Aspect_Linker_Section               => Aspect_Linker_Section,
     Aspect_Lock_Free                    => Aspect_Lock_Free,
     Aspect_Machine_Radix                => Aspect_Machine_Radix,
+    Aspect_Max_Queue_Length             => Aspect_Max_Queue_Length,
     Aspect_No_Elaboration_Code_All      => Aspect_No_Elaboration_Code_All,
     Aspect_No_Return                    => Aspect_No_Return,
     Aspect_No_Tagged_Streams            => Aspect_No_Tagged_Streams,
Index: aspects.ads
===================================================================
--- aspects.ads	(revision 244124)
+++ aspects.ads	(working copy)
@@ -116,6 +116,7 @@ 
       Aspect_Link_Name,
       Aspect_Linker_Section,                -- GNAT
       Aspect_Machine_Radix,
+      Aspect_Max_Queue_Length,              -- GNAT
       Aspect_Object_Size,                   -- GNAT
       Aspect_Obsolescent,                   -- GNAT
       Aspect_Output,
@@ -247,6 +248,7 @@ 
       Aspect_Inline_Always              => True,
       Aspect_Invariant                  => True,
       Aspect_Lock_Free                  => True,
+      Aspect_Max_Queue_Length           => True,
       Aspect_Object_Size                => True,
       Aspect_Persistent_BSS             => True,
       Aspect_Predicate                  => True,
@@ -353,6 +355,7 @@ 
       Aspect_Link_Name                  => Expression,
       Aspect_Linker_Section             => Expression,
       Aspect_Machine_Radix              => Expression,
+      Aspect_Max_Queue_Length           => Expression,
       Aspect_Object_Size                => Expression,
       Aspect_Obsolescent                => Optional_Expression,
       Aspect_Output                     => Name,
@@ -460,6 +463,7 @@ 
       Aspect_Linker_Section               => Name_Linker_Section,
       Aspect_Lock_Free                    => Name_Lock_Free,
       Aspect_Machine_Radix                => Name_Machine_Radix,
+      Aspect_Max_Queue_Length             => Name_Max_Queue_Length,
       Aspect_No_Elaboration_Code_All      => Name_No_Elaboration_Code_All,
       Aspect_No_Return                    => Name_No_Return,
       Aspect_No_Tagged_Streams            => Name_No_Tagged_Streams,
@@ -731,6 +735,7 @@ 
       Aspect_Import                       => Never_Delay,
       Aspect_Initial_Condition            => Never_Delay,
       Aspect_Initializes                  => Never_Delay,
+      Aspect_Max_Queue_Length             => Never_Delay,
       Aspect_No_Elaboration_Code_All      => Never_Delay,
       Aspect_No_Tagged_Streams            => Never_Delay,
       Aspect_Obsolescent                  => Never_Delay,
Index: par-prag.adb
===================================================================
--- par-prag.adb	(revision 244124)
+++ par-prag.adb	(working copy)
@@ -1396,6 +1396,7 @@ 
            Pragma_Machine_Attribute              |
            Pragma_Main                           |
            Pragma_Main_Storage                   |
+           Pragma_Max_Queue_Length               |
            Pragma_Memory_Size                    |
            Pragma_No_Body                        |
            Pragma_No_Elaboration_Code_All        |
Index: sem_ch13.adb
===================================================================
--- sem_ch13.adb	(revision 244124)
+++ sem_ch13.adb	(working copy)
@@ -2823,6 +2823,19 @@ 
                   goto Continue;
                end Initializes;
 
+               --  Max_Queue_Length
+
+               when Aspect_Max_Queue_Length =>
+                  Make_Aitem_Pragma
+                    (Pragma_Argument_Associations => New_List (
+                       Make_Pragma_Argument_Association (Loc,
+                         Expression => Relocate_Node (Expr))),
+                     Pragma_Name                  => Name_Max_Queue_Length);
+
+                  Decorate (Aspect, Aitem);
+                  Insert_Pragma (Aitem);
+                  goto Continue;
+
                --  Obsolescent
 
                when Aspect_Obsolescent => declare
@@ -9251,6 +9264,7 @@ 
               Aspect_Implicit_Dereference       |
               Aspect_Initial_Condition          |
               Aspect_Initializes                |
+              Aspect_Max_Queue_Length           |
               Aspect_Obsolescent                |
               Aspect_Part_Of                    |
               Aspect_Post                       |
Index: s-tposen.adb
===================================================================
--- s-tposen.adb	(revision 244124)
+++ s-tposen.adb	(working copy)
@@ -6,7 +6,7 @@ 
 --                                                                          --
 --                                B o d y                                   --
 --                                                                          --
---         Copyright (C) 1998-2013, Free Software Foundation, Inc.          --
+--         Copyright (C) 1998-2016, Free Software Foundation, Inc.          --
 --                                                                          --
 -- GNARL is free software; you can  redistribute it  and/or modify it under --
 -- terms of the  GNU General Public License as published  by the Free Soft- --
@@ -218,6 +218,7 @@ 
      (Object            : Protection_Entry_Access;
       Ceiling_Priority  : Integer;
       Compiler_Info     : System.Address;
+      Entry_Queue_Max   : Protected_Entry_Queue_Max_Access;
       Entry_Body        : Entry_Body_Access)
    is
    begin
@@ -226,6 +227,7 @@ 
       Object.Compiler_Info := Compiler_Info;
       Object.Call_In_Progress := null;
       Object.Entry_Body := Entry_Body;
+      Object.Entry_Queue_Max := Entry_Queue_Max;
       Object.Entry_Queue := null;
    end Initialize_Protection_Entry;
 
Index: s-tposen.ads
===================================================================
--- s-tposen.ads	(revision 244124)
+++ s-tposen.ads	(working copy)
@@ -6,7 +6,7 @@ 
 --                                                                          --
 --                                  S p e c                                 --
 --                                                                          --
---          Copyright (C) 1992-2013, Free Software Foundation, Inc.         --
+--          Copyright (C) 1992-2016, Free Software Foundation, Inc.         --
 --                                                                          --
 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
 -- terms of the  GNU General Public License as published  by the Free Soft- --
@@ -182,10 +182,16 @@ 
 
    type Protection_Entry_Access is access all Protection_Entry;
 
+   type Protected_Entry_Queue_Max is new Natural;
+
+   type Protected_Entry_Queue_Max_Access is
+     access all Protected_Entry_Queue_Max;
+
    procedure Initialize_Protection_Entry
      (Object            : Protection_Entry_Access;
       Ceiling_Priority  : Integer;
       Compiler_Info     : System.Address;
+      Entry_Queue_Max   : Protected_Entry_Queue_Max_Access;
       Entry_Body        : Entry_Body_Access);
    --  Initialize the Object parameter so that it can be used by the run time
    --  to keep track of the runtime state of a protected object.
@@ -270,6 +276,10 @@ 
 
       Entry_Queue : Entry_Call_Link;
       --  Place to store the waiting entry call (if any)
+
+      Entry_Queue_Max : Protected_Entry_Queue_Max_Access;
+      --  Access to a natural representing the max value for the single
+      --  entry's queue length. A value of 0 signifies no max.
    end record;
 
 end System.Tasking.Protected_Objects.Single_Entry;
Index: snames.ads-tmpl
===================================================================
--- snames.ads-tmpl	(revision 244124)
+++ snames.ads-tmpl	(working copy)
@@ -575,6 +575,7 @@ 
    Name_Machine_Attribute              : constant Name_Id := N + $; -- GNAT
    Name_Main                           : constant Name_Id := N + $; -- GNAT
    Name_Main_Storage                   : constant Name_Id := N + $; -- GNAT
+   Name_Max_Queue_Length               : constant Name_Id := N + $; -- GNAT
    Name_Memory_Size                    : constant Name_Id := N + $; -- Ada 83
    Name_No_Body                        : constant Name_Id := N + $; -- GNAT
    Name_No_Elaboration_Code_All        : constant Name_Id := N + $; -- GNAT
@@ -1904,6 +1905,7 @@ 
       Pragma_Machine_Attribute,
       Pragma_Main,
       Pragma_Main_Storage,
+      Pragma_Max_Queue_Length,
       Pragma_Memory_Size,
       Pragma_No_Body,
       Pragma_No_Elaboration_Code_All,