9.5.2 Entries and Accept Statements
1
Entry_declarations, with
the corresponding entry_bodies or accept_statements,
are used to define potentially queued operations on tasks and protected
objects.
Syntax
2/2
{
AI95-00397-01}
entry_declaration ::=
[overriding_indicator]
entry defining_identifier [(
discrete_subtype_definition)]
parameter_profile;
3
accept_statement ::=
accept entry_direct_name [(
entry_index)]
parameter_profile [
do
handled_sequence_of_statements
end [
entry_identifier]];
3.a
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.
4
entry_index ::= expression
5
entry_body ::=
entry defining_identifier entry_body_formal_part entry_barrier is
declarative_part
begin
handled_sequence_of_statements
end [
entry_identifier];
5.a/2
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.
6
entry_body_formal_part ::= [(
entry_index_specification)]
parameter_profile
7
entry_barrier ::= when condition
8
entry_index_specification ::= for defining_identifier in discrete_subtype_definition
9
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.
10
[An entry_declaration
is allowed only in a protected or task declaration.]
10.a
Proof: This follows from the BNF.
10.1/2
{
AI95-00397-01}
An overriding_indicator
is not allowed in an entry_declaration that
includes a discrete_subtype_definition.
10.a.1/2
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
11
{expected profile
(accept_statement entry_direct_name) [partial]} In
an
accept_statement, the expected profile
for the
entry_direct_name is that of
the
entry_declaration;
{expected
type (entry_index) [partial]} the expected
type for an
entry_index is that of the subtype
defined by the
discrete_subtype_definition
of the corresponding
entry_declaration.
12
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].
12.a
Proof: The only declarations that occur
immediately within the declarative region of an accept_statement
are those for its formal parameters.
Legality Rules
13
An
entry_declaration in
a task declaration shall not contain a specification for an access parameter
(see
3.10).
13.a
Reason: Access
parameters for task entries would require a complex implementation. For
example:
13.b
task T is
entry E(Z : access Integer); -- Illegal!
end T;
13.c
task body T is
begin
declare
type A is access all Integer;
X : A;
Int : aliased Integer;
task Inner;
task body Inner is
begin
T.E(Int'Access);
end Inner;
begin
accept E(Z : access Integer) do
X := A(Z); -- Accessibility_Check
end E;
end;
end T;
13.d
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.
13.e
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).
13.1/2
{
AI95-00397-01}
If an entry_declaration
has an overriding_indicator, then at the point
of the declaration:
13.2/2
- if the overriding_indicator
is overriding, then the entry shall implement an inherited subprogram;
13.3/2
- if the overriding_indicator
is not overriding, then the entry shall not implement any inherited
subprogram.
13.4/2
{generic
contract issue [partial]} 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.
13.f/2
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).
14
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.
{full conformance (required)}
An
accept_statement shall
have a parenthesized
entry_index if and only
if the corresponding
entry_declaration has
a
discrete_subtype_definition.
15
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.
15.a
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.
15.b
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.
15.c
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.
16
{requires a completion
(protected entry_declaration) [partial]} An
entry_declaration of a protected unit requires
a completion[, which shall be an
entry_body,]
{only as a completion (entry_body)
[partial]} and every
entry_body
shall be the completion of an
entry_declaration
of a protected unit.
{completion legality
(entry_body) [partial]} The profile of
the
entry_body shall conform fully to that
of the corresponding declaration.
{full
conformance (required)}
16.a
Ramification: An entry_declaration,
unlike a subprogram_declaration, cannot be
completed with a renaming_declaration.
16.b
To be honest: The completion can be a
pragma Import, if the implementation supports
it.
16.c
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.
17
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).
{full conformance (required)}
18
A name that denotes a formal parameter of an entry_body
is not allowed within the entry_barrier of
the entry_body.
Static Semantics
19
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).
19.a
Discussion: Note that access parameters
are not allowed for task entries (see above).
20
{family (entry)}
{entry family}
{entry index subtype}
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.]
{single entry} {entry
(single)} The term
single entry
is used to refer to any entry other than an entry of an entry family.
21
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;
{named
entry index} the value of the
named
entry index identifies which entry of the family was called.
21.a
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
22/1
{
8652/0002}
{
AI-00171-01}
{elaboration (entry_declaration)
[partial]} 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.
22.a
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.
23
[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.]
24
{execution (accept_statement)
[partial]} 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.
{implicit
subtype conversion (entry index) [partial]} {blocked
(on an accept_statement) [partial]} {selection
(of an entry caller)} 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.
24.a
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.
24.b
The caller gets a new occurrence; this isn't
considered propagation.
24.c
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!).
25
{rendezvous}
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.]
26
[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).]
{execution (entry_body) [partial]}
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).
26.a
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.
27
23 A task entry has corresponding accept_statements
(zero or more), whereas a protected entry has a corresponding entry_body
(exactly one).
28
24 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.
29/2
25 {
AI-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.
29.a
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.
29.b
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.
30
26 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.
31
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
32
Examples of entry
declarations:
33
entry Read(V : out Item);
entry Seize;
entry Request(Level)(D : Item); -- a family of entries
34
Examples of accept
statements:
35
accept Shut_Down;
36
accept Read(V : out Item) do
V := Local_Item;
end Read;
37
accept Request(Low)(D : Item) do
...
end Request;
Extensions to Ada 83
37.a
{
extensions to Ada 83}
The
syntax rule for
entry_body is new.
37.b
Accept_statements
can now have exception_handlers.
Wording Changes from Ada 95
37.c/2
37.d/2
{
AI95-00397-01}
Overriding_indicators
can be used on entries; this is only useful when a task or protected
type inherits from an interface.