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

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

!standard D.2.4 (10/3)          18-05-14 AI12-0279-1/01
!class binding interpretation
!class binding interpretation 18-05-14
!status work item 18-05-14
!status received 18-05-11
!priority Medium
!difficulty Easy
!qualifier Omission
!subject Nonpreemptive Dispatching Needs More Dispatching Points
!summary
All potentially blocking operations are preemption points for the Non-Preemptive Dispatching Policy.
!question
In non-preemptive dispatching it is necessary to have controlled points in the code where preemption is enabled, as a mechanism to keep the non-preemptive sections short and reduce blocking time for higher priority tasks. Unlike the preemptive case, these preemption points need to be under the programmer's control in order for the program semantics to be fully predictable. The current wording in the standard mentions "blocking of a task" as a preemption point. This can happen for instance when calling a closed entry or suspension object. However, if the entry is open or the suspension object is true, there is no preemption point, which introduces uncertainty on whether a preemption point is reached and makes it difficult to determine the blocking (non-preemptive) time for higher priority tasks.
Should this nondeterminism be eliminated? (Yes.)
!recommendation
The solution to this unpredictability is to declare all potentially blocking operations to be preemption points. In this case, all calls to an entry or wait operations on a suspension point are preemption points regardless of whether they are open or not. This simple change would make non-preemptive dispatching more predictable.
!wording
Modify D.2.4 (10/3) For this policy, {invoking an operation that is potentially blocking,} [blocking or ]termination of a task, [a delay_statement], {and} a call to Yield_To_Higher[, and a call to Yield_To_Same_Or_Higher or Yield] are the only task dispatching points (see D.2.1).
Modify D.2.4 (10.a/3) {Reason: We want higher predictability for determining the blocking time for higher priority tasks. We want starting any potentially blocking operation to be a dispatching point, as otherwise calling an open entry or a suspension object that is open would not trigger dispatching, but would if the entry or suspection object happened to be closed at the time of the call.}
Ramification: {Any potentially blocking operation}[A delay_statement] is always a task dispatching point even if it is not blocking. Similarly, a call to Yield_To_Higher is never blocking, but it is a task dispatching point{.} In each of these cases, they can cause the current task to stop running (it is still ready). [Otherwise, the running task continues to run until it is blocked.]
!discussion
We don't need to say anything about calls such as Yield, Suspend_Until_True, or Suspend_Until_True_And_Set_Deadline, as these subprograms all have the Nonblocking aspect specified as False, and the new wording covers all potentially blocking operations, which includes these calls.
!ASIS
No ASIS effect.
!ACATS test
An ACATS C-Test is needed to check that a potentially blocking operation is a dispatching point, even if it does not block.
!appendix

From: Tullio Vardanega
Sent: Friday, May 11, 2018  2:37 AM

The (short but intense) burst of AIs from the IRTAW group shows evidence that
they (me included) recently had a productive meeting :) In addition to Alan 
Burns' AI with the revised wording of the Deadline Floor Protocol, and Brad 
Moore's cut at lock-free atomic operations, I was tasked to submit another --
very simple indeed -- AI with a binding interpretation of the semantics of 
non-blocking dispatching, which I attach below.

[This attached version /01 of this AI - Editor.]

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

From: Tullio Vardanega
Sent: Friday, May 11, 2018  2:43 AM

Ehm.
Thanks to the echoing service, I was that what I wrote in premise to the AI I 
have just sent reads rather weird.
The subject matter is the semantics of potentially blocking operations in 
nonpreemptive dispatching.
Apologies for botching up the wording ...

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

From: Brad Moore
Sent: Friday, May 11, 2018  6:54 PM

I thought of something today, unfortunately after Tullio had sent the AI to
the ARG.

We should probably add a couple paragraphs in the Discussion section stating 
that we considered defining the rules to target more precisely the preemption
points (for example making a call on an open entry, or suspension object, or 
making calls to Yield, etc) rather than the blanket rule of invoking any 
potentially blocking operation.

I think the justification is that the rules are simpler, easier to maintain 
and implement, and provides more preemption points that might be useful for 
analysis including more likely to break up long bouts of processing, which 
was part of the original motivation.

The second paragraph should say something about the case where applications 
have not applied the nonblocking aspect to the various subprogram 
specifications in the application. An example of this would be legacy systems.
The default is that most such calls have nonblocking=>false, which means they 
are potentially blocking. There could be an extremely large number of 
preemption points in such an application, which might potentially be 
prohibitively expensive. Is this a problem?

This also raises a similar question in my mind, relating to the Nonblocking 
aspect. Consider a legacy system where a PO calls subprograms in some non-pure
package. If these are now considered to be potentially blocking due to lack of
a Nonblocking aspect on the specification of the subprogram, the compiler 
would start to flag these as errors. Is this a backwards compatibility 
problem? 

One might be able to apply a configuration pragma to say that the Program_Unit 
is by default NonBlocking, but then presumably the compiler might start 
flagging routines that actually are potentially blocking as having an 
incompatible default, requiring code changes to fix.

The description of Nonblocking aspect in RM 9.5 doesn't mention any backwards 
incompatibility. Am I missing something here?

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

From: Randy Brukardt
Sent: Monday, May 14, 2018  10:26 PM

> I thought of something today, unfortunately after Tullio had sent the 
> AI to the ARG.
> 
> We should probably add a couple paragraphs in the Discussion section 
> stating that we considered defining the rules to target more precisely 
> the preemption points (for example making a call on an open entry, or 
> suspension object, or making calls to Yield,
> etc) rather than the blanket rule of invoking any potentially blocking 
> operation.
> 
> I think the justification is that the rules are simpler, easier to 
> maintain and implement, and provides more preemption points that might 
> be useful for analysis including more likely to break up long bouts of 
> processing, which was part of the original motivation.

You probably should have just proposed some wording to add to the AI; that 
would have been quicker than outlining it and hoping that someone else 
writes it. I can add it if you write it (and it does seem like it would 
clarify the AI).

> The second paragraph should say something about the case where 
> applications have not applied the nonblocking aspect to the various 
> subprogram specifications in the application. An example of this would 
> be legacy systems. The default is that most such calls have 
> nonblocking=>false, which means they are potentially blocking. There 
> could be an extremely large number of preemption points in such an 
> application, which might potentially be prohibitively expensive. Is 
> this a problem?

You're confused. "Potentially blocking" is purely a dynamic concept that 
hasn't been changed much from Ada 95's version. (The only change is to avoid
a requirement to make a check on every routine *except* those with
Nonblocking.) 

"Nonblocking" is a purely static concept. Only language-defined subprograms 
that are not Nonblocking are "potentially blocking", and that's the same set
of subprograms as in the past (except for a couple of bugs that got identified
and fixed during that process). It has *no* effect on user-defined subprograms
vis-a-vis Detect_Blocking or the bounded error.

The Bounded Error for potentially blocking can be detected early, if the 
subprogram itself is potentially blocking. This is a bug in Ada 95 (a useless
permission that causes problems with other rules, specifically 
Detect_Blocking), but given the recent rule changes, such a subprogram is not 
itself potentially blocking. I'm pretty sure you would not want to give 
permission to do context switches on arbitrary calls. In any case, this is an
Ada 95 issue that we *fixed* recently, not something introduced. Without the 
fixes, you would have been right; Ada 95/2005 potentially blocking would not 
have been appropriate for defining dispatching points, since it applied to 
virtually every subprogram and it is very difficult to tell which routines it 
did or didn't apply to.

> This also raises a similar question in my mind, relating to the 
> Nonblocking aspect. Consider a legacy system where a PO calls 
> subprograms in some non-pure package. If these are now considered to 
> be potentially blocking due to lack of a Nonblocking aspect on the 
> specification of the subprogram, the compiler would start to flag 
> these as errors. Is this a backwards compatibility problem?

This does not happen. All language-defined subprograms are specified one way 
or the other (to match the previous definitions), and other routines are never
potentially blocking for this reason.

> One might be able to apply a configuration pragma to say that the 
> Program_Unit is by default NonBlocking, but then presumably the 
> compiler might start flagging routines that actually are potentially 
> blocking as having an incompatible default, requiring code changes to 
> fix.
> 
> The description of Nonblocking aspect in RM 9.5 doesn't mention any 
> backwards incompatibility.
> Am I missing something here?

Yes, read 9.5(56/5) and the associated AARM note carefully. :-) You're 
imagining a problem that does not exist.

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

From: Randy Brukardt
Sent: Monday, May 14, 2018  10:57 PM

>!recommendation
>
>The solution to this unpredictability is to declare all potentially
blocking 
>operations to be preemption points. In this case, all calls to an entry 
>or wait operations on a suspension point are preemption points 
>regardless of whether they are open or not. This simple change would 
>make non-preemptive dispatching more predictable.

For the record, this brings this policy much closer to how Janus/Ada handles
Ada tasking. Janus/Ada reschedules on any call to the task supervisor that can
cause a task to be suspended, whether or not it actually suspends. (This 
happened more for practicality than any plan -- since the task supervisor has
its own separate context a switch is needed to execute it, and then selecting
the next task to run on the way out handles all cases the same way [blocking, 
delay expiration, etc.]).

Janus/Ada does not however, preempt on any call to a potentially blocking 
subprogram (with the exception of the Yield ones, which are mapped to 
supervisor calls) -- doing that on I/O would be rather expensive, especially 
in the character-at-a-time case. I wonder if this would be better if you 
didn't require preemption at most language-defined subprograms that are 
potentially blocking - specifically the large number of I/O routines that are
blocking. Most of those might have some internal locking, but often let the
OS do that if necessary. (That is the main reason I haven't implemented 
Detect_Blocking; I don't know of any way to do that that doesn't make I/O much
more expensive in non-tasking cases.)

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

Questions? Ask the ACAA Technical Agent