Version 1.1 of ai12s/ai12-0247-1.txt

Unformatted version of ai12s/ai12-0247-1.txt version 1.1
Other versions for file ai12s/ai12-0247-1.txt

!standard 9.5(55/5)          18-01-18 AI12-0247-1/01
!standard 9.5(56/5)
!standard 9.5.1(18/5)
!standard H.5(5/2)
!class binding interpretation 18-01-18
!status work item 15-06-04
!status received 15-04-28
!priority Low
!difficulty Easy
!qualifier Omission
!subject Potentially Blocking goes too far for Detect_Blocking
!summary
During a protected action, a call on a subprogram that contains a potentially blocking operation, may, but does not have to, raise Program_Error.
!question
The definition of the pragma Detect_Blocking says "An implementation is required to detect a potentially blocking operation within a protected operation, and to raise Program_Error (see 9.5.1)."
The definition of a potentially blocking operation includes the following bullet:
* a call on a subprogram whose body contains a potentially blocking operation.
This bullet is recursive. Thus, a correct implementation of Detect_Blocking requires analysis of (potentially) the entire program source.
Specifically, imagine determining if a call to subprogram S1 is potentially blocking. In order to do that, we need to analyze the body of S1. If that body contains a call to S2 and no other potentially blocking operations, we then have to analyze the body of S2 in order to determine if it is potentially blocking. And possibly so on through the entire (static) call tree of S1.
Is this intended? (No.)
!recommendation
(See Summary.)
!wording
[Note: This AI assumes the many wording changes of AI12-0064-2 have been applied, and uses paragraph numbers as in Draft 12 of the Ada 202x Standard.]
Modify 9.5(55/5):
* 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[;]{.}
Delete 9.5(56/5) and the associated AARM note.
Add after 9.5.1(18/5): [In the Bounded Error section]
During a protected action, a call on a subprogram whose body contains a potentially blocking operation is a bounded error. If the bounded error is detected, Program_Error is raised; otherwise, the call proceeds normally.
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. [This is the Ada 95 AARM note - Editor.] If the call proceeds normally, reaching the potentially blocking operation is a separate bounded error, covered by the previous rules. [This part is new - Editor.]
Modify H.5(5/2):
An implementation is required to detect a potentially blocking operation {during}[within] a protected operation, and to raise Program_Error (see 9.5.1).
[This is just a wording correction, see the !discussion for details - RLB]
!discussion
The bullet was fine in the original Ada 95 formulation, since the call would trigger a bounded error, and one of the choices for handling the bounded error is to do the normal thing (that is, make no check). As such, the bullet just added a permission to detect blocking early, one that would rarely apply.
However, the addition of the pragma Detect_Blocking made the use of the normal call wrong -- there is no choice about what to do.
As such, we just eliminate the bullet and add a separate bounded error for the original Ada 95 intent. The new bounded error allows raising Program_Error or doing the right thing; since it is not part of the definition of "potentially blocking operations", the use of Detect_Blocking doesn't change the effect of this new bounded error.
Since Ada 2020 adds static detection of blocking behavior, it is unlikely that implementations would want to make any effort to use the new bounded error (it adds nothing as the static check would already catch the error and prevent the program from running anyway). We do need the new bounded error, however, so that no existing implementation needs to change any existing behavior (we don't know if this bullet is used by any implementations, and we don't want to prohibit such usage).
---
During the discussion of this AI, it was noted that the definition of Detect_Blocking is worded improperly; all of the other related rules use "during a protected action", which is proper dynamic wording. We've corrected this as well.
!ASIS
No ASIS effect.
!ACATS test
Bounded errors are not usefully testable.
!appendix

From: Randy Brukardt
Sent: Friday, December 15, 2017  8:19 PM

Having just finished applying all of the changes of AI12-0064-2 (aspect
Nonblocking) to the draft RM, I've realized that there is a problem with the
definition of pragma Detect_Blocking.

The definition of the pragma says "An implementation is required to detect a
potentially blocking operation within a protected operation, and to raise
Program_Error (see 9.5.1)."

The definition of a potentially blocking operation includes the following
bullet:

* a call on a subprogram whose body contains a potentially blocking operation.

This bullet is recursive. Thus, a correct implementation of Detect_Blocking
requires analysis of (potentially) the entire program source.

Specifically, imagine determining if a call to subprogram S1 is potentially
blocking. In order to do that, we need to analyze the body of S1. If that body
contains a call to S2 and no other potentially blocking operations, we then have
to analyze the body of S2 in order to determine if *it* is potentially blocking.
And possibly so on through the entire (static) call tree of S1.

[Aside: We can do a bit better in Ada 2020, if S2 is declared to be Nonblocking,
one does not need to look at the body. But that doesn't seem to be any real
help.]

I'm pretty sure that (A) we did not intend such an implementation; and (B) no
one actually implements Detect_Blocking this way. All we wanted Detect_Blocking
to do is to ensure that no operation that actually might block gets called
during a protected action.

The problem comes from the bullet mentioned above. For the original use of
"potentially blocking" as a Bounded Error, this bullet was fine, as doing the
normal thing was always allowed, so the bullet could be ignored by an
implementation unless it wanted to do some sort of early detection. (The AARM
gives the reason for this bullet as allowing early raising of Program_Error.)

But it is clear that Detect_Blocking eliminates the permission to do the normal
thing. A subprogram is potentially blocking if the body contains anything
potentially blocking, period, including a call on something that is potentially
blocking only because of something in its body. Since this bullet is recursive,
it requires recursive analysis to properly implement.

I can't imagine that we want to require recursive analysis. I could imagine
requiring analysis that none of the obvious potentially blocking operations
occurs in the body of the subprogram, except that in Ada 2020 one can do that
using aspect Nonblocking. So there doesn't seem to be much value in requiring
Detect_Blocking to do such analysis (does any compiler even do that?) - any
actual problem case will be detected when an obvious potentially blocking
operation occurs. And anyone wanting to ensure no blocking can always use aspect
Nonblocking.

That suggests that we want to remove this bullet from the definition of
"potentially blocking" and add an Implementation Permission. The easiest
solution seems to add it to 9.5.1 as a permission applying to the Bounded Error
case (which appears to have been the original intent based on the AARM Note):

    During a protected action, a call on a subprogram whose body contains a
    potentially blocking operation may raise Program_Error.

This would eliminate any requirement to do that when Detect_Blocking is
specified, but still would allow it as an implementation option in both the
normal Bounded Error case and in the Detect_Blocking case. (It also would let me
get rid of a convoluted AARM note in the definition of Nonblocking.)

Any thoughts on this? I can write up the necessary AI if everyone agrees.

****************************************************************

From: Tucker Taft
Sent: Saturday, December 16, 2017  2:04 PM

Now that we have the Nonblocking aspect, I agree that this kind of "early"
detection seems to be overkill, and the wording was a bit bogus to begin with.
Your solution seems fine, and an AI would be welcome.

****************************************************************

From: Jean-Pierre Rosen
Sent: Sunday, December 17, 2017  1:52 AM

> Having just finished applying all of the changes of AI12-0064-2
> (aspect Nonblocking) to the draft RM, I've realized that there is a
> problem with the definition of pragma Detect_Blocking.

I think the problem comes from the fact that "potentially blocking" is a compile
time notion, while "detect_blocking" is a run-time semantics.

> The definition of the pragma says "An implementation is required to
> detect a potentially blocking operation within a protected operation,
> and to raise Program_Error (see 9.5.1).> The definition of a
> potentially blocking operation includes the following bullet:
>
> * a call on a subprogram whose body contains a potentially blocking
> operation.

Why not say that all other cases are "directly blocking operations", and this
one is defined as "indirectly blocking". Then the definition of the pragma could
say: "An implementation is required to detect a {call to a directly} potentially
blocking operation [within]{during} a protected operation, and to raise
Program_Error (see 9.5.1)."

At least that's how I understand the intent, and it would remove the confusion
between static and dynamic semantics.

****************************************************************

From: Tullio Vardanega
Sent: Sunday, December 17, 2017  9:06 AM

JP has it right (from the perspective of the original intent, barring the
awkward formulation). I would be happy with the text he suggests.

****************************************************************

From: Tucker Taft
Sent: Sunday, December 17, 2017  10:09 AM

...
>> Having just finished applying all of the changes of AI12-0064-2
>> (aspect Nonblocking) to the draft RM, I've realized that there is a
>> problem with the definition of pragma Detect_Blocking.
>
> I think the problem comes from the fact that "potentially blocking" is
> a compile time notion, while "detect_blocking" is a run-time semantics.

I suppose, but if that is the case, then the last bullet really doesn't belong
there, since it cannot be detected at compile time by the "average" Ada
compiler.

So I think I agree with Randy that that bullet is the outlier.

...
>> The definition of the pragma says "An implementation is required to
>> detect a potentially blocking operation within a protected operation,
>> and to raise Program_Error (see 9.5.1).> The definition of a
>> potentially blocking operation includes the following bullet:
>>
>> * a call on a subprogram whose body contains a potentially blocking
>> operation.
>
> Why not say that all other cases are "directly blocking operations",
> and this one is defined as "indirectly blocking". Then the definition
> of the pragma could say:
> "An implementation is required to detect a {call to a directly}

Not all potentially blocking operations are callable entities, so it is not just
"calls" that you want to detect.  Perhaps "invoking a directly potentially
blocking operation" -- but that is a mouthful.  Randy's approach might be
simpler.  In any case, it will be easier to discuss in the context of a specific
AI, I believe.

...
> potentially blocking operation [within]{during} a protected operation,
> and to raise Program_Error (see 9.5.1)."

This really should say "during a protected action," since a "protected
operation" is a compile-time notion, while "protected action" is the run-time
thing.

...
> At least that's how I understand the intent, and it would remove the
> confusion between static and dynamic semantics.

Not entirely, as indicated above.  I agree we should try to remove this
confusion, but I think it still needs a bit more work, and the proposed AI seems
like the right place to thrash this out.

****************************************************************

From: Randy Brukardt
Sent: Monday, December 18, 2017  5:51 PM

> > Having just finished applying all of the changes of AI12-0064-2
> > (aspect Nonblocking) to the draft RM, I've realized that there is a
> > problem with the definition of pragma Detect_Blocking.
>
> I think the problem comes from the fact that "potentially blocking" is
> a compile time notion, while "detect_blocking"
> is a run-time semantics.

No, "potentially blocking" controls a Bounded Error (a runtime notion - "either
works or raises an exception" is surely a runtime notion) in Ada 95, and pragma
Detect_Blocking in Ada 2005 (also a runtime notion). Indeed, I had to define a
totally separate notion of "nonblocking" so it would work for compile-time for
Ada 2020.

There are some wording issues with "potentially blocking" that confuse the
issue, but those are just wrong and most of them were changed by Ada 2020's
corrections in approved AI12-0064-2.

> > The definition of the pragma says "An implementation is required to
> > detect a potentially blocking operation within a protected
> > operation, and to raise Program_Error (see 9.5.1).> The definition
> > of a potentially blocking operation includes the following bullet:
> >
> > * a call on a subprogram whose body contains a potentially blocking
> > operation.
>
> Why not say that all other cases are "directly blocking operations",
> and this one is defined as "indirectly blocking". Then the definition
> of the pragma could say:
> "An implementation is required to detect a {call to a directly}
> potentially blocking operation [within]{during} a protected operation,
> and to raise Program_Error (see 9.5.1)."

That adds a fourth term to something that is already confusing with three terms
already ("allows blocking", "nonblocking", and "potentially blocking"). One that
we don't need.

In addition, no Ada 2020 compiler vendor will want to take any advantage of this
rule (because it conflicts with aspect Nonblocking, which does the entire job
correctly, and because it requires adding body dependencies where there are
none). The only reason for not dumping the rule completely is to ensure that
vendors don't have to change whatever it is that they are doing for the Bounded
Error and Detect_Blocking cases, as hopefully no one is using the first and the
second is only useful to detect deadlocks. It's potentially a significant
portability problem and provides no value whatsoever in Ada 2020. (If it was up
to me solely, I'd delete it since I can't imagine any sane way to use it in
implementing the Bounded Error, but I recognize that might just be a lack of
imagination on my part. And it might have had some [misguided, IMHO] use in an
Ada 95 implementation.)

> At least that's how I understand the intent, and it would remove the
> confusion between static and dynamic semantics.

Again, "potentially blocking" has always been solely a dynamic notion; the
confusion is in the old wording (which is completely wrong for dynamic semantics
as Tucker and Steve have variously pointed out). In Ada 2020, "potentially
blocking" is purely a dynamic notion, as there are separate static notions to
implement aspect Nonblocking.

Anyway, I think you understand the intent the same as I do (even if you
misunderstand the static/dynamic nature of the rule), which I why I proposed the
solution that I did. The permission I proposed allows Program_Error to be raised
in exactly the cases that the old rule did, without requiring it when pragma
Detect_Blocking is in force. That's all we need/want to change (especially as
this entire notion only exists for compatibility in Ada 2020).

****************************************************************

From: Randy Brukardt
Sent: Thursday, January 18, 2018  11:04 PM

Attached is the write-up (version /01 of the AI) for a topic that we discussed
here back in December.

I came up with a better solution than either of those proposed then: make the
subprogram call case a separate bounded error. That changes the original
meaning less than an Implementation Permission would have, avoids the need for
an extra new term (or an extra header in the RM), and solves the problem by
keeping this case out the definition of "potentially blocking operation". The
wording is a bit longer than the permission would have been, but it better
explains why this exception is happening. Hopefully, everyone will like it.

As always, comments welcome.

****************************************************************


Questions? Ask the ACAA Technical Agent