Annotated Ada Reference ManualLegal Information
Contents   Index   References   Search   Previous   Next 

9.5.2 Entries and Accept Statements

Entry_declarations, with the corresponding entry_bodies or accept_statements, are used to define potentially queued operations on tasks and protected objects. 


{AI95-00397-01} {AI05-0183-1} entry_declaration ::= 

   entry defining_identifier [(discrete_subtype_definition)] parameter_profile
accept_statement ::= 
   accept entry_direct_name [(entry_index)] parameter_profile [do
   end [entry_identifier]];
Reason: We cannot use defining_identifier for accept_statements. Although an accept_statement is sort of like a body, it can appear nested within a block_statement, and therefore be hidden from its own entry by an outer homograph. 
entry_index ::= expression
entry_body ::= 
  entry defining_identifier  entry_body_formal_part  entry_barrier is
  end [entry_identifier];
Discussion: {AI95-00397-01} We don't allow an overriding_indicator on an entry_body because entries always implement procedures at the point of the type declaration; there is no late implementation. And we don't want to have to think about overriding_indicators on accept_statements.
entry_body_formal_part ::= [(entry_index_specification)] parameter_profile
entry_barrier ::= when condition
entry_index_specification ::= for defining_identifier in discrete_subtype_definition
If an entry_identifier appears at the end of an accept_statement, it shall repeat the entry_direct_name. If an entry_identifier appears at the end of an entry_body, it shall repeat the defining_identifier.
[An entry_declaration is allowed only in a protected or task declaration.] 
Proof: This follows from the BNF. 
{AI95-00397-01} An overriding_indicator is not allowed in an entry_declaration that includes a discrete_subtype_definition.
Reason: An entry family can never implement something, so allowing an indicator is felt by the majority of the ARG to be redundant. 

Name Resolution Rules

In an accept_statement, the expected profile for the entry_direct_name is that of the entry_declaration; the expected type for an entry_index is that of the subtype defined by the discrete_subtype_definition of the corresponding entry_declaration.
Within the handled_sequence_of_statements of an accept_statement, if a selected_component has a prefix that denotes the corresponding entry_declaration, then the entity denoted by the prefix is the accept_statement, and the selected_component is interpreted as an expanded name (see 4.1.3)[; the selector_name of the selected_component has to be the identifier for some formal parameter of the accept_statement].
Proof: The only declarations that occur immediately within the declarative region of an accept_statement are those for its formal parameters. 

Legality Rules

An entry_declaration in a task declaration shall not contain a specification for an access parameter (see 3.10). 
Reason: Access parameters for task entries would require a complex implementation. For example: 
task T is
   entry E(Z : access Integer); -- Illegal!
end T;
task body T is
      type A is access all Integer;
      X : A;
      Int : aliased Integer;
      task Inner;
      task body Inner is
      end Inner;
      accept E(Z : access Integer) do
         X := A(Z); -- Accessibility_Check
      end E;
end T;
Implementing the Accessibility_Check inside the accept_statement for E is difficult, since one does not know whether the entry caller is calling from inside the immediately enclosing declare block or from outside it. This means that the lexical nesting level associated with the designated object is not sufficient to determine whether the Accessibility_Check should pass or fail.
Note that such problems do not arise with protected entries, because entry_bodies are always nested immediately within the protected_body; they cannot be further nested as can accept_statements, nor can they be called from within the protected_body (since no entry calls are permitted inside a protected_body).
   {AI95-00397-01} If an entry_declaration has an overriding_indicator, then at the point of the declaration: 
if the overriding_indicator is overriding, then the entry shall implement an inherited subprogram;
if the overriding_indicator is not overriding, then the entry shall not implement any inherited subprogram.
   In addition to the places where Legality Rules normally apply (see 12.3), these rules also apply in the private part of an instance of a generic unit.
Discussion: These rules are subtly different than those for subprograms (see 8.3.1) because there cannot be “late” inheritance of primitives from interfaces. Hidden (that is, private) interfaces are prohibited explicitly (see 7.3), as are hidden primitive operations (as private operations of public abstract types are prohibited — see 3.9.3). 
For an accept_statement, the innermost enclosing body shall be a task_body, and the entry_direct_name shall denote an entry_declaration in the corresponding task declaration; the profile of the accept_statement shall conform fully to that of the corresponding entry_declaration. An accept_statement shall have a parenthesized entry_index if and only if the corresponding entry_declaration has a discrete_subtype_definition.
An accept_statement shall not be within another accept_statement that corresponds to the same entry_declaration, nor within an asynchronous_select inner to the enclosing task_body.
Reason: Accept_statements are required to be immediately within the enclosing task_body (as opposed to being in a nested subprogram) to ensure that a nested task does not attempt to accept the entry of its enclosing task. We considered relaxing this restriction, either by making the check a run-time check, or by allowing a nested task to accept an entry of its enclosing task. However, neither change seemed to provide sufficient benefit to justify the additional implementation burden.
Nested accept_statements for the same entry (or entry family) are prohibited to ensure that there is no ambiguity in the resolution of an expanded name for a formal parameter of the entry. This could be relaxed by allowing the inner one to hide the outer one from all visibility, but again the small added benefit didn't seem to justify making the change for Ada 95.
Accept_statements are not permitted within asynchronous_select statements to simplify the semantics and implementation: an accept_statement in an abortable_part could result in Tasking_Error being propagated from an entry call even though the target task was still callable; implementations that use multiple tasks implicitly to implement an asynchronous_select might have trouble supporting "up-level" accepts. Furthermore, if accept_statements were permitted in the abortable_part, a task could call its own entry and then accept it in the abortable_part, leading to rather unusual and possibly difficult-to-specify semantics.
An entry_declaration of a protected unit requires a completion[, which shall be an entry_body,] and every entry_body shall be the completion of an entry_declaration of a protected unit. The profile of the entry_body shall conform fully to that of the corresponding declaration.
Ramification: An entry_declaration, unlike a subprogram_declaration, cannot be completed with a renaming_declaration.
To be honest: {AI05-0229-1} If The completion can be a pragma Import, if the implementation supports it, the entry body can be imported (using aspect Import, see B.1), in which case no explicit entry_body is allowed
Discussion: The above applies only to protected entries, which are the only ones completed with entry_bodies. Task entries have corresponding accept_statements instead of having entry_bodies, and we do not consider an accept_statement to be a “completion,” because a task entry_declaration is allowed to have zero, one, or more than one corresponding accept_statements.
An entry_body_formal_part shall have an entry_index_specification if and only if the corresponding entry_declaration has a discrete_subtype_definition. In this case, the discrete_subtype_definitions of the entry_declaration and the entry_index_specification shall fully conform to one another (see 6.3.1).
A name that denotes a formal parameter of an entry_body is not allowed within the entry_barrier of the entry_body.

Static Semantics

The parameter modes defined for parameters in the parameter_profile of an entry_declaration are the same as for a subprogram_declaration and have the same meaning (see 6.2). 
Discussion: Note that access parameters are not allowed for task entries (see above). 
An entry_declaration with a discrete_subtype_definition (see 3.6) declares a family of distinct entries having the same profile, with one such entry for each value of the entry index subtype defined by the discrete_subtype_definition. [A name for an entry of a family takes the form of an indexed_component, where the prefix denotes the entry_declaration for the family, and the index value identifies the entry within the family.] The term single entry is used to refer to any entry other than an entry of an entry family.
In the entry_body for an entry family, the entry_index_specification declares a named constant whose subtype is the entry index subtype defined by the corresponding entry_declaration; the value of the named entry index identifies which entry of the family was called. 
Ramification: The discrete_subtype_definition of the entry_index_specification is not elaborated; the subtype of the named constant declared is defined by the discrete_subtype_definition of the corresponding entry_declaration, which is elaborated, either when the type is declared, or when the object is created, if its constraint is per-object. 

Dynamic Semantics

 {8652/0002} {AI95-00171-01} The elaboration of an entry_declaration for an entry family consists of the elaboration of the discrete_subtype_definition, as described in 3.8. For the elaboration of an entry_declaration for an entry family, if the discrete_subtype_definition contains no per-object expressions (see 3.8), then the discrete_subtype_definition is elaborated. Otherwise, the elaboration of the entry_declaration consists of the evaluation of any expression of the discrete_subtype_definition that is not a per-object expression (or part of one). The elaboration of an entry_declaration for a single entry has no effect. 
Discussion: The elaboration of the declaration of a protected subprogram has no effect, as specified in clause 6.1. The default initialization of an object of a task or protected type is covered in 3.3.1
[The actions to be performed when an entry is called are specified by the corresponding accept_statements (if any) for an entry of a task unit, and by the corresponding entry_body for an entry of a protected unit.]
For the execution of an accept_statement, the entry_index, if any, is first evaluated and converted to the entry index subtype; this index value identifies which entry of the family is to be accepted. Further execution of the accept_statement is then blocked until a caller of the corresponding entry is selected (see 9.5.3), whereupon the handled_sequence_of_statements, if any, of the accept_statement is executed, with the formal parameters associated with the corresponding actual parameters of the selected entry call. Upon completion of the handled_sequence_of_statements, the accept_statement completes and is left. When an exception is propagated from the handled_sequence_of_statements of an accept_statement, the same exception is also raised by the execution of the corresponding entry_call_statement.
Ramification: This is in addition to propagating it to the construct containing the accept_statement. In other words, for a rendezvous, the raising splits in two, and continues concurrently in both tasks.
The caller gets a new occurrence; this isn't considered propagation.
Note that we say “propagated from the handled_sequence_of_statements of an accept_statement”, not “propagated from an accept_statement.” The latter would be wrong — we don't want exceptions propagated by the entry_index to be sent to the caller (there is none yet!). 
The above interaction between a calling task and an accepting task is called a rendezvous. [After a rendezvous, the two tasks continue their execution independently.]
[An entry_body is executed when the condition of the entry_barrier evaluates to True and a caller of the corresponding single entry, or entry of the corresponding entry family, has been selected (see 9.5.3).] For the execution of the entry_body, the declarative_part of the entry_body is elaborated, and the handled_sequence_of_statements of the body is executed, as for the execution of a subprogram_body. The value of the named entry index, if any, is determined by the value of the entry index specified in the entry_name of the selected entry call (or intermediate requeue_statement — see 9.5.4). 
To be honest: If the entry had been renamed as a subprogram, and the call was a procedure_call_statement using the name declared by the renaming, the entry index (if any) comes from the entry name specified in the subprogram_renaming_declaration.
24  A task entry has corresponding accept_statements (zero or more), whereas a protected entry has a corresponding entry_body (exactly one).
25  A consequence of the rule regarding the allowed placements of accept_statements is that a task can execute accept_statements only for its own entries.
26  {AI95-00318-02} A return statement return_statement (see 6.5) or a requeue_statement (see 9.5.4) may be used to complete the execution of an accept_statement or an entry_body.
Ramification: An accept_statement need not have a handled_sequence_of_statements even if the corresponding entry has parameters. Equally, it can have a handled_sequence_of_statements even if the corresponding entry has no parameters. 
Ramification: A single entry overloads a subprogram, an enumeration literal, or another single entry if they have the same defining_identifier. Overloading is not allowed for entry family names. A single entry or an entry of an entry family can be renamed as a procedure as explained in 8.5.4
27  The condition in the entry_barrier may reference anything visible except the formal parameters of the entry. This includes the entry index (if any), the components (including discriminants) of the protected object, the Count attribute of an entry of that protected object, and data global to the protected unit.
The restriction against referencing the formal parameters within an entry_barrier ensures that all calls of the same entry see the same barrier value. If it is necessary to look at the parameters of an entry call before deciding whether to handle it, the entry_barrier can be “when True” and the caller can be requeued (on some private entry) when its parameters indicate that it cannot be handled immediately. 


Examples of entry declarations: 
entry Read(V : out Item);
entry Seize;
entry Request(Level)(D : Item);  --  a family of entries
Examples of accept statements: 
accept Shut_Down;
accept Read(V : out Item) do
   V := Local_Item;
end Read;
accept Request(Low)(D : Item) do
end Request;

Extensions to Ada 83

The syntax rule for entry_body is new.
Accept_statements can now have exception_handlers.

Wording Changes from Ada 95

{8652/0002} {AI95-00171-01} Corrigendum: Clarified the elaboration of per-object constraints.
{AI95-00397-01} Overriding_indicators can be used on entries; this is only useful when a task or protected type inherits from an interface. 

Extensions to Ada 2005

{AI05-0183-1} An optional aspect_specification can be used in an entry_declaration. This is described in 13.3.1. 

Contents   Index   References   Search   Previous   Next 
Ada-Europe Ada 2005 and 2012 Editions sponsored in part by Ada-Europe