9.5 Intertask Communication
The primary
means for intertask communication is provided by calls on entries and
protected subprograms. Calls on protected subprograms allow coordinated
access to shared data objects. Entry calls allow for blocking the caller
until a given condition is satisfied (namely, that the corresponding
entry is open — see
9.5.3), and then
communicating data or control information directly with another task
or indirectly via a shared protected object.
Static Semantics
{
AI05-0225-1}
{
AI05-0291-1}
When a
name
or
prefix
denotes an entry, protected subprogram, or a prefixed view of a primitive
subprogram of a limited interface whose first parameter is a controlling
parameter, the
name
or
prefix
determines a
target object, as follows:
To be honest: {
AI05-0291-1}
This wording uses "denotes" to mean "denotes a view of
an entity" (when the term is used in Legality Rules), and "denotes
an entity" (when the term is used in Dynamic Semantics rules). It
does not mean "view of a declaration", as that would not include
renames (a renames is not an entry or protected subprogram).
{
AI05-0291-1}
If it is a
direct_name
or expanded name that denotes the declaration (or body) of the operation,
then the target object is implicitly specified to be the current instance
of the task or protected unit immediately enclosing the operation;
a
call using such a name is defined to be an
internal call;
{
AI05-0291-1}
If it is a
selected_component
that is not an expanded name, then the target object is explicitly specified
to be the object denoted by the
prefix
of the
name;
a call using such a name is defined to be an
external
call;
Discussion: For example:
protected type Pt is
procedure Op1;
procedure Op2;
end Pt;
PO : Pt;
Other_Object : Some_Other_Protected_Type;
protected body Pt is
procedure Op1 is begin ... end Op1;
{
AI12-0005-1}
procedure Op2
is
begin
Op1; --
An internal call.
Pt.Op1; --
Another internal call.
PO.Op1; --
An external call. If the current instance is PO, then
--
this is a bounded error (see 9.5.1).
Other_Object.Some_Op; --
An external call.
end Op2;
end Pt;
{
AI05-0291-1}
If the
name
or
prefix
is a dereference (implicit or explicit) of an access-to-protected-subprogram
value, then the target object is determined by the
prefix
of the Access
attribute_reference
that produced the access value originally; a call using such a name is
defined to be an
external call;
{
AI05-0291-1}
A call on an entry or a protected subprogram either uses a
name
or
prefix
that determines a target object implicitly, as above, or is a call on
(a non-prefixed view of) a primitive subprogram of a limited interface
whose first parameter is a controlling parameter, in which case the target
object is identified explicitly by the first parameter. This latter case
is an
external call.
A
corresponding definition of target object applies to a
requeue_statement
(see
9.5.4), with a corresponding distinction
between an
internal requeue and an
external requeue.
Legality Rules
Reason: {
AI05-0225-1}
The point is to prevent any calls to such a
name
whose target object is a constant view of a protected object, directly,
or via an access value, renames, or generic formal subprogram. It is,
however, legal to say P'Count in a protected function body, even though
the protected object is a constant view there.
Ramification: {
AI05-0291-1}
This rule does not apply to calls that are not to a prefixed view. Specifically
a "normal" call to a primitive operation of a limited interface
is not covered by this rule. In that case, the normal parameter passing
mode checks will prevent passing a constant protected object to an operation
implemented by a protected entry or procedure as the mode is required
to be
in out or
out.
Reason: {
AI125-0166-1}
These calls will be made before the start of the protected action, and
thus would not be subject to the expected mutual exclusion. As such,
they would be an automatic race condition (the state of the called object
could change before the start of the protected action for the call on
the protected entry or subprogram).
To be honest: {
AI125-0166-1}
6.1.1 actually defines "specific precondition
expression" and "class-wide precondition expression".
This rule is intended to apply to both.
Dynamic Semantics
Within the body of a protected operation, the current
instance (see
8.6) of the immediately enclosing
protected unit is determined by the target object specified (implicitly
or explicitly) in the call (or requeue) on the protected operation.
To be honest: The current instance is
defined in the same way within the body of a subprogram declared immediately
within a
protected_body.
Any call on a protected procedure or entry of a target
protected object is defined to be an update to the object, as is a requeue
on such an entry.
Reason: Read/write access to the components
of a protected object is granted while inside the body of a protected
procedure or entry. Also, any protected entry call can change the value
of the Count attribute, which represents an update. Any protected procedure
call can result in servicing the entries, which again might change the
value of a Count attribute.
Syntax
Static Semantics
{
AI05-0215-1}
For the declaration of a primitive procedure of a synchronized tagged
type the following language-defined representation aspect may be specified
with an
aspect_specification
(see
13.1.1):
Synchronization
If specified, the aspect definition shall be a
synchronization_kind.
Aspect Description for Synchronization:
Defines whether a given primitive operation of a synchronized interface
will be implemented by an entry or protected procedure.
{
AI05-0030-2}
{
AI05-0215-1}
Inherited subprograms inherit the Synchronization aspect, if any, from
the corresponding subprogram of the parent or progenitor type. If an
overriding operation does not have a directly specified Synchronization
aspect then the Synchronization aspect of the inherited operation is
inherited by the overriding operation.
Legality Rules
{
AI05-0030-2}
{
AI05-0215-1}
A procedure for which the specified
synchronization_kind
is By_Entry shall be implemented by an entry. A procedure for which the
specified
synchronization_kind
is By_Protected_Procedure shall be implemented by a protected procedure.
A procedure for which the specified
synchronization_kind
is Optional may be implemented by an entry or by a procedure (including
a protected procedure).
{
AI05-0030-2}
{
AI05-0215-1}
If a primitive procedure overrides an inherited operation for which the
Synchronization aspect has been specified to be By_Entry or By_Protected_Procedure,
then any specification of the aspect Synchronization applied to the overriding
operation shall have the same
synchronization_kind.
{
AI05-0030-2}
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.
Static Semantics
{
AI12-0064-2}
{
AI12-0374-2}
For a program unit, task entry, formal package, formal subprogram, formal
object of an anonymous access-to-subprogram type, enumeration literal,
and for a subtype (including a formal subtype), the following language-defined
operational aspect is defined:
Nonblocking
This aspect specifies the blocking restriction for the entity; it shall
be specified by a static Boolean expression. [The
aspect_definition
can be omitted from the specification of this aspect; in that case, the
aspect for the entity is True.
]
Aspect Description for Nonblocking:
Specifies that an associated subprogram does not block.
Proof: 13.1.1
allows omitting the aspect
expression
for any aspect with type Boolean; we take advantage of that here.
{
AI12-0064-2}
The Nonblocking aspect may be specified for all entities for which it
is defined, except for protected operations and task entries. In particular,
Nonblocking may be specified for generic formal parameters.
Ramification: The Nonblocking aspect
cannot be specified for predefined operators or enumeration literals
but we don't need to mention that above. One would have to declare a
subprogram in order to specify the aspect in those cases, but that defines
a user-defined subprogram which is itself not a predefined operator or
an enumeration literal.
{
AI12-0064-2}
{
AI12-0374-2}
{
AI12-0439-1}
When aspect Nonblocking is False for an entity, the entity can contain
a potentially blocking operation; such an entity
allows blocking.
If the aspect is True for an entity, the entity is said to be
nonblocking.
Ramification: Specifying Nonblocking
as False imposes no restrictions. Specifying Nonblocking as True imposes
additional compile-time checks to prevent blocking, but does not prevent
deadlock. A pragma Detect_Blocking can be used to ensure that Program_Error
is raised in a deadlock situation.
{
AI12-0064-2}
{
AI12-0374-2}
For a generic instantiation and entities declared within such an instance,
the aspect is determined by the Nonblocking aspect for the corresponding
entity of the generic unit,
anded with the Nonblocking aspects
of the actual generic parameters
used by the entity. If the aspect
is directly specified for an instance, the specified expression shall
have the same value as the Nonblocking aspect of the instance (after
anding with the aspects of the used actual parameters). In the
absence of a Use_Formal aspect, all actual generic parameters are presumed
to be
used by an entity (see
H.7.1).
Reason: We want to allow confirming aspects
for instances, but nothing else. The Legality Rules of the generic body
were checked assuming the Nonblocking aspect of the generic unit combined
with the Nonblocking aspects of the formals where they are used, and
if that is overridden on the instance, the instance body might make calls
that allow blocking in subprograms that are declared nonblocking.
{
AI12-0064-2}
{
AI12-0374-2}
For a (protected or task) entry, the Nonblocking aspect is False.
Reason: An entry can be renamed as a
procedure, so the value of the aspect has to be well-defined (as the
attribute can be applied to a procedure). We do not want a nonblocking
subprogram to be able to call an entry, no matter how it occurs, so the
value ought to be False. Moreover, we do not want a subprogram that renames
an entry to be able to override a nonblocking subprogram. We could have
used individual rules for these cases, but there were already many of
them, and this solution avoids the need for extra rules for entries.
{
AI12-0064-2}
{
AI12-0374-2}
For an enumeration literal, the Nonblocking aspect is True.
Reason: Enumeration literals can be renamed
as functions, and passed to generic formal functions, so we need to define
the value of the aspect to ensure the other rules are meaningful.
{
AI12-0064-2}
{
AI12-0374-2}
For a predefined operator of an elementary type, the Nonblocking aspect
is True. For a predefined operator of a composite type, the Nonblocking
aspect of the operator is the same as the Nonblocking aspect for the
type.
Reason: Predefined operators of elementary
types can never include any potentially blocking operations, so we want
them to declare that. Record equality can be composed of operations including
user-defined "=" operators, which might allow blocking. Array
equality might use some record equality. So we have to have the possibility
of allowing blocking for them. We don't just copy the Nonblocking aspect
of the type in every case, as someone could declare an elementary type
to allow blocking.
Ramification: It's not possible to specify
the nonblocking expression of a predefined operator; if an operator is
declared in order to do that, it is no longer predefined.
{
AI12-0064-2}
For a dereference of an access-to-subprogram type, the Nonblocking aspect
of the designated subprogram is that of the access-to-subprogram type.
{
AI12-0374-2}
For the base subtype of a scalar (sub)type, the Nonblocking aspect is
True.
Reason: The first subtype of a scalar
type can allow blocking (which can be useful so a predicate can allow
blocking), but the base subtype is always Nonblocking. We need this so
the Nonblocking value is well-defined for any subtype that is built from
the base subtype (T'Base). T'Base of any scalar type, including a generic
formal type, is always nonblocking.
{
AI12-0064-2}
For an inherited primitive dispatching subprogram that is null or abstract,
the subprogram is nonblocking if and only if a corresponding subprogram
of at least one ancestor is nonblocking. For any other inherited subprogram,
it is nonblocking if and only if the corresponding subprogram of the
parent is nonblocking.
{
AI12-0064-2}
Unless directly specified, overridings of dispatching operations inherit
this aspect.
{
AI12-0064-2}
{
AI12-0374-2}
Unless directly specified, for a formal subtype, formal package, or formal
subprogram, the Nonblocking aspect is that of the actual subtype, package,
or subprogram.
Reason: This means that Nonblocking legality
checking for the actual parameters of the instance is only necessary
when the aspect is explicitly specified for the formal type.
{
AI12-0064-2}
{
AI12-0374-2}
Unless directly specified, for a non-first subtype
S, the Nonblocking
aspect is that of the subtype identified in the subtype_indication defining
S; unless directly specified for the first subtype of a derived
type, the Nonblocking aspect is that of the ancestor subtype.
Discussion: The expressions that can
be specified for a such a subtype are limited by a Legality Rule, see
below.
{
AI12-0064-2}
Unless directly specified, for any other program unit, first subtype,
or formal object, the Nonblocking aspect of the entity is determined
by the Nonblocking aspect for the innermost program unit enclosing the
entity.
{
AI12-0064-2}
{
AI12-0374-2}
If not specified for a library unit, the Nonblocking aspect is True if
the library unit is declared pure, or False otherwise.
Reason: The primary purpose of these
rules is to define what operations are not allowed in a protected operation
(blocking is not allowed). Some of these operations are not directly
blocking. However, they are still treated as potentially blocking, because
allowing them in a protected action might impose an undesirable implementation
burden.
task creation or activation;
during a protected action, an external call on
a protected subprogram (or an external requeue) with the same target
object as that of the protected action.
Reason: This is really a deadlocking
call, rather than a blocking call, but we include it in this list for
simplicity.
{
AI12-0064-2}
If a language-defined subprogram allows blocking, then a call on the
subprogram is a potentially blocking operation.
Ramification: Calls on other subprograms
that allow blocking are not themselves potentially blocking; the execution
of the body could execute a potentially blocking operation.
A user-defined instance of a language-defined
generic creates user-defined subprograms for the purpose of this rule.
A dispatching call to a language-defined abstract subprogram always calls
a user-defined concrete subprogram, so that too is not potentially blocking
for the purposes of this rule.
Legality Rules
{
AI12-0064-2}
{
AI12-0267-1}
{
AI12-0374-2}
A portion of program text is called a
nonblocking region
if it is anywhere within a parallel construct, or if the innermost enclosing
program unit is nonblocking. A nonblocking region shall not contain any
of the following:
task creation or activation.
{
AI12-0374-2}
Furthermore, a parallel construct shall neither contain a call on a callable
entity for which the Nonblocking aspect is False, nor shall it contain
a call on a callable entity declared within a generic unit that uses
a generic formal parameter with Nonblocking aspect False (see Use_Formal
aspect in
H.7.1).
{
AI12-0374-2}
Finally, a nonblocking region that is outside of a parallel construct
shall not contain a call on a callable entity for which the Nonblocking
aspect is False, unless the region is within a generic unit and the callable
entity is associated with a generic formal parameter of the generic unit,
or the call is within the
aspect_definition
of an assertion aspect for an entity that allows blocking.
Reason: A generic unit or entity declared
within one is presumed to use its "used" generic formal parameters
at least once each time it is invoked, and this passes through to the
parallel construct check.
Ramification: Implicit calls for finalization,
storage pools, and the like are covered by the above prohibition. The
rules above say “a call”, not “an explicit call”.
Such calls are considered statically bound when that is possible, that
is, when the controlling object has a known specific type (even if the
actual implementation uses dispatching).
Discussion: We don't need to worry specially
about entry calls (even if the entry has been renamed as a procedure),
as they will be detected by the prohibition against calls to entities
with the Nonblocking aspect False.
Similarly, we don't need to specially worry
about subprograms of limited interfaces that are implemented by entries,
as any such subprogram necessarily has the value statically False for
the Nonblocking aspect, and thus is already covered by the prohibition
against calling such subprograms.
{
AI12-0064-2}
{
AI12-0374-2}
For the purposes of the above rules, an
entry_body
is considered nonblocking if the immediately enclosing protected unit
is nonblocking.
Reason: An entry declaration always allows
blocking (by rule); but we want to be able to compile-time check for
most violations of the prohibition against potentially blocking operations
in a protected action (see
9.5.1). We do
that by using the nonblocking status of the protected unit as the controlling
factor, and enforce that by not allowing the specification of the Nonblocking
aspect for any protected operation. We can't do this checking unconditionally,
as that would be incompatible: existing Ada protected units might call
subprograms that allow blocking. Thus a protected unit that allows blocking
(which is the default) must allow calling any subprogram from an entry
body.
{
AI12-0374-2}
For a subtype for which aspect Nonblocking is True, any predicate expression
that applies to the subtype shall only contain constructs that are allowed
immediately within a nonblocking program unit.
{
AI12-0064-2}
A subprogram shall be nonblocking if it overrides a nonblocking dispatching
operation. An entry shall not implement a nonblocking procedure. If an
inherited dispatching subprogram allows blocking, then the corresponding
subprogram of each ancestor shall allow blocking.
Discussion: Rules elsewhere in the standard
(
4.6 and
3.10.2)
ensure that access-to-subprogram conversion and the Access attribute
enforce nonblocking.
Ramification: A nonblocking subprogram
can override one that allows blocking, but the reverse is illegal. Thus
one can declare a Finalize subprogram to be nonblocking, even though
it overrides a routine that allows blocking. (This works because a nonblocking
subprogram allows a strict subset of the operations allowed in allows
blocking subprograms, so calling such a subprogram as if it allows blocking
— as is necessary in a dispatching call — is harmless.)
{
AI12-0064-2}
{
AI12-0374-2}
{
AI12-0396-1}
{
AI12-0399-1}
It is illegal to directly specify aspect Nonblocking for the first subtype
of the full view of a type that has a partial view. If the Nonblocking
aspect of the full view is inherited, it shall have the same value as
that of the partial view, or have the value True.
Reason: We need completions to agree
on nonblocking with the original view. One reason this is necessary to
prevent the predefined equality operator from being nonblocking in the
partial view and allowing blocking in the full view.
{
AI12-0064-2}
{
AI12-0374-2}
Aspect Nonblocking shall be directly specified for the first subtype
of a derived type only if it has the same value as the Nonblocking aspect
of the ancestor subtype or if it is specified True. Aspect Nonblocking
shall be directly specified for a nonfirst subtype
S only if it
has the same value as the Nonblocking aspect of the subtype identified
in the
subtype_indication
defining
S or if it is specified True.
Reason: Boolean-valued aspects have a
similar rule to the first rule here (see
13.1.1),
we want this one to work similarly. We need non-first subtypes to allow
blocking only if the original first subtype allows blocking, as that
allows the programmer to know that any operation on any subtype of a
type are nonblocking if the first subtype is nonblocking.
{
AI12-0319-1}
For an access-to-object type that is nonblocking, the Allocate, Deallocate,
and Storage_Size operations on its storage pool shall be nonblocking.
Ramification: Standard storage pools
always have nonblocking operations by definition (see
13.11),
so this rule only can fail for user-defined storage pools.
{
AI12-0319-1}
For a composite type that is nonblocking:
All component subtypes shall be nonblocking;
For a record type or extension, every call in the
default_expression
of a component (including discriminants) shall call an operation that
is nonblocking;
For a controlled type, the Initialize, Finalize,
and Adjust (if any) subprograms shall be nonblocking.
Reason: These rules ensure that if a
type is nonblocking, the default initialization, finalization, and assignment
of the type are also nonblocking. This ensures that if a generic formal
type is nonblocking, all of the basic operations of the actual type are
nonblocking.
Default initialization, finalization, and assignment
of elementary types are always nonblocking, so we don't need any rules
for those.
{
AI12-0064-2}
{
AI12-0374-2}
The predefined equality operator for a composite type, unless it is for
a record type or record extension and the operator is overridden by a
primitive equality operator, is illegal if it is nonblocking and:
for a record type or record extension, the parent
primitive "=" allows blocking; or
some component is of a type T, and:
T is a record type or record extension
that has a primitive "=" that allows blocking; or
T is neither a record type nor
a record extension, and T has a predefined "=" that
allows blocking.
Ramification: This applies to both record
and array "=".
This check occurs when the equality operator
is declared, so this rule effectively makes the type illegal if the rule
is violated.
Reason: We don't need to check this when
the operator is overridden for a record type, as the body of the new
definition of equality will enforce the rules, and there is no case where
the predefined operator will re-emerge. We do have to check this for
array types even if the operator is overridden, as the predefined operator
will re-emerge in generics and record equality.
the actual subprogram corresponding to a nonblocking
formal subprogram shall be nonblocking [(an actual that is an entry is
not permitted in this case)];
the actual subtype corresponding to a nonblocking
formal subtype shall be nonblocking;
Ramification: We require matching for
formal scalar or access-to-object types, even though their predefined
operators are always nonblocking (and they re-emerge in the generic unit)
- because a "blocking" predicate might apply to the actual
subtype, which will also be enforced on operations of the formal type.
the actual object corresponding to a formal object
of a nonblocking access-to-subprogram type shall be of a nonblocking
access-to-subprogram type;
the actual instance corresponding to a nonblocking
formal package shall be nonblocking.
{
AI12-0064-2}
In addition to the places where Legality Rules normally
apply (see
12.3), the above rules also apply
in the private part of an instance of a generic unit.
Ramification: For a generic formal parameter
to be nonblocking (thus, for these rules to apply), it has to explicitly
specify aspect Nonblocking to be True. However, if not specified True,
these rules do apply in the instance of the specification of the generic
unit (the normal re-checking is needed). For instance, the body of an
expression function might make a prohibited call.
Wording Changes from Ada 95
{
AI95-00345-01}
Added a Legality Rule to make it crystal-clear that the protected object
of an entry or procedure call must be a variable. This rule was implied
by the Dynamic Semantics here, along with the Static Semantics of
3.3,
but it is much better to explicitly say it. While many implementations
have gotten this wrong, this is not an incompatibility — allowing
updates of protected constants has always been wrong.
Extensions to Ada 2005
{
AI05-0030-2}
{
AI05-0215-1}
Added the Synchronization aspect to allow specifying
that an interface procedure is really an entry or a protected procedure.
Wording Changes from Ada 2005
{
AI05-0225-1}
Correction: Clarified that the target object of any name denoted
a protected procedure or entry can never be a constant (other than for
the 'Count attribute). This closes holes involving calls to access-to-protected,
renaming as a procedure, and generic formal subprograms.
Inconsistencies With Ada 2012
{
AI12-0064-2}
Calls on procedures that rename an entry or are implemented
by an entry are now defined to be potentially blocking. This means that
such a call now might raise Program_Error. However, it never made sense
for some entry calls to be excluded from being potentially blocking,
and we expect that most implementations already treated all entry calls
the same way. Thus do not expect this wording change to actually change
the behavior of any implementation, and thus no program will change.
Incompatibilities With Ada 2012
{
AI12-0166-1}
Correction: Internal protected calls are now
prohibited in preconditions and default expressions of protected operations.
These were allowed in Ada 2012, but as they cause race conditions and
as most existing Ada 95 compilers crash when given such a default parameter,
we expect such code to be extremely rare.
Extensions to Ada 2012
{
AI12-0064-2}
{
AI12-0319-1}
{
AI12-0374-2}
Aspect Nonblocking is new; it allows compile-time
checks to prevent using potentially blocking operations in contexts where
that is not allowed.
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe