Version 1.18 of ai12s/ai12-0064-2.txt
!standard 9.5(17/3) 17-10-13 AI12-0064-2/13
!standard 9.5.1(8)
!standard 9.5.1(9)
!standard 9.5.1(10)
!standard 9.5.1(11)
!standard 9.5.1(12)
!standard 9.5.1(13)
!standard 9.5.1(14)
!standard 9.5.1(15)
!standard 9.5.1(16)
!standard 9.5.1(18)
!standard 9.5.1(22.1/2)
!standard 3.10.2(33/3)
!standard 4.6(24.21/4)
!standard 4.9(8)
!standard 13.1.1(17/4)
!standard 13.13.2(37/1)
!class Amendment 15-10-17
!status work item 15-12-18
!status received 15-10-17
!priority Medium
!difficulty Medium
!subject Nonblocking subprograms
!summary
Aspect and attribute Nonblocking are added.
!problem
During a protected action, it is a bounded error to invoke an operation that
is potentially blocking. There is currently no mechanism (other than a
comment) to specify that a given subprogram is intended to be safely callable
during a protected action (i.e., that the subprogram will not invoke an
operation that is potentially blocking). This seems like a useful part of a
subprogram's "contract" that should be (optionally) specifiable at the point
of a subprogram's declaration.
!proposal
Add the aspect Nonblocking and the attribute Nonblocking to Ada. These allow
specifying and querying the blocking status of a subprogram. If a subprogram
is declared to be nonblocking, the Ada compiler will verify that it does not
execute any potentially blocking operations (other than deadlocking
operations).
[Summary of changes for October 2017 meeting:
Added some proposal wording, and put in the missing !wording.
Changed "blocking restriction expression" to "nonblocking expression" as
requested. Changed many occurrences of "nonblocking expression" to
"Nonblocking aspect" as suggested by Tucker.
Changed "nonblocking-static" expressions to only allow combining with
"and" and "and then", as requested. Note that I didn't change the wording
for the "poor man's inference" (as Tucker called it), as I couldn't find
any simplification. I considered replacing "and" and "and then" with
"boolean operator or short-circuit form" (which have to be only "and" or
"and then" in this context), but this is longer and doesn't seem to add
any readability/understandability. In any case, we have to allow conforming
to parts of an expression, and that seems to need some description of the
parts in question. (If we just said "conform to some part of the expression",
that would seem to leave a lot to the imagination, or to figuring out the
details of the rules.) [This wording can be near around line 620 in this AI;
I'm not giving exact numbers as editing changes the line numbers frequently.]
Changed the "assume-the-best" and "assume-the-worst" rules to apply to
stand-alone generic specifications and generic bodies as well as entities
declared inside of them. (I noted this while describing the AI to the ARG in
Vienna.) Since calls to subprograms that allow blocking can occur in the
elaboration code of generic packages and in the bodies of generic subprograms,
we need to know when and how to make checks on those calls. [This wording can
be found at approximately lines 600-620 in this AI.]
Minor: The nonblocking expression of a predefined operator of a composite
type was "determined by" the expression of the type; I changed it to say
it is "the same as" the expression of the type since that more clearly
expresses the intent. (else someone will ask "determined how"?).
Note: We didn't discuss the Open Issue found near line 740; we need to decide
how Nonblocking aspects will be added to the Standard library. I personally
think we should write them all as aspects, since Global will have to be written
that way, having both pragmas and aspects is ugly, and as such no Program Unit
pragma Nonblocking is needed. But this needs discussion, as it changes the
Barnes compromise.]
[Summary of changes for June 2017 meeting: (Note: I kept this for the benefit
of people who were not at the Vienna meeting.)
Applied the minor wording changes requested during meeting #56 (Pittsburgh).
Added definition of nonblocking-static expressions, to reply to a comment from
Steve Baird that a static expression cannot have different values in a generic
unit and its associated instance. This means that the nonblocking attribute
cannot be static in some cases for a generic unit, and we still want to allow
such attribute references to be used to specify nonblocking aspects. The value
used to specify a nonblocking aspect needs to be known at compile-time, so that
it can be used to enforce Legality Rules. Thus we need this term to allow only
static expressions and Nonblocking attributes, and combinations of them.
Nonblocking attributes are now static only if their prefix is not a generic
unit nor declared in a generic unit.
Tightened up the note 9.5.1(22.1/2) to say exactly what you have to do (specify
the aspect to have the value True) rather than just "use" the aspect.
Deleted a redundant rule about the Access attribute (it was given normatively
in both 3.10.2 and 9.5).
Finished the list of what needs to be done for non-container units. (Mostly
adding "with Nonblocking => True"). Still need to figure out the list of
paragraph numbers (I won't do that until we're pretty sure these rules are
right).
Moved the Legality Rules out of the aspect definition (it was just getting
really long).
Added the ability to specify the Nonblocking aspect for any type. This is
used for the aspect of the predefined operators for composite types (and
the previous uses for access-to-subprogram types). We allow it on all types
so that private types completed by elementary types work; but we do not
use it in generic matching unless the formal might be composite. Note that
the Nonblocking aspect of an elementary type has no meaning at all other
than to set the value of the corresponding attribute; it only exists so that
private types completed by elementary types have a well-defined aspect.
Changed nonblocking to be an operational aspect, as we need to be able to
specify it on partial views.
Moved the rules about predefined operators into the aspect definition, since
they sometimes contradicted the other rules in that section (which isn't going
to work.) Elementary predefined operators are always nonblocking (this is
important if they re-emerge).
Added a rule that if a composite type is specified to be nonblocking, then the
type is illegal if any of the "=" operators used to implement its predefined
"=" allow blocking. This is a lot easier way to get nonblocking "=" than trying
to calculate that from all of the used "=" operators.
Nonblocking is now an expression-valued aspect, so that it makes sense inside
of generic units. Outside of any generic, it is required to be static so that
we can enforce Legality Rules based on an unambiguous value. In order to
follow the model of preconditions, the expression is given a name, the
"nonblocking expression". I changed as many uses as possible to use
this name; it makes more sense than talking about the "value of the
Nonblocking aspect" when that might be a complex expression. (When Tucker
reviewed the AI, he asked me to remove most of the remaining uses of "value",
which did seem to improve the understandability.)
Adopted a much more complex set of "assume-the-worst" rules for generic
bodies. These are only needed if someone messes up the declaration of a
generic unit (but that's likely to happen soon or later). See the discussion
for examples of why we need these complex rules.
Nonblocking for formal parameters is always that of the actual (unless it is
directly specified); it no longer inherits from the surrounding unit. That
eliminates matching checks for an instantiation in the normal case; matching
is only necessary if the aspect is specified for the formal (which we allow).
This change causes mistakes in defining the nonblocking aspects of a generic
unit to make that unit illegal; the previous definition meant that they usually
made the instance illegal instead (which clearly would be harder to debug and
rather late as well).
Tightened up the definition of the attributes, so they make more sense as
expressions, and explicitly stated where the underlying expression is
evaluated.]
---
!wording
[Editor's note: Individual rule changes scattered throughout the Standard
follow this primary definition.]
Add after 9.5(17/3):
Static Semantics
An expression is nonblocking-static if it is one of the following:
* a static expression;
* a Nonblocking attribute reference;
* a call to a predefined boolean logical operator /and/ where each
operand is nonblocking-static;
* an /and then/ short-circuit control form where each operand is
nonblocking-static;
* a parenthesized nonblocking-static expression.
[Editor's note: This wording is intended to parallel the definition of
predicate-static expression (from 3.2.4(15-22/3)). However, we only
allow combining expressions with "and" or "and then", as this is the
only useful case. (Other combinations mismatch with the underlying
Legality Rules.)]
AARM Reason: We define the term "nonblocking-static expression" so that
nonblocking attribute references can be used to define the value of
other nonblocking aspects, but we don't allow anything with a value
not known at compile-time.
For a program unit, for a task entry, for a formal package, formal
subprogram, formal object of an anonymous access-to-subprogram type,
enumeration literal, and for a type (including a formal type), the
following language-defined operational aspect is defined:
Nonblocking
This aspect specifies the blocking restriction for the entity; it shall
be specified by an expression, called a nonblocking expression. If
directly specified, the aspect_definition shall be a
nonblocking-static expression. The expected type for the expression is
the predefined type Boolean. [Redundant: The aspect_definition can be
omitted from the specification of this aspect; in that case the
nonblocking expression for the entity is the enumeration literal True.]
AARM Proof: 13.1.1 allows omitting the aspect expression for
any aspect with type Boolean; we take advantage of that here.
[Editor's note: 13.1.1(15/3) doesn't say that it applies only
to boolean-valued aspects - we take advantage of the vagueness
here. The basic outline of the wording is the same as used
for preconditions.]
[Editor's 2nd note: One difference with preconditions is the we
specify that the type is Boolean, not "any boolean type". We did
this because we have defined nonblocking attributes, and having
attributes with a different type than the aspect is weird, while
attributes with "any boolean type" is weirder. ]
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.
[Editor's note: The explicit mention of generic formal parameters
here is to make it clear that such specification is intended;
13.1(9.4/5) does not apply to aspect Nonblocking. This is the
"unless otherwise specified" of that rule.]
AARM 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
specify the aspect, but that makes a user-defined subprogram which
is itself not a predefined operator or an enumeration literal.
When the nonblocking expression is static for an entity,
the expression is evaluated to produce a static value for the aspect.
When aspect Nonblocking is statically False for an entity, the entity
might contain a potentially blocking operation; such an entity *allows
blocking*. If the aspect is statically True for an entity, the entity
is said to be nonblocking.
AARM Discussion: We have to allow the aspect to be described as an
expression inside of generic units, where the actual value of
the aspect in an instance could be determined by the aspect of
one or more actuals. Our intent is that the expression is always
a static expression outside of any generic unit, and that in such
contexts it is treated more like a static value than an expression.
AARM 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.
For a generic instantiation and entities declared within such an
instance, the aspect is determined by the nonblocking
expression for the corresponding entity of the generic unit, with
any Nonblocking attributes of the generic formal parameters replaced
by the appropriate nonblocking expression of the corresponding actual
parameters. If the aspect is directly specified for an instance, the
specified expression shall be static and have the same value as the
nonblocking expression of the instance (after replacement).
AARM Reason: We want to allow confirming aspects for instances,
but nothing else. The Legality Rules of the generic body were
checked assuming the nonblocking expression of the
generic unit, and if that is changed, the instance body might
make calls that allow blocking in subprograms that are nonblocking.
AARM Ramification: If the nonblocking expression of the
instance is not static (if the instance is itself inside of a
generic unit), then the Nonblocking aspect cannot be specified
for the instance.
[Editor's note: I've made the re-evaluation and re-checking of the
Nonblocking aspect explicit; while it follows from "normal" generic
instance processing, it's unusual enough to be worth spelling out.]
[Editor's 2nd note: I tried to use the term "confirming" here, but
confirming is not defined for operational aspects (13.1(18.2/3) only
applies to representation aspects). And then we would probably
have had to explain that for non-static aspect expressions, that
"conforming is confirming". :-)]
[Editor's 3rd note: We originally had a mechanism for allowing a
conforming expression to be given here in case the aspect expression
is not static, but the description seemed too complex for a feature
that is "nice-to-have" at best. We could have allowed no specification
at all for instances, but it seems useful for the reader of a instance
to know that the instance is nonblocking without having to look up the
definition of the generic unit and repeat any substitutions.]
For a (protected or task) entry, the Nonblocking aspect is
the Boolean literal False.
AARM 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 an enumeration literal, the Nonblocking aspect is the Boolean
literal True.
AARM Reason: Enumeration literals can be renamed as functions,
and passed to generic formal functions, so we need to defined
the value of the aspect so the other rules are meaningful.
For a predefined operator of an elementary type the Nonblocking
aspect is the Boolean literal 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.
AARM 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, but we don't want
to have to worry about generic matching, so the operators of elementary
types are handled separately. In addition, aspects of subprograms can
be view-specific, while aspects of types cannot be view specific (see
13.1.1); thus in order to handle private types completed by
elementary types, we need to have this rule apply to the operators,
not the types.
AARM 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.
For a dereference of an access-to-subprogram type, the Nonblocking
aspect of the designated subprogram is that of the access-to-subprogram
type.
[Redundant: For a full type declaration that has a partial view, the
aspect is the same as that of the partial view.]
AARM Proof: Type aspects are never view-specific; they always have
the same value for all views. This is formally stated in 13.1.
For an inherited primitive subprogram, if the subprogram is null
or abstract, the subprogram is nonblocking if the corresponding
subprogram of any ancestor is nonblocking. If the subprogram is
neither null nor abstract, the subprogram is nonblocking if and
only if the corresponding subprogram of the parent is
nonblocking.
Unless directly specified, overridings of dispatching operations
inherit this aspect.
Unless directly specified, for a formal type, formal package, or
formal subprogram, the aspect is that of the actual type, package, or
subprogram.
AARM 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.
Unless directly specified, for a derived type the Nonblocking
aspect is that of the parent type.
AARM Discussion: The expressions that can be specified for a derived
type are limited by a Legality Rule, see below.
Unless directly specified, for any other program unit, type, or formal
object, the Nonblocking aspect of the entity is determined by the
Nonblocking aspect for the innermost program unit enclosing the entity.
[Editor's note: Formal objects are here since objects don't have
the aspect in general, only in this specific case.]
If not specified for a library unit, the nonblocking expression
is the Boolean literal True if the library unit is declared pure and is
not a generic unit, and the Boolean literal False otherwise.
[Editor's note: Legality Rules follow all of these other Static Semantics
definitions.]
For a prefix S that denotes a subprogram (including a formal subprogram):
S'Nonblocking
Denotes whether subprogram S is considered nonblocking; the type
of this attribute is the predefined type Boolean.
The prefix S shall statically denote a subprogram.
AARM Ramification: The evaluation of the prefix S will have no effect,
which is necessary for S'Nonblocking to be static. For the intended
use in aspect specifications, we don't want any evaluation, as it
would happen at some freezing point.
S'Nonblocking represents the nonblocking expression of S;
evaluation of S'Nonblocking evaluates that expression.
[Editor's note: All of these attributes are not allowed to be used
outside of a generic unit if the prefix is that of an entity declared
within the generic unit; when the prefix is that of an entity declared
within a generic unit, the nonblocking value may depend on the actuals
and thus only has a defined static value in an instance (that is outside
of any generic). This is given in the Legality Rules below.]
For a prefix P that denotes a package (including a formal package):
P'Nonblocking
Denotes whether package P is considered nonblocking; the type
of this attribute is the predefined type Boolean.
P'Nonblocking represents the nonblocking expression of P;
evaluation of P'Nonblocking evaluates that expression.
For a prefix S that denotes a subtype (including formal subtypes):
S'Nonblocking
Denotes whether predefined operators (and in the case of
access-to-subprogram subtypes) a subprogram designated by a value of
type S are considered nonblocking; the type of this attribute is the
predefined type Boolean.
S'Nonblocking represents the nonblocking expression of S;
evaluation of S'Nonblocking evaluates that expression.
[Editor's note: The following is moved from 9.5.1, including the AARM notes
with minimal changes. The entry_call_statement rule had been previously
identified as needing a change (it's really broken, having nothing specifically
to do with this AI).]
The following are defined to be potentially blocking operations:
AARM 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.
* a select_statement;
* an accept_statement;
* an entry_call_statement, or a call on a procedure that
renames or is implemented by an entry;
* a delay_statement;
* an abort_statement;
* 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;
AARM Reason: This is really a deadlocking call, rather than a blocking
call, but we include it in this list for simplicity.
* a call on a subprogram whose body contains a potentially blocking
operation.
AARM Reason: This allows an implementation to check and raise Program_Error
as soon as a subprogram is called, rather than waiting to find out whether
it actually reaches the potentially blocking operation.
[Editor's notes: End mostly unchanged text. I considered trying to unify
Nonblocking and potentially blocking further, but that seemed messy and
error-prone. One could imagine replacing the last rule with "a call
on a subprogram with Nonblocking = False", but that would expose a lot of
existing code to a Bounded Error (since the default for Nonblocking
is False, and that has to be the case for compatibility).]
If a language-defined subprogram allows blocking, then a call on the
subprogram is a potentially blocking operation.
[Editor's note: This is what remains of 9.5.1(18). The old definition should
be reflected in the aspect values for language-defined routines; see the
discussion of language-defined units below.]
Legality Rules
A nonblocking program unit shall not contain, other than within
nested units with Nonblocking specified as statically False, a call on a
callable entity for which the Nonblocking aspect is statically False, nor
shall it contain any of the following:
* a select_statement;
* an accept_statement;
* a delay_statement;
* an abort_statement;
* task creation or activation.
AARM 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).
AARM Discussion: 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.
Similarly, we don't need to worry specially about entry calls, as they
will be detected by the prohibition against calls to entities with the
Nonblocking aspect False.
End AARM Discussion.
For the purposes of the above rule, an entry_body is considered
nonblocking if the immediately enclosing protected unit is nonblocking.
AARM Reason: An entry always allows blocking (by rule); but we want to
be able to compile-time check for most violations of 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.
A subprogram shall be nonblocking if it overrides a nonblocking
dispatching operation. An entry shall not implement a nonblocking
procedure. If an inherited subprogram allows blocking, then
the corresponding subprogram of each ancestor shall allow blocking.
AARM Discussion: Rules elsewhere in the standard (4.6 and 3.10.2)
ensure that access-to-subprogram conversion and the Access attribute
enforce nonblocking.
[Editor's note: These rules are given later in this AI.]
AARM 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.)
It is illegal to specify aspect Nonblocking for the full view of a type
that has a partial view.
AARM Ramification: The aspect should be specified on the partial view
for such a type. This is necessary to prevent the predefined equality
operator from being nonblocking in the partial view and allowing
blocking in the full view.
Aspect Nonblocking shall be specified for a derived type only if it
fully conforms to the nonblocking expression of the ancestor type
or if it is specified to have the Boolean literal True.
AARM Reason: Boolean-valued aspects have a similar rule (see 13.1.1),
we want this one to work similarly.
[Editor's note: The rule in question is 13.1.1(18.1/4).]
If aspect Nonblocking is specified for an entity that is not a generic
unit or declared inside of a generic unit, the aspect_definition shall
be a static expression.
If the prefix of a Nonblocking attribute reference denotes a generic unit G,
the reference shall occur within the declarative region of G.
AARM Reason: We want the value of Nonblocking attributes to be static
so long as they occur outside of any generic unit. The Nonblocking
aspect of a generic unit will often depend on the actual parameters
of the unit, so it cannot be static (or have any well-defined value).
We need this latter rule in case the attribute of an entity declared in
a generic is used outside of the generic. Note that the previous rule
makes it illegal to use such an attribute to specify aspect Nonblocking
outside of a generic, but we don't want to allow any other uses since
it does not have a static value until instantiated.
AARM Ramification: This rule does not apply to instances of generic
units and entities declared within them.
[Editor's note: We don't need to talk about entities "declared within a
generic unit G", as those aren't visible anyway, and thus can't be used
as a prefix of an attribute. If someone finds a way to do that, we'll need
to add that to this rule.]
The predefined equality operator for a composite type is illegal if it is
nonblocking and, for a record type, it is not overridden by a primitive
equality operator, and:
* for a record type, the parent primitive "=" allows blocking; or
* any component that has a record type that has a primitive "=" that
allows blocking; or
* any component that has a non-record type that has a predefined "="
that allows blocking.
AARM 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.
End AARM Ramification.
AARM 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.
In a generic instantiation (after replacement in the nonblocking
expressions by values of the actuals as described previously):
* the actual subprogram corresponding to a nonblocking formal
subprogram shall be nonblocking Redundant[(an actual that is an
entry is not permitted in this case)];
* the actual type corresponding to a nonblocking formal
private, derived, array, or access-to-subprogram type shall
be nonblocking;
AARM Ramification: We do not require matching for formal
scalar or access-to-object types, as their predefined operators are
always nonblocking (and they re-emerge in the generic unit) -- the
nonblocking status of the type has no impact.
* 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.
In addition to the places where Legality Rules normally apply
(see 12.3), the above rules apply also in the private part of an
instance of a generic unit.
AARM 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. In particular, these rules do not apply when it
specifies aspect Nonblocking to be an expression involving attribute
Nonblocking of a generic formal parameter. However, in
such a case, 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.
A program unit P declared inside of a generic unit but not in a generic body
or that is a generic specification not declared in a generic unit
is considered nonblocking for the purposes of checking the restrictions on a
nonblocking unit only if the value of its Nonblocking aspect is statically
True. For the purposes of checks in P, a call to a subprogram is considered
nonblocking unless the value of its Nonblocking aspect is statically False.
AARM Reason: This is a typical "assume-the-best" rule. We only make checks
if we know the nonblocking status of both P and the called subprogram.
All other checks will be performed when the generic unit is instantiated.
We used the awkward "inside of a generic unit but not in a generic body"
so that a generic specification declared inside of a generic body uses
the following "assume-the-worst" rule.
A program unit P declared inside of a generic body or that is a generic body
is considered nonblocking for the purposes of checking the restrictions on a
nonblocking unit unless the value of its Nonblocking aspect is statically
False. For the purposes of checks in P, a call to a subprogram is considered
to allow blocking unless:
* the value of its Nonblocking aspect is statically True, or
* its nonblocking expression (that is, Nonblocking aspect)
conforms exactly to that of P, or conforms to some part of the
nonblocking expression of P that is combined with the remainder of the
nonblocking expression of P by one or more "and" or "and then"
operations.
AARM Ramification: That is, if the aspect of the program unit is specified
(directly or via inheritance) with any non-static Nonblocking aspects, it
is considered to be a nonblocking program unit for the purposes of making
checks. This is a typical "assume-the-worst" rule.
AARM Reason: The second part allows calls on subprograms with Nonblocking
aspects of Formal'Nonblocking, so long as the Nonblocking aspect of P is
some formula that contains Formal'Nonblocking combined with "and".
This ensures that P will always allow blocking if the actual for Formal
turns out to allow blocking.
Without this rule, we'd allow calls on formals in any body subprogram,
even if the subprogram did not include the formal in its Nonblocking
aspect. For instance:
procedure Blah with Formal1'Blocking is
begin
Formal2;
end Blah;
if Formal1 is nonblocking and Formal2 allows blocking, then we'd have a
nonblocking routine calling a routine that might block. That has to be
prevented as this is "assume-the-worst" checking.
end AARM Reason.
Modify 9.5.1(8):
During a protected action, it is a bounded error to invoke an operation that is
potentially blocking.[ The following are defined to be potentially blocking
operations:]
[Editor's note: This is no longer a definition for potentially blocking.]
Delete 9.5.1(9-16, 18) and the associated AARM notes.
Replace note 9.5.1(22.1/2) with:
The aspect Nonblocking can be specified True on the definition of a protected
unit in order to reject most attempts to use potentially blocking operations
within the protected unit (see 9.5). The pragma Detect_Blocking may be used to
ensure that any remaining executions of potentially blocking operations
during a protected action raise Program_Error. See H.5.
AARM Discussion: The deadlock case cannot be detected at compile-time,
so pragma Detect_Blocking is needed to give it consistent behavior.
[Editor's note: I decided to ignore the possibility of doing this checking at
runtime with just pragma Detect_Blocking -- why would anyone want to take
the risk of an unexpected Program_Error if compile-time checks are available?]
Modify 3.10.2(33/3): [Part of the definition of the Access attribute for subprograms]
... The accessibility level of P shall not be statically deeper than that
of S. {If S is nonblocking, P shall be nonblocking. }In addition to the
places where Legality Rules normally apply (see 12.3),
{these rules apply}[this rule applies] also in the private part of an
instance of a generic unit.
Add after 4.6(24.21/4): [Type conversion Legality Rules for access-to-subprogram types]
* If the target type is nonblocking, the operand type shall be nonblocking.
Add after 4.9(8):
* an attribute_reference whose prefix denotes a non-generic entity that is not
declared in a generic unit, and whose attribute_designator is Nonblocking;
[Editor's note: Any generic unit or anything declared inside of a generic unit
makes Nonblocking nonstatic. We want non-generic Nonblocking to be static so
that it can be used freely in defining the Nonblocking aspect for other entities,
and so that such uses don't affect the generic body assume-the-worst rules.]
Modify the AARM Note 13.1(9.d/3):
...most aspects do not need this complexity[ (including all language-defined
aspects as of this writing)], we avoid the complexity...
[Editor's note: This and the next couple of changes are needed as Nonblocking
can be specified on generic formal parameters, and it surely is
language-defined. In this particular case, the rule itself is fine (it says
"Unless otherwise specified...").]
Add Nonblocking to the list of operational aspects in AARM 13.1(8.mm-rr/1).
Remove generic_formal_parameter_declaration from the list in 13.1.1(17/5).
[Editor's note: Nonblocking is allowed there, of course, so the statement will
be clearly False. Moreover, 13.1(9.4/5) already says the same thing, with the
needed "unless otherwise specified", so we don't need to mention formals here
at all.]
Modify the AARM Note 13.1.1(17.a/3):
Implementation-defined aspects can be allowed on these, of course; the
implementation will need to define the semantics. In {addition}[particular],
{the language does not define default aspect matching rules for generic
formals; only the handful of aspects allowed on formals have such rules.
Therefore,} the implementation will need to define actual [type] matching
rules for any aspects allowed on formal types[; there are no default matching
rules defined by the language].
Add after 13.13.2(37/1):
The aspect Nonblocking is the Boolean literal False for the default
implementations of stream-oriented attributes.
AARM Reason: The underlying Read/Write operations are called via dispatching
calls. Since we cannot afford any incompatibility with existing
Ada code, the stream operations allow blocking. Thus the
stream-oriented attributes must allow blocking as well.
Wording for definition of language-defined packages and subprograms is TBD.
These are just appropriate aspect clauses, and in a few cases, the deletion
of the English text that says something is potentially blocking.
If a language-defined package needs to add Nonblocking, any pragma will
also be changed to the aspect form at the same time. [Author's note: I've
discussed this issue with John; he mainly does not want that to happen
for an empty package. The only empty language-defined package is Ada, and
that is Pure so no change is needed at this time.]
For instance, we'll change
package Ada.Command_Line is
pragma Preelaborate(Command_Line);
to
package Ada.Command_Line
with Preelaborate, Nonblocking is
[Lengthy Editor's note:
We intend that language-defined subprograms are nonblocking
unless this Standard says otherwise. Specifically, 9.5.1(18) said (before we
deleted it above):
Certain language-defined subprograms are potentially blocking. In particular,
the subprograms of the language-defined input-output packages that
manipulate files (implicitly or explicitly) are potentially blocking. Other
potentially blocking subprograms are identified where they are defined. When
not specified as potentially blocking, a language-defined subprogram is
nonblocking.
Non-generic units that are pure are automatically nonblocking as specified in
9.5 (these are noted below). Other units should explicitly have aspect
Nonblocking specified.
We'll handle the containers in AI12-0112-1 (the AI that defines preconditions
for the container operations); it probably makes the most sense to add all of
the contracts at once for those.
The entire list of non-container units is:
Ada - A.2 - Pure
Ada.Assertions 11.4.2 - Pure
Ada.Asynchronous_Task_Control D.11 - Nonblocking => True
Ada.Calendar 9.6 - Nonblocking => True
Ada.Calendar.Arithmetic 9.6.1 - Nonblocking => True
Ada.Calendar.Formatting 9.6.1 - Nonblocking => True
Ada.Calendar.Time_Zones 9.6.1 - Nonblocking => True
Ada.Characters A.3.1 - Pure
Ada.Conversions A.3.4 - Pure
Ada.Handling A.3.2 - Pure
Ada.Latin_1 A.3.3 - Pure
Ada.Command_Line A.15 - Nonblocking => True
Ada.Complex_Text_IO G.1.3 - Nonblocking => False (** String routines)
Ada.Decimal F.2 - Pure
Ada.Direct_IO A.8.4 - Nonblocking => False (I/O)
Ada.Directories A.16 - Nonblocking => False (I/O) - Full_Name through Compose should have Nonblocking => True (as they are just string manipulation routines).
Ada.Directories.Hierarchical_File_Names A.16.1 - Nonblocking => True (these are all string manipulation routines).
Ada.Directories.Information A.16 - (**** Impl def)
Ada.Dispatching D.2.1 - Nonblocking => False (For Yield by the second sentence of D.2.1(7/3), which should be deleted. There are no other subprograms here.)
Ada.Dispatching.EDF D.2.6 - Nonblocking => True - Delay_Until_and_Set_Deadline has Nonblocking => False. -- (This wording is missing from the RM,
-- so we don't have to delete it.) (***** AB.)
Ada.Dispatching.Non_Preemptive D.2.4 - Nonblocking => True -- AARM Note D.2.4(2.b/3) confirms this for Yield_to_Higher.
-- Yield_to_Same_or_Higher is a rename, and gets the value from the original routine.
Ada.Dispatching.Round_Robin D.2.5 - Nonblocking => True (***** AB.)
Ada.Dynamic_Priorities D.5.1 - Nonblocking => True (***** AB.)
Ada.Environment_Variables A.17 - Nonblocking => True
Ada.Exceptions 11.4.1 - Nonblocking => True
Ada.Execution_Time D.14 - Nonblocking => True
Ada.Execution_Time.Group_Budgets D.14.2 - Nonblocking => True
Ada.Execution_Time.Interrupts D.14.3 - Nonblocking => True
Ada.Execution_Time.Timers D.14.1 - Nonblocking => True
Ada.Finalization 7.6 - Nonblocking => False (*** user overriding)
Ada.Float_Text_IO A.10.9 - Nonblocking => False (** String routines)
Ada.Float_Wide_Text_IO A.11 - Nonblocking => False (** String routines)
Ada.Float_Wide_Wide_Text_IO A.11 - Nonblocking => False (** String routines)
Ada.Integer_Text_IO A.10.8 - Nonblocking => False (** String routines)
Ada.Integer_Wide_Text_IO A.11 - Nonblocking => False (** String routines)
Ada.Integer_Wide_Wide_Text_IO A.11 - Nonblocking => False (** String routines)
Ada.Interrupts C.3.2 - Nonblocking => True
Ada.Interrupts.Names C.3.2 - (**** Impl def)
Ada.IO_Exceptions A.13 - Pure
Ada.Iterator_Interfaces 5.5.1 - Nonblocking => False (this declares interfaces used elsewhere, and we have to allow blocking in the
-- implemented routines. This is annoying; we may have to make a separate nonblocking version for the parallel stuff)
Ada.Locales A.19 - Nonblocking => True
Ada.Numerics A.5 - Pure
Ada.Numerics.Complex_Arrays G.3.2 - Pure
Ada.Numerics.Complex_Elementary_Functions G.1.2 - Pure
Ada.Numerics.Complex_Types G.1.1 - Pure
Ada.Numerics.Discrete_Random A.5.2 - Nonblocking => True
Ada.Numerics.Elementary_Functions A.5.1 - Pure
Ada.Numerics.Float_Random A.5.2 - Nonblocking => True
Ada.Numerics.Generic_Complex_Arrays G.3.2 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True)
Ada.Numerics.Generic_Complex_Elementary_Functions G.1.2 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True)
Ada.Numerics.Generic_Complex_Types G.1.1 - Nonblocking => True (Pure but generic)
Ada.Numerics.Generic_Elementary_Functions A.5.1 - Nonblocking => True (Pure but generic)
Ada.Numerics.Generic_Real_Arrays G.3.1 - Nonblocking => True (Pure but generic)
Ada.Numerics.Real_Arrays G.3.1 - Pure
Ada.Real_Time D.8 - Nonblocking => True
Ada.Real_Time.Timing_Events D.15 - Nonblocking => True (confirmed by note D.15(48/2)).
Ada.Sequential_IO A.8.1 - Nonblocking => False (I/O)
Ada.Storage_IO A.9 - Nonblocking => False (I/O)
Ada.Streams 13.13.1 - Nonblocking => False (*** user overriding)
Ada.Streams.Stream_IO A.12.1 - Nonblocking => False (I/O)
Ada.Strings A.4.1 - Pure
Ada.Strings.Bounded A.4.4 - Nonblocking => True
Ada.Strings.Bounded.Equal_Case_Insensitive A.4.10 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True)
Ada.Strings.Bounded.Hash A.4.9 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True)
Ada.Strings.Bounded.Hash_Case_Insensitive A.4.9 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True)
Ada.Strings.Bounded.Less_Case_Insensitive A.4.10 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True)
Ada.Strings.Fixed A.4.3 - Nonblocking => True
Ada.Strings.Fixed.Equal_Case_Insensitive A.4.10 - Pure (from a rename)
Ada.Strings.Fixed.Hash A.4.9 - Pure
Ada.Strings.Fixed.Hash_Case_Insensitive A.4.9 - Pure
Ada.Strings.Fixed.Less_Case_Insensitive A.4.10 - Pure
Ada.Strings.Equal_Case_Insensitive A.4.10 - Pure
Ada.Strings.Hash A.4.9 - Pure
Ada.Strings.Hash_Case_Insensitive A.4.9 - Pure
Ada.Strings.Less_Case_Insensitive A.4.10 - Pure
Ada.Strings.Maps A.4.2 - Pure
Ada.Strings.Maps.Constants A.4.6 - Pure
Ada.Strings.Unbounded A.4.5 - Nonblocking => True
Ada.Strings.Unbounded.Equal_Case_Insensitive A.4.10 - Nonblocking => True
Ada.Strings.Unbounded.Hash A.4.9 - Nonblocking => True
Ada.Strings.Unbounded.Hash_Case_Insensitive A.4.9 - Nonblocking => True
Ada.Strings.Unbounded.Less_Case_Insensitive A.4.10 - Nonblocking => True
Ada.Strings.UTF_Encoding A.4.11 - Pure
Ada.Strings.UTF_Encoding.Conversions A.4.11 - Pure
Ada.Strings.UTF_Encoding.Strings A.4.11 - Pure
Ada.Strings.UTF_Encoding.Wide_Strings A.4.11 - Pure
Ada.Strings.UTF_Encoding.Wide_Wide_Strings A.4.11 - Pure
Ada.Strings.Wide_Bounded A.4.7 - Nonblocking => True
Ada.Strings.Wide_Bounded.Wide_Equal_Case_Insensitive A.4.7 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True)
Ada.Strings.Wide_Bounded.Wide_Hash A.4.7 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True)
Ada.Strings.Wide_Bounded.Wide_Hash_Case_Insensitive A.4.7 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True)
Ada.Strings.Wide_Equal_Case_Insensitive A.4.7 - Pure
Ada.Strings.Wide_Fixed A.4.7 - Nonblocking => True
Ada.Strings.Wide_Fixed.Wide_Equal_Case_Insensitive A.4.7 - Pure (from a rename)
Ada.Strings.Wide_Fixed Wide_Hash A.4.7 - Pure
Ada.Strings.Wide_Fixed Wide_Hash_Case_Insensitive A.4.7 - Pure
Ada.Strings.Wide_Hash A.4.7 - Pure
Ada.Strings.Wide_Hash_Case_Insensitive A.4.7 - Pure
Ada.Strings.Wide_Maps A.4.7 - Nonblocking => True
Ada.Strings.Wide_Maps.Wide_Constants A.4.7 - Nonblocking => True
Ada.Strings.Wide_Unbounded A.4.7- Nonblocking => True
Ada.Strings.Wide_Unbounded.Wide_Equal_Case_Insensitive A.4.7- Nonblocking => True
Ada.Strings.Wide_Unbounded.Wide_Hash A.4.7- Nonblocking => True
Ada.Strings.Wide_Unbounded.Wide_Hash_Case_Insensitive A.4.7- Nonblocking => True
Ada.Strings.Wide_Wide_Bounded A.4.8 - Nonblocking => True
Ada.Strings.Wide_Wide_Bounded.Wide_Wide_Equal_Case_Insensitive A.4.8 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True)
Ada.Strings.Wide_Wide_Bounded.Wide_Wide_Hash A.4.8 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True)
Ada.Strings.Wide_Wide_Bounded.Wide_Wide_Hash_Case_Insensitive A.4.8 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True)
Ada.Strings.Wide_Wide_Equal_Case_Insensitive A.4.8 - Pure
Ada.Strings.Wide_Wide_Fixed A.4.8 - Nonblocking => True
Ada.Strings.Wide_Wide_Fixed.Wide_Wide_Equal_Case_Insensitive A.4.8 - Pure (from a renames)
Ada.Strings.Wide_Wide_Fixed.Wide_Wide_Hash A.4.8 - Pure
Ada.Strings.Wide_Wide_Fixed.Wide_Wide_Hash_Case_Insensitive A.4.8 - Pure
Ada.Strings.Wide_Wide_Hash A.4.8 - Pure
Ada.Strings.Wide_Wide_Hash_Case_Insensitive - A.4.8 - Pure
Ada.Strings.Wide_Wide_Maps A.4.8 - Nonblocking => True
Ada.Strings.Wide_Wide_Maps.Wide_Wide_Constants A.4.8 - Nonblocking => True
Ada.Strings.Wide_Wide_Unbounded A.4.8 - Nonblocking => True
Ada.Strings.Wide_Wide_Unbounded.Wide_Wide_Equal_Case_Insensitive A.4.8 - Nonblocking => True
Ada.Strings.Wide_Wide_Unbounded.Wide_Wide_Hash A.4.8 - Nonblocking => True
Ada.Strings.Wide_Wide_Unbounded.Wide_Wide_Hash_Case_Insensitive A.4.8 - Nonblocking => True
Ada.Synchronous_Barriers D.10.1 - Nonblocking => True (Wait_For_Release has Nonblocking => False by D.10.1(14/3); that paragraph should be deleted).
Ada.Synchronous_Task_Control D.10 - Nonblocking => True (Suspend_Until_True has Nonblocking => False by D.10(10), that sentence should be deleted).
Ada.Synchronous_Task_Control.EDF D.10 - Nonblocking => False (by D.10(10.1/3), that sentence should be deleted.)
Ada.Tags 3.9 - Nonblocking => True
Ada.Tags.Generic_Dispatching_Constructor 3.9 - Nonblocking => Constructor'Nonblocking (* generic)
Ada.Task_Attributes C.7.2 - Nonblocking => True
Ada.Task_Identification C.7.1 - Nonblocking => True (Abort_Task has Nonblocking => False by C.7.1(16); that paragraph should be deleted)
Ada.Task_Termination C.7.3 - Nonblocking => True
Ada.Text_IO A.10.1 - Nonblocking => False (** String routines)
Ada.Text_IO.Bounded_IO A.10.11 - Nonblocking => False -- I/O
Ada.Text_IO.Complex_IO G.1.3 - Nonblocking => False -- I/O
Ada.Text_IO.Editing F.3.3 - Nonblocking => False (** String routines)
Ada.Text_IO.Text_Streams A.12.2 - Nonblocking => False
Ada.Text_IO.Unbounded_IO A.10.12 - Nonblocking => False
Ada.Unchecked_Conversion 13.9 - Nonblocking => True (Pure but generic)
Ada.Unchecked_Deallocate_Subpool 13.11.5 - Nonblocking => False (*** user calls)
Ada.Unchecked_Deallocation 13.11.2 - Nonblocking => True
Ada.Wide_Characters A.3.1 - Pure
Ada.Wide_Characters.Handling A.3.5 - Pure
Ada.Wide_Text_IO A.11 - Nonblocking => False (** String routines)
Ada.Wide_Text_IO.Complex_IO G.1.4 - Nonblocking => False -- I/O
Ada.Wide_Text_IO.Editing F.3.4 - Nonblocking => False (** String routines)
Ada.Wide_Text_IO.Text_Streams A.12.3 - Nonblocking => False
Ada.Wide_Text_IO.Wide_Bounded_IO A.11 - Nonblocking => False -- I/O
Ada.Wide_Text_IO.Wide_Unbounded_IO A.11 - Nonblocking => False
Ada.Wide_Wide_Characters A.3.1 - Pure
Ada.Wide_Wide_Characters.Handling A.3.6 - Pure
Ada.Wide_Wide_Text_IO A.11 - Nonblocking => False (** String routines)
Ada.Wide_Wide_Text_IO.Complex_IO G.1.4 - Nonblocking => False -- I/O
Ada.Wide_Wide_Text_IO.Editing F.3.4 - Nonblocking => False (** String routines)
Ada.Wide_Wide_Text_IO.Text_Streams A.12.3 - Nonblocking => False
Ada.Wide_Wide_Text_IO.Wide_Wide_Bounded_IO A.11 - Nonblocking => False -- I/O
Ada.Wide_Wide_Text_IO.Wide_Wide_Unbounded_IO A.11 - Nonblocking => False
Interfaces B.2 - Pure
Interfaces.C B.3 - Pure
Interfaces.C.Pointers B.3.2 - Nonblocking => True
Interfaces.C.Strings B.3.1 - Nonblocking => True
Interfaces.COBOL B.4 - Nonblocking => True
Interfaces.Fortran B.5 - Pure
System 13.7 - Pure
System.Address_To_Access_Conversions 13.7.2 - Nonblocking => True
System.Machine_Code 13.8 - (**** Impl def)
System.Multiprocessors D.16 - Nonblocking => True
System.Multiprocessors.Dispatching_Domains D.16.1 - Nonblocking => True
System.RPC E.5 - Nonblocking => False (E.5(23) says this explicitly; that paragraph should be deleted.)
System.Storage_Elements 13.7.1 - Pure
System.Storage_Pools 13.11 - Nonblocking => False (*** user overriding)
System.Storage_Pools.Subpools 13.11.4 - Nonblocking => False (*** user overriding)
Items marked "Pure" are pure, and thus automatically are Nonblocking.
Items marked "(* generic)" have Nonblocking given as a formula. This
automatically matches the nonblocking setting to that of the actual
parameters (see the !discussion for more on this). The containers will be
like this as well.
Items marked "(** String routines)" have Get/Put routines that operate only on
Strings -- those explicitly have Nonblocking => True specified. That's in
accordance with the AARM note 9.5.1(18.a) (and an old AI).
Items marked "(*** user overriding)" are mainly used to provide a framework
for user code (as in storage pools or streams). Since all dispatching calls
have to "assume the worst" for nonblocking, and we have to keep compatibility
with existing Ada code, we cannot make such packages (and types) nonblocking.
The user can explicitly mark their overriding routines Nonblocking (overridings
of "allows blocking" subprograms can be declared nonblocking, but the other way
around is prohibited).
Items marked "(*** user calls)" make calls on code that is potentially
user-defined via dispatching. These usually work in conjunction with types
declared in packages associated with the previous item.
Items marked "(**** impl def)" have implementation-defined contents, so we need
say nothing.
Items marked "(**** AB)" were verified with Alan Burns. Since explicit wording
is needed in Ada 2012 to specify that a routine is potentially blocking, the
lack of such wording could mean either that the subprogram was considered and
should be nonblocking, or that no one considered whether the subprogram needs
to be potentially blocking. As such, I verified with Alan Burns whether any
packages that have no evidence that nonblocking was considered need to be
explicitly potentially blocking (see e-mail of January 11, 2017, and the reply).
In particular, Ada.Dispatching.EDF.Delay_Until_and_Set_Deadline, which includes
the semantics of a delay statement, needs to be potentially blocking but isn't
declared this way in the RM.
End lengthy editor's note.]
!discussion
We considered changing the aspect name from "Nonblocking" to
"Potentially_Blocking," as that matches RM terminology better, but we
ultimately concluded that would be a mistake. Furthermore, "nonblocking"
is used in 9.5.1, albeit somewhat informally. Were we to switch to
Potentially_Blocking, the default would be True rather than False, which
is unlike other Boolean aspects. Furthermore, with Potentially_Blocking
=> True, we wouldn't require that it be potentially blocking, merely
allow it. Perhaps Allow_Blocking would be better, but that doesn't match
RM terminology at all, and still has the "wrong" default.
We initially modeled this aspect after No_Return, which has a somewhat
similar purpose and presumably has already worked out some of the needed
rules. However, we have gone beyond that, because we now have
nonblocking access-to-subprogram types, nonblocking formal subprograms,
etc.
The aspect is described as being a boolean valued expression, but our intent
is that it act like a boolean-valued aspect outside of any generic unit.
Thus it is required to be static in such contexts, the expression can be
omitted when it is specified (in which case is represents the expression of
the boolean literal True), it can only be changed to True for derived types,
and so on. We repeat these rules even when the 13.1.1 blanket rules can be
read to apply, as that might be surprising to a reader.
The rules do not allow calling "normal" subprograms from a nonblocking
subprogram. This allows detecting any potentially blocking operations
used in a nonblocking subprogram statically. This is important if pragma
Detect_Blocking is used, as such detection is required. (Otherwise, this
is just a bounded error and the "mistake" can be ignored with the usual
consequences.)
We have provided package-level defaults, given that many packages will
have all of their subprograms non-blocking. We chose to make the default
for a declared pure, non-generic library unit to be nonblocking, as that
is almost always the case, since blocking typically implies the use of
some kind of global lock. We do not foresee significant
incompatibilities, since declared pure library units may only depend on
other declared pure library units. For pure generic units we leave the
default at False for compatibility reasons, because these might have
existing instances where an actual subprogram (or access-to-subprogram
type) is potentially blocking.
We did not specify that protected subprograms are by default
Nonblocking=>True, since that would be incompatible, as they then could
not call subprograms with a default Nonblocking aspect value of False.
It might be possible to specify Nonblocking=>True as the default for
protected subprograms in a future version of the standard (and clearly
an implementation could at least provide a warning when a call is made
to a subprogram with Nonblocking of False). Because of the confusion
related to the fact that protected operations are always required to be
nonblocking at run-time, we don't allow specifying the attribute
directly on an individual protected operation. However, we allow
specifying Nonblocking on a protected unit to determine the setting for
all of the enclosed protected operations. This allows rejection of
protected operations that call or use allows blocking operations.
We only allow specifying a conforming expression (essentially a
confirming value) of Nonblocking on a generic
instantiation; the value of the aspect comes from the generic unit
(possibly after re-evaluating the aspect based on the values of the
actual parameters). Specifying a different value would simply be
confusing, as it wouldn't change the enforcement of Legality Rules
in the generic unit (and it would be wrong to supply a value of
True for an instance of a unit that has the value of False, as in
that case no rules would have been enforced in the body).
----
The attribute Nonblocking is primarily useful for use in the Nonblocking
aspect of other subprograms, and mainly for the non-blocking property
of formal subprograms and other formal parameters.
We allow the prefix to be any subprogram to avoid having special cases,
and as it may be useful to ensure that a group of subprograms all have
the same contract. In the case of nonblocking, that could be accomplished
with a constant, but in the case of other static contracts that we are
considering like exception contracts (AI12-0015-1) and global contracts
(AI12-0079-1), a mechanism to copy them will be valuable (especially as
they may be lengthy). As we want all of the contracts to work as similarly
as possible, we make the attribute Nonblocking as general as possible.
The primary use for this attribute is in aspects of generic units. The
attribute makes it possible for a generic unit to have a nonblocking
aspect that depends on those of the actual subprograms. That's especially
important for the containers, which we want to be primarily nonblocking.
This mechanism takes some effort for the implementer of a generic unit,
but it means that the instantiator of such a unit does not need to
worry about nonblocking, as the most restrictive setting compatible with
the actual subprograms will automatically be chosen.
Unfortunately, this mechanism doesn't have an obvious extension to support
anonymous access-to-subprogram parameters; the type is anonymous and the
actual is typically an Access attribute. One could imagine allowing the
prefix to be a parameter, something like:
procedure Iterate
(Container : in Hashed_Maps;
Process : not null access procedure (Position : in Cursor)
when Nonblocking => Process'Nonblocking and
Hash'Nonblocking and
Equivalent_Keys'Nonblocking);
But in that case the Nonblocking value would have to be determined
based on the actuals of the call; it would be weird for the Legality
of a call to depend on the details of actual parameters. Thus we didn't
propose such a mechanism.
----
We could simplify this proposal further by dropping the ability to specify
Nonblocking on generic formal parameters, and just depending on the Nonblocking
attribute to handle that. That would eliminate the rules about generic formal
matching. We didn't do that as that would require having nonblocking attributes
for formal objects (which would reduce the value somewhat),
and would eliminate the "easy" solution for new code (which is to simply
require everything to be nonblocking). Not everyone needs to write the most
flexible possible generics.
---
The assume-the-worst rules are fairly complex, in that we want to allow the
intended cases without accidentally allowing illegal situations in instances.
Just assuming that the aspects have the value True works for the intended
usage, but we have to detect errors in that usage.
For instance, consider the following example:
generic
type P is private;
Obj : P;
function F (Param : P) return Boolean;
package Gen is
with Nonblocking => P'Nonblocking and F'Nonblocking;
procedure Proc (Param : P);
end Gen;
package body Gen is
procedure Proc (Param : P) is
begin
if P = Obj then --
...
elsif F (P) then --
...
end if;
end Proc;
end Gen;
In this normal usage, the entire generic has a nonblocking aspect based on the
"and" of the actuals Nonblocking status. This means that procedure Proc also
inherits this aspect. As such, (1) and (2) should be allowed, as any legal
instance will work. A "split" instance (where the Nonblocking aspects differ;
for instance when P is nonblocking and F allows blocking) will end up allowing
blocking for Proc. We avoid any check as the assume-the-worst says no check is
needed for a call whose Nonblocking aspect exactly matches some portion of the
aspect expression combined with "and" for the subprogram as a whole.
One can also imagine a belt-and-suspenders approach where everything is
specified:
generic
type P is private with Nonblocking => P'Nonblocking;
Obj : P;
function F (Param : P) return Boolean with Nonblocking => F'Nonblocking;
package Gen is
with Nonblocking => P'Nonblocking and F'Nonblocking;
procedure Proc (Param : P);
end Gen;
This also works fine (assuming the same body), as the same matching rule applies.
In this case, Proc will only be nonblocking if both P and F are nonblocking, so there
can be no problem with the calls to either.
Similarly, if we wanted to specify a more limited nonblocking for a different
procedure, we could do that:
generic
type P is private;
Obj : P;
function F (Param : P) return Boolean;
package Gen2 is
with Nonblocking => P'Nonblocking and F'Nonblocking;
procedure Proc2 (Param : P) with F'Nonblocking;
end Gen2;
package body Gen2 is
procedure Proc2 (Param : P) is
begin
if F (P) then --
...
end if;
end Proc;
end Gen2;
In this case, the aspect of the subprogram called at (3) (that of the actual,
F'Nonblocking) exactly matches that of the checked subprogram (Proc2). This
is true even if the actual for P allows blocking, since no allows blocking
operation of P is called in Proc2.
As noted before, we need the complex rules in order to avoid problems when
someone screws up. Consider a version of the Gen2 that puts the wrong
aspect on Proc2:
generic
type P is private;
Obj : P;
function F (Param : P) return Boolean;
package Gen2 is
with Nonblocking => P'Nonblocking and F'Nonblocking;
procedure Proc2 (Param : P) with P'Nonblocking;
end Gen2;
Again, any combination of nonblocking aspects of the actuals would be legal.
The rules as described make the call at (3) illegal (as the aspects don't
conform). This is important, as the case where the actual for F allows
blocking and the actual for P is nonblocking would lead to a nonblocking
subprogram calling a subprogram that allows blocking. However, our
initial rule of treating all of the attributes as having the value True would
have allowed this case (since both Proc2 and F have values that derive from
formal entities, just different ones). That can't be allowed.
Similarly, consider mistakenly using "or" instead of "and" for the unit
in the general case:
generic
type P is private;
Obj : P;
function F (Param : P) return Boolean;
package Gen is
with Nonblocking => P'Nonblocking or F'Nonblocking;
procedure Proc (Param : P);
end Gen;
This wouldn't change the legality of the actuals at all. The rules as
described would make both calls (1) and (2) illegal, as the neither of
the aspects of the formal would conform with the aspect inherited for
Proc (and the "and" rule for portions would not apply). Again, in the
case where the actual for F allows blocking and the actual for P is
nonblocking we would have a nonblocking subprogram Proc calling a
subprogram F (2) that allows blocking, so this indeed has to be illegal.
(The call (1) would not be a problem in that case, but reverse the
blocking of the actuals and then (1) would be the problematic call.)
Again, the initial rule would not have detected the problem.
---
Comparing Alternative 1 with this proposal.
The problem with alternative 1 is that a generic unit like the containers
can be set to nonblocking, but then using this with an allows blocking
routine requires an explicit override by the user on the instance. Since the
default for most routines is that they are not nonblocking, this could provide
a significant compatibility problem.
An alternative for alternative 1 would be to declare units like the containers
to be allows blocking; but then they can never be nonblocking (and we surely
want to use them as nonblocking).
In contrast, this proposal puts all of the burden on the implementer of a
package (where it should be) and none on the user of the package. Alternative
1 is definitely easier for the implementer of a package, and harder for a
user.
Container usage examples:
Imagine that a user has an existing user-defined Hash function:
subtype Label is String (1..10);
function Hash (Key : in Label) return Ada.Containers.Hash_Type;
With this proposal (as outlined in the example section below), if they don't
care about nonblocking (as is likely to be the case for recompiling existing
code), their existing instantiation will compile with no problem:
package My_Hashed_Map is new
Ada.Containers.Hashed_Map (Label, Element, Hash, "=");
If they do care about blocking behavior, they can add Nonblocking to Hash
and they will get the Nonblocking behavior they want:
function Hash (Key : in Label) return Ada.Containers.Hash_Type
with Nonblocking => True;
Alternatively, they could declare the instance to be Nonblocking:
package My_Hashed_Map is new
Ada.Containers.Hashed_Map (Label, Element, Hash, "=")
with Nonblocking => True;
which would cause an error (as Nonblocking is False), hopefully with an error
message that Hash has Nonblocking set as False (since that's the default).
With a good error message, the correct fix should be easy to find.
-------------------
For alternative 1 (as described in AI12-0064-1/05), the situation is different.
The original instantiation of:
package My_Hashed_Map is new
Ada.Containers.Hashed_Map (Label, Element, Hash, "=");
is now illegal, as Hash has Nonblocking = False, and that fails to match the
default for the formal parameter Hash (which is Nonblocking => True). Thus the
user has to change their code and add Nonblocking => True to Hash or add
Nonblocking => False to the instance My_Hashed_Map.
That doesn't seem good.
If the default of Ada.Containers.Hashed_Map is changed to False, then the
above works, but then there no longer is any way to get a Nonblocking
container.
package My_Hashed_Map is new
Ada.Containers.Hashed_Map (Label, Element, Hash, "=")
with Nonblocking => True;
should be illegal in this case, as the restrictions were not enforced in the
generic body.
---------------
There is one known problem with this proposal as it is written. The prefix
of the Nonblocking attribute has to resolve without any context. That means
that in many circumstances, overloaded prefixes aren't going to be usable.
That could be a problem for operators (like "=" in the containers) that
are widely used.
I considered using subprogram calls rather than subprogram names in the
prefix, but that ran into issues both with having appropriate parameters
to use (in the generic case) and with evaluation of the prefix (which we
don't want to do).
I also considered using qualification, but that doesn't help for relational
operators (they all return Boolean!).
It's possible to rename operators to unique names, so the problem isn't
unsurmountable, but of course that clutters the name space of packages.
(We can use renames as aspects aren't resolved until the freezing point.)
One of course can avoid using operators in generic specifications, but that's
impractical for existing generics and a usage pain for new generics.
!example
package Ada.Text_IO
with Nonblocking => False is
...
generic
type Enum is (<>);
package Enumeration_IO is --
Default_Width : Field := 0;
Default_Setting : Type_Set := Upper_Case;
procedure Get(File : in File_Type; --
...
procedure Get(From : in String;
Item : out Enum;
Last : out Positive)
with Nonblocking => True; --
procedure Put(To : out String;
Item : in Enum;
Set : in Type_Set := Default_Setting)
with Nonblocking => True; --
end Enumeration_IO
...
end Ada.Text_IO;
with Ada.Iterator_Interfaces;
generic
type Key_Type is private;
type Element_Type is private;
with function Hash (Key : Key_Type) return Hash_Type;
with function Equivalent_Keys (Left, Right : Key_Type)
return Boolean;
with function "=" (Left, Right : Element_Type)
return Boolean is <>;
package Ada.Containers.Hashed_Maps is
with Nonblocking => Key_Type'Nonblocking and
Element_Type'Nonblocking and
Hash'Nonblocking and
Equivalent_Keys'Nonblocking and
Element_Equal'Nonblocking;
pragma Preelaborate(Hashed_Maps);
pragma Remote_Types(Hashed_Maps);
function Element_Equal (Left, Right : Element_Type)
return Boolean renames "="; --
...
procedure Iterate
(Container : in Map;
Process : not null access procedure (Position : in Cursor))
with Nonblocking => False;
...
end Ada.Containers.Hashed_Maps;
Alternatively, we could separately specify the blocking for the individual
routines, depending on which of the formal routines they are allowed to use.
(Given that we leave that unspecified in the Standard, it's probably better to
use a global setting as was done here.)
!ASIS
TBD.
!ACATS test
ACATS B-Tests and C-Tests.
!appendix
From: Randy Brukardt
Sent: Thursday, June 2, 2016 7:59 PM
At the Vermont meeting, I was asked to create an alternative to Tucker's
Nonblocking proposal using an attribute to specify nonblocking for generics.
I did that back in December and sent it off to Tucker for comment. After
waiting slightly less than 167 days (and sending between 3-6 reminders,
depending on how one counts) [but who's counting :-)] without receiving any
reply or even acknowledgement, I've decided to stop waiting and submit a
slightly revised draft to the entire group in the hopes of getting comments.
[This is version /02 - Ed.]
While I'm convinced this is better (especially for compatibility with the
existing containers), it probably can be improved further (and there were a
handful of areas that I didn't figure out in detail).
****************************************************************
From: Jean-Pierre Rosen
Sent: Friday, June 3, 2016 12:36 AM
> If not specified for a library unit, the default is True if the
> library unit is declared pure and is not a generic unit, and
> False otherwise.
I was wondering about Shared_Passive units. Reading further, I realize that
SP units can call protected subprograms (if the PO has no entries), and those
are not Nonblocking.
Maybe an extra reason for making protected subprograms nonblocking...
****************************************************************
From: Tucker Taft
Sent: Friday, June 3, 2016 8:46 AM
Sorry for being so slow. This upcoming weekend is set aside as my "ARG"
weekend. It has been really hard for me to find time before now to focus
on the ARG issues.
****************************************************************
From: Tucker Taft
Sent: Sunday, June 5, 2016 11:15 AM
Sorry for the late reply. This looks good to me. For AI12-0079 I think I
will steal the notion of an attribute of generic formals to specify more
precisely the Global aspect for generic code, as there is a very similar
problem there, and a similar solution seems appropriate.
****************************************************************
From: Steve Baird
Sent: Thursday, October 20, 2016 8:22 PM
In private mail, I wrote:
> Language design principle:
> If an expression in a generic is static, then the
> corresponding expression in an instance must also
> be static and must have the same value.
Note that I'm not quoting this LDP from the RM or anywhere else. Randy and I had
a discussion of how violating this principle leads to pestilence, famine, and
other bad things. This discussion can be repeated if anyone is interested.
>
> Which brings us to the Nonblocking attribute as described in
> alternative 2, version 1.5 of ai12-0064 (I know we just discussed this
> AI in Pittsburgh, but I don't recall any updates that are relevant to
> today's question).
>
> We've got:
>
> For a prefix S that denotes a subprogram (including a formal
> subprogram):
>
> S'Nonblocking
> ...; the value
> of this attribute ...is always static ...
>
> If S denotes a formal subprogram of a generic unit G, the value of
> S'Nonblocking is True within the body of G or within the body of a
> generic unit declared within the declarative region of G, and False
> otherwise.
>
> ...
>
> In an instance, S'Nonblocking returns the value
> of the nonblocking aspect of the actual subprogram, even if
> referenced through the name of the formal.
>
> I think we have a problem here with a violation of the aforementioned
> language design principle.
Do folks agree that there is a problem here? I think this means that if the
Nonblocking attribute of a generic formal subprogram is static, then the
corresponding actual parameter must have a matching attribute value. There are
several possible solutions which satisfy this but they each have drawbacks and
would need to be discussed.
For example, the Nonblocking attribute of a formal subprogram could be nonstatic
and then an approach based on post-compilation rules (which could be checked at
compile time by implementations which macro-expand instantiations) might work if
combined with an idea Randy suggested, an almost-static expression which is
non-static in a generic but will be static in any instance.
****************************************************************
From: Tucker Taft
Sent: Thursday, October 20, 2016 8:39 PM
>> Language design principle:
>> If an expression in a generic is static, then the
>> corresponding expression in an instance must also
>> be static and must have the same value.
>>
>
> Note that I'm not quoting this LDP from the RM or anywhere else.
> Randy and I had a discussion of how violating this principle leads to
> pestilence, famine, and other bad things.
> This discussion can be repeated if anyone is interested.
I'd be somewhat interested, though I can imagine some weirdness if you capture
the value of the attribute. I think we want to eliminate the notion it is
"always static." We almost never say that sort of thing, and I think your
principle about generics makes that unwise. I think more frequently we talk
about assuming the "best" in the generic spec (and rechecking in the instance)
while assuming the worst in the generic body. I suspect that that same approach
can work here.
>> ... We've got:
>>
>> For a prefix S that denotes a subprogram (including a formal
>> subprogram):
>>
>> S'Nonblocking
>> ...; the value
>> of this attribute ...is always static ...
>>
>> If S denotes a formal subprogram of a generic unit G, the value of
>> S'Nonblocking is True within the body of G or within the body of a
>> generic unit declared within the declarative region of G, and False
>> otherwise.
>>
>> ...
>>
>> In an instance, S'Nonblocking returns the value
>> of the nonblocking aspect of the actual subprogram, even if
>> referenced through the name of the formal.
>>
>> I think we have a problem here with a violation of the aforementioned
>> language design principle.
>
> Do folks agree that there is a problem here?
Yes, saying this is "static" in a generic seems unwise. I would rather use the
"assume the best" and "assume the worst" approach.
> For example, the Nonblocking attribute of a formal subprogram could be
> nonstatic and then an approach based on post-compilation rules (which
> could be checked at compile time by implementations which macro-expand
> instantiations) might work if combined with an idea Randy suggested,
> an almost-static expression which is non-static in a generic but will
> be static in any instance.
I think this is basically accomplishing something very similar to the assume the
best/worst approach. Of course when you say "any instance" you mean any
instance that is not itself nested within a generic.
****************************************************************
From: Randy Brukardt
Sent: Friday, October 21, 2016 12:18 PM
...
> > For example, the Nonblocking attribute of a formal subprogram could
> > be nonstatic and then an approach based on post-compilation rules
> > (which could be checked at compile time by implementations which
> > macro-expand
> > instantiations) might work if combined with an idea Randy suggested,
> > an almost-static expression which is non-static in a generic but
> > will be static in any instance.
>
> I think this is basically accomplishing something very similar to the
> assume the best/worst approach. Of course when you say "any instance"
> you mean any instance that is not itself nested within a generic.
That's (assume-the-worst/assume-the-best) is what the current rules are intended
to accomplish. We essentially assume-the-worst about the value of the attribute
in a generic body.
What other way could work??
Steve completely ignored our lengthy e-mail discussion in this note, forcing me
to reproduce the entire thing here (and wasting another 30 minutes).
In particular, he ignored a far more important (in my view) Language Design
Principle (LDP):
If the value of an expression is needed to determine the result of a Legality
Rule, the expression shall be static.
(Again, I don't think this is ever expressed in the AARM, but it should be
pretty obvious.)
Since the entire point of attribute Nonblocking is to use it in aspect
Nonblocking, which controls Legality Rules, this LDP also applies.
Clearly one of these LDPs has to be extensively modified in order to make this
work.
Also note that it is critical that Nonblocking attributes can be combined in
expressions for the aspect Nonblocking. (Usually with "and", but I'd hate to
limit things that way.) They also need to be able to be combined with other
static expressions (such as a global flag).
Specifically, we need to know what rules to enforce inside of generics for cases
like:
procedure Foo (...)
with Nonblocking => Bar'Nonblocking and Glarch'Nonblocking and
Some_Global_Nonblocking_Setting;
The only solutions I see are far too heavy:
The best I can do is to define something akin to a predicate-static expression
(which I jokingly called a
Steve_Baird_not_quite_memorial_and_not_quite_static_expression), and then such
an expression would be allowed (by fiat) in aspect Nonblocking. LDP #2 would be
modified to include the new kind of expression. That's awfully heavy. (*)
The alternative of some sort of assume-the-worst fiat for a specified aspect
Nonblocking and dropping the requirement for the expression to be static doesn't
really work: it doesn't make sense if the expression is statically False (and
the expression could be complicated and involve attributes Nonblocking from
nongeneric units), and moreover we'd still have to somehow prevent
procedure Foo with Nonblocking => Some_Function(42);
Once you've handled those issues, you're pretty much back to the other solution
(just with more wording).
So as far as I can tell, this kills Nonblocking unless some other solution can
be found.
(*) Here's the actual joke wording that I proposed:
A Steve_Baird_not_quite_memorial_and_not_quite_static_expression is
* A non-static Nonblocking attribute (that is, one given inside of a
generic that depends on a formal parameter); or
* A static expression; or
* A combination of two
Steve_Baird_not_quite_memorial_and_not_quite_static_expressions with a
logical binary operator; or
* The "not" operator applied to a
Steve_Baird_not_quite_memorial_and_not_quite_static_expression.
We'd also have to define precisely which Nonblocking attributes are non-static,
both here and in 4.9. (That alone will take a large number of words, because of
the headaches of generic child units as well as nested generics.)
We can get away with this little of a definition because we know that
Nonblocking has type Boolean. (A complete definition would also include
relational operators, but as they seem useless for type Boolean, I left them
out.)
There would be some value to a more general
compile-time-known-but-not-static-expression (for 'Size of records, for
instance), but that would be almost as much work to define as static expressions
themselves.
We'd have to come up with a better term.
****************************************************************
From: Tucker Taft
Sent: Friday, October 21, 2016 2:20 PM
> ...
>>> For example, the Nonblocking attribute of a formal subprogram could
>>> be nonstatic and then an approach based on post-compilation rules
>>> (which could be checked at compile time by implementations which
>>> macro-expand
>>> instantiations) might work if combined with an idea Randy suggested,
>>> an almost-static expression which is non-static in a generic but
>>> will be static in any instance.
>>
>> I think this is basically accomplishing something very similar to the
>> assume the best/worst approach. Of course when you say "any
>> instance" you mean any instance that is not itself nested within a
>> generic.
>
> That's (assume-the-worst/assume-the-best) is what the current rules
> are intended to accomplish. We essentially assume-the-worst about the
> value of the attribute in a generic body.
>
> What other way could work??
I think making this static is unnecessary. We have other legality rules that
depend on the best case or worst case, without requiring the value to be static.
> Steve completely ignored our lengthy e-mail discussion in this note,
> forcing me to reproduce the entire thing here (and wasting another 30 minutes).
>
> In particular, he ignored a far more important (in my view) Language
> Design Principle (LDP):
>
> If the value of an expression is needed to determine the result of
> a Legality Rule, the expression shall be static.
>
> (Again, I don't think this is ever expressed in the AARM, but it
> should be pretty obvious.)
I guess this is where I disagree. We can say that something is illegal if the
value *might* possibly be a particular value at run-time. The *bounds* of what
it might be needed to be known at compile time, but the actual value itself
doesn't need to be static. We have a number of rules which are based on "known
to be ..." sorts of things.
> Since the entire point of attribute Nonblocking is to use it in aspect
> Nonblocking, which controls Legality Rules, this LDP also applies.
But it could apply only as a worst case or a best case, rather than by saying it
is in fact static.
> ... moreover we'd still have to somehow prevent
> procedure Foo with Nonblocking => Some_Function(42); Once
> you've handled those issues, you're pretty much back to the other
> solution (just with more wording).
I suspect we will end up going the same route as predicate static (as you
mentioned), saying effectively that it must be an expression composed only of
static subexpressions and 'Nonblocking attribute references.
> So as far as I can tell, this kills Nonblocking unless some other
> solution can be found.
I don't see this as a "terminal" disease. Perhaps just a bit of the LDP "flu."
****************************************************************
From: Randy Brukardt
Sent: Friday, October 21, 2016 2:44 PM
...
> > In particular, he ignored a far more important (in my view) Language
> > Design Principle (LDP):
> >
> > If the value of an expression is needed to determine the result
> > of a Legality Rule, the expression shall be static.
> >
> > (Again, I don't think this is ever expressed in the AARM, but it
> > should be pretty obvious.)
>
> I guess this is where I disagree. We can say that something is
> illegal if the value
> *might* possibly be a particular value at run-time. The
> *bounds* of what it might be needed to be known at compile time, but
> the actual value itself doesn't need to be static.
> We have a number of rules which are based on "known to be ..." sorts
> of things.
Sure, but none of those rules are based on the *value* of an expression (they're
all other sorts of properties).
> > Since the entire point of attribute Nonblocking is to use it in
> > aspect Nonblocking, which controls Legality Rules, this LDP also applies.
>
> But it could apply only as a worst case or a best case, rather than by
> saying it is in fact static.
Surely; but that is just modifying the LDP to say "static or <new term
here>". It doesn't invalidate the LDP in any way.
> > ... moreover we'd still have to somehow prevent
> > procedure Foo with Nonblocking => Some_Function(42); Once
> > you've handled those issues, you're pretty much back to the other
> > solution (just with more wording).
>
> I suspect we will end up going the same route as predicate static (as
> you mentioned), saying effectively that it must be an expression
> composed only of static subexpressions and 'Nonblocking attribute
> references.
Unless someone has a radical solution that doesn't cause other problems, it
seems like the only sensible route.
So, any ideas for the term to use?? I'll need something for the write-up, and
"Steve Baird not quite memorial pseudo-static expression" probably doesn't work
for most. :-)
I suppose if we are going to use a one-time use term, we could copy the form of
the "predicate-static" term and use "nonblocking-static". Other ideas?
> > So as far as I can tell, this kills Nonblocking unless some other
> > solution can be found.
>
> I don't see this as a "terminal" disease. Perhaps just a bit of the
> LDP "flu."
It going to add quite a bit of wording to a concept that already has altogether
too much wording (and also I've been requested to try to figure out how to make
it work for record equality, a topic that I punted on because it appeared so
hard - that's also going to add a lot of wording).
But I suppose it is always darkest before the dawn. (I just wonder if the sun is
actually going to come up.)
****************************************************************
From: Tucker Taft
Sent: Friday, October 21, 2016 3:28 PM
> ... I suppose if we are going to use a one-time use term, we could
> copy the form of the "predicate-static" term and use "nonblocking-static".
> Other ideas?
Yes, nonblocking-static is probably where we will end up.
****************************************************************
From: Randy Brukardt
Sent: Wednesday, January 11, 2017 11:02 PM
9.5.1 requires that routines that are potentially blocking to be
identified explicitly in the Standard. (A potentially blocking
routine shouldn't be used in a protected operation.)
No routine in Ada.Dispatching.EDF is so identified.
However, Ada.Dispatching.EDF.Delay_Until_and_Set_Deadline
sure *sounds* like it is potentially blocking (a delay_statement
certainly is). And Ada.Dispatching.EDF.Set_Deadline is a task
dispatching point (as the deadline is being changed) -- D.2.6(19/2).
I think that means it is also potentially blocking (but here I'm not
certain); surely the calling task can be suspended by this operation.
Get_Deadline probably doesn't need to be potentially blocking (it's
just a query).
Similarly, nothing is said for Ada.Dispatching.Round_Robin.
This seems intentional, as none of the operations cause
(directly) a task dispatching point; a quantum change doesn't appear
to take effect until it is suspended and then becomes ready
(D.2.5(11/2)). Am I right?
Similarly, nothing is said for Ada.Dynamic_Priorities. That may be
intentional, but it is hard for me to tell (the lack of wording
doesn't tell one if that was considered and intentionally omitted).
Could you confirm (or deny) that Set_Priority was intended to be
nonblocking? (That is, not potentially blocking.)
****************************************************************
From: Alan Burns
Sent: Thursday, February 9, 2017 1:59 AM
Operations that change a tasks scheduling parameter (e.g. priority or
deadline) are not, I feel, potentially blocking in the usual sense of this
term. Yes they could lead to pre-emption but this is not blocking.
Blocking is when a task cannot make progress even if it were the most eligible
task in the system.
But yes, Delay_Until_and_set_deadline is a delay statement and is potentially
blocking just like the usual delay statement.
I agree with what you say about round robin
PS sorry I must have missed this email earlier
****************************************************************
From: Randy Brukardt
Sent: Friday, February 17, 2017 3:01 PM
Attached find the result of Tucker and my homework on this AI [This is version
/10 of the AI - Editor]. There is a lengthy list of changes from the version
seen at the last meeting at the beginning of the AI.
A number of big points:
* The aspect is now an expression rather than a static value, as it can't
(and shouldn't) be static inside of generics. Rules make it static for
entities outside of any generic including those in instances.
* The above makes the assume-the-worst/assume-the-best rules are a lot more
complicated (since they have to involve matching of expressions rather than
simple values); this however has the effect of detecting most errors in the
definition of a generic unit when the unit is compiled as opposed to doing
so when it is instantiated (or worse, never).
* The aspect is allowed on types in order to control the blocking of
predefined composite operators (which compose potentially including
user-defined routines that might block). It had to be allowed on all types
so that private types (which are formally composite) can be completed with
elementary types. Note that predefined elementary operators are always
nonblocking - the aspect of an elementary type has no effect at the moment.
* I moved all of the Legality Rules to a separate Legality Rules section
because the aspect definition was getting way too large.
Many of these rules are necessary to cover Bairdian cases that might happen
(mismatching formal aspects, for instance). I think I've covered all of the
areas that need rules, but of course the Master of Bairdian cases hasn't
reviewed this draft yet, so I wouldn't be surprised if new issues emerge.
As always, any comments are welcome.
****************************************************************
From: Tucker Taft
Sent: Friday, October 13, 2017 3:09 PM
New paragraph:
For an inherited primitive subprogram, if the subprogram is null
or abstract, the subprogram is nonblocking if the corresponding
subprogram of any ancestor is nonblocking. If the subprogram is
neither null nor abstract, the subprogram is nonblocking if and
only if the corresponding subprogram of the parent is
nonblocking.
immediately preceding:
Unless directly specified, overridings of dispatching operations
inherit this aspect.
Update the following paragraph by adding a sentence (in {}):
A subprogram shall be nonblocking if it overrides a nonblocking
dispatching operation. An entry shall not implement a nonblocking
procedure. { If an inherited subprogram allows blocking, then
the corresponding subprogram of each ancestor shall allow blocking.}
[Editor's note: These were added to version /13 of the AI.]
****************************************************************
Questions? Ask the ACAA Technical Agent