!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 Amendment 1-2012 18-01-29 !status WG9 Approved 16-06-22 !status ARG Approved 11-0-0 18-01-29 !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. !corrigendum 9.5(17/3) @drepl Force a conflict with AI12-0064-2. @dby Change in conflict file. !corrigendum 9.5.1(18) @drepl Force a conflict with AI12-0064-2. @dby Change in conflict file. !corrigendum H.5(5/2) @drepl An implementation is required to detect a potentially blocking operation within a protected operation, and to raise Program_Error (see 9.5.1). @dby An implementation is required to detect a potentially blocking operation during a protected operation, and to raise Program_Error (see 9.5.1). !ASIS No ASIS effect. !ACATS test Bounded errors are not usefully testable. We must check existing Detect_Blocking tests that they do not require this case to raise Program_Error. !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. **************************************************************** From: Jean-Pierre Rosen Sent: Friday, January 19, 2018 3:17 AM > !ACATS test > > Bounded errors are not usefully testable. If Detect_Blocking applies, then it's no more a bounded error, and a test is necessary. Or is the test already there (sorry, I didn't care to check) ? **************************************************************** From: Tucker Taft Sent: Friday, January 19, 2018 7:33 AM Seems like a nice solution. **************************************************************** From: Bob Duff Sent: Friday, January 19, 2018 7:50 AM I agree. **************************************************************** From: Tullio Vardanega Sent: Friday, January 19, 2018 9:04 AM Neat, I like it. Thanks Randy. **************************************************************** From: Randy Brukardt Sent: Tuesday, January 23, 2018 12:25 AM > > Bounded errors are not usefully testable. > If Detect_Blocking applies, then it's no more a bounded error, and a > test is necessary. Or is the test already there (sorry, I didn't care > to check) ? Any such test clearly belongs to pragma Detect_Blocking, as all this AI does is reduce the cases where Detect_Blocking is required to do something. So the most that might need to be done is modifying an existing test. I don't generally mention that in these clauses, as it applies to any Binding Interpretation AI (some existing test might need to be changed). Now, is your question whether there are any Detect_Blocking tests? The answer is probably not; all of the real-time tests were farmed out to IRTAW which has to date resulted in exactly 0 ACATS tests. I've been prioritizing the core language (which Detect_Blocking is not) in my own test writing. Annex C is about as far back in the Standard as I've gone. In any case, test(s) for Detect_Blocking is on the Ada 2005 to-do list (with a priority 8 out of 10). P.S. If such a test showed up in my in-box, it would probably get issued ASAP. I'm mostly working on priority 8 issues at this point, so it is among the highest priority issues remaining. **************************************************************** From: Randy Brukardt Sent: Friday, January 19, 2018 12:36 AM > If Detect_Blocking applies, then it's no more a bounded error, and a > test is necessary. Or is the test already there (sorry, I didn't care > to > check) ? My earlier answer probably answered the question you meant, but it's irrelevant for this AI. This AI defines a new bounded error for a specific case. That error has nothing to do with Detect_Blocking (that was the entire point of the change) and as such any testing of this AI also has nothing to do with Detect_Blocking. So there is only a bounded error, which is not very valuable to test. (This particular error could be tested, but generally ACATS tests are not supposed to care as to what implementation choices are made when the Standard gives choices. And it's unclear what incorrect results could be tested; guessing about incorrect results are not valuable.) Therefore, Bounded Errors are interesting only as things to avoid in ACATS tests. ****************************************************************