Version 1.7 of ais/ai-00188.txt

Unformatted version of ais/ai-00188.txt version 1.7
Other versions for file ais/ai-00188.txt

!standard D.5 (10)          04-03-24 AI95-00188/05
!class confirmation 04-03-24
!status work item 98-04-02
!status received 97-08-19
!priority Medium
!difficulty Medium
!subject The definition of setting a task base priority is too vague
!summary
Setting a task's base priority is set as soon as practical, subject to the the limitations set forth in D.5(10).
!question
Must the setting of a task base priority happen "immediately" on a monoprocessor, in analogy with the requirements for preemptive abort? (No.)
!response
The questioner was expecting a response along the lines of:
There seems no reason that the timing requirements for changing a task's priority and aborting a task on a single processor should differ significantly. Hence, the term "immediately" should be used in the definition of when a task's base priority is changed on a single processor, once the task is outside a protected action.
In particular, there seems no justification to allow real-time implementations to defer the change of base priority until the task wakes up on its own at its old priority, because the purpose of raising its priority may very well be to have the target task "immediately" preempt some intermediate priority task.
However, there is a justification for the difference. The difference is that "completing" a construct is not the same as "exiting" the construct, and priority change is closer to exiting, since it has a big nasty side-effect -- namely, removal and re-insertion of queued entry calls -- that may require waiting for the caller-task to execute.
From an implementation point of view, we can have some other task mark a given task as having "completed" a construct, but to actually execute the finalization code and leave the construct we need to wait for the affected task to run.
By analogy, here we can change the priority of a task, but if we want the task's entry calls to be repositioned, we have to wait until the task can be scheduled.
The abort statement is defined in the core language and the IRTAW was concerned that a 'valid' implementation could postpone the effect of abort indefinitely - hence the use of "immediate" in the Real-Time Annex. By contrast, the dynamic priorities package is a Annex D facility and hence it can be assumed the implementation does the right thing, and that "as soon as practical" is strong enough. As said before we do not require integer arithmetic to be "immediate", but rely on an implementation to do the obvious and sensible thing. When to complete an abort is not so obvious and hence Annex D's requirement for immediate.
!appendix

!section D.5(10)
!subject The definition of setting a task base priority is too vague
!reference RM95-D.5(10)
!reference RM95-D.6(2)
!from Offer Pazy 97-04-19
!reference 1997-15745.b Offer Pazy  1997-4-19>>
!discussion

At the IRTWA8, it was noted that the use of "as soon as practical" is
unnecessarily vague. I believe that the words was chosen with
multiprocessors in mind. However, a similar problem exists for preemptive
aborts (D.6(2)) and there the language is more precise. It was suggested to
use similar words in D.5(10) in order to tighten the semantics for the
single-processor case. (Note that even if the multi-processor case is not
considered, the single-processor case when running on top of a virtual
processor layer such as threads, should be kept in mind.)

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

From: 	Ted Baker[SMTP:baker@dad.cs.fsu.edu]
!reference AI95-00188/01
!reference RM95-D.6(2)
!from Ted Baker
!discussion

(I apologize for not doing my action-item from the previous ARG
meeting, but taking a 180-degree turn from what we agreed upon in
St. Louis is too much punishment, if that is the intention! :-)

The proposed binding resolution would break the GNAT tasking
implementation in a fundamental way, that I don't know how to fix.
Furthermore, it is contrary to the intent of the original Ada'9X
design as I understood it when I was working on this annex.

| Setting a task's base priority takes place immediately on a monoprocessor,

This is a direct contradiction of the ARM language. D5 (10) was
extensively debated, and the loosenss of "as soon as is practical"
was entirely intentional.

| There seems no reason that the timing requirements for changing a task's
| priority and aborting a task on a single processor should differ
| significantly...
| In particular, there seems no justification to allow real-time
| implementations to defer the change of base priority until the task
| wakes up on its own at its old priority...

The difference is that "completing" a construct is not the same as
"exiting" the construct, and priority change is closer to exiting,
since it has a big nasty side-effect -- namely, removal and
re-insertion of queued entry calls -- that may require waiting for
the caller-task to execute.

From an implementation point of view, we can have some other task
mark a given task as having "completed" a construct, but to
actually execute the finalization code and leave the construct we
need to wait for the affected task to run.

By analogy, here we can change the priority of a task, but if
we want the task's entry calls to be repositioned, we have to
wait until the task can be scheduled.  [Note that the priority
ceiling locking rules require that the calling task do its own
queue reshuffling, or else we have no sensible way to treat
the possibility of one of those operations raising Program_Error
if it violates the priority ceiling.  Note also that this his not
an improbable thing, since users will typically give the task
that is calling for a priority change a very high priority, so
that it gets a chance to do its job!!]

Offer and I argued extensively about this during the Ada'9X
language design period.  I wanted to have immediate priority
changes, but not require entry-queue reordering.  That is, I
wanted the priority of a call to be frozen when it is made,
and not change unless the call is explicitly requeued.  Offer
wanted to have queue reordering, but to make it implementable
we had to allow the priority change to be deferred.

If people feel strongly that the priority change should be
immediate, then perhaps we can rework the compromise, by allowing
the queue reordering to be deferred until the next time the task
executes.  That would require that we "interpret" D.4 (11) as
possibly being delayed until the next time the task executes, at
its new priority.

--Ted Baker

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

From: 	Tucker Taft[SMTP:stt@inmet.com]
Sent: 	Thursday, April 09, 1998 5:53 PM
Subject: 	Re: AI-00188/1

Well one reason to send out these AIs is to get some response.
I'm glad you have provided some rationale for the current wording
of the manual.  We should use that in the AI, whichever way
we ultimately decide it should go.
-Tuck

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

!topic ai-00188 proposed revision (99-03-21)
!from Ted Baker

I believe Tucker's proposed revision of this AI leaves it
impractical to implement on systems where tasks are implemented as threads,
usig the lock and priority primitives of an underlying threads
implementation.

For background: These implementations behave very much like
multi-processor implementations, because the Ada runtime system
does not have direct control over task scheduling or context
switching.  Mutual exclusion is enforced using lock primitives,
and priority is controlled by making service calls, providev by
the thread implementation.  Priority ceiling effect may be
provided implicitly by the lock primitives, or it may need to be
implement by explicit calls to a set-priority operation around the
lock/unlock operations.

What concerns me is the phrase underscored below.

| Setting a task T's base priority takes place immediately on a monoprocessor,
| and as soon as practical on a multiprocessor, except not while the task
                                                xxxxxxxxxxxxxxxxxxxxxxxxx
| is performing a protected action.  On a multiprocessor, the setting
  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
| occurs no later than the next abort completion point of the task T.

Suppose task B wants to change the base priority of task A.  How
will task B tell whether task A is in a protected action?  There is
a "race" condition here between B and A, unless B can "lock" A out
of protected actions while a priority change is under way, and A can
lock B out of priority changes while it is in a protected action.

The proposed semantics would require that the setting of A's
priority and the beginning and end of every protected action
executed by A must be synchronized.  This would roughly double the
locking overhead associated with protected actions, since now we
would not only need to "lock" the protected object, but also
"lock" the base priority of the current task.  Among other things,
this means that task A must be prepared to block when it begins a
protected action if there is a priority change for A going on at
the time, until the priority change is complete.

If Tucker thinks this "double locking" is not necessary, I'm
interested in hearing what implementation model he had in mind.

--Ted

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

From: 	Tucker Taft
Sent: 	Monday, March 22, 1999 12:27 PM

Ted Baker wrote:
> I believe Tucker's proposed revision of this AI leaves it
> impractical to implement on systems where tasks are implemented as threads,
> usig the lock and priority primitives of an underlying threads
> implementation.
>
> For background: These implementations behave very much like
> multi-processor implementations, because the Ada runtime system
> does not have direct control over task scheduling or context
> switching.  Mutual exclusion is enforced using lock primitives,
> and priority is controlled by making service calls, providev by
> the thread implementation.  Priority ceiling effect may be
> provided implicitly by the lock primitives, or it may need to be
> implement by explicit calls to a set-priority operation around the
> lock/unlock operations.
>
> What concerns me is the phrase underscored below.
>
> | Setting a task T's base priority takes place immediately on a monoprocessor,
> | and as soon as practical on a multiprocessor, except not while the task
>                                                 xxxxxxxxxxxxxxxxxxxxxxxxx
> | is performing a protected action.  On a multiprocessor, the setting
>   xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
> | occurs no later than the next abort completion point of the task T.
>
> Suppose task B wants to change the base priority of task A.  How
> will task B tell whether task A is in a protected action?  There is
> a "race" condition here between B and A, unless B can "lock" A out
> of protected actions while a priority change is under way, and A can
> lock B out of priority changes while it is in a protected action.

I didn't mean to propose any change in this area.  The existing
wording of D.5(10) already says "but not while the
task is performing a protected action".  Do you think we
should drop that requirement, or rephrase it to allow implementations
to defer setting the priority until the end of the protected
action, but not require them to do so?  Please elaborate...
>
> The proposed semantics would require that the setting of A's
> priority and the beginning and end of every protected action
> executed by A must be synchronized.  This would roughly double the
> locking overhead associated with protected actions, since now we
> would not only need to "lock" the protected object, but also
> "lock" the base priority of the current task.  Among other things,
> this means that task A must be prepared to block when it begins a
> protected action if there is a priority change for A going on at
> the time, until the priority change is complete.
>
> If Tucker thinks this "double locking" is not necessary, I'm
> interested in hearing what implementation model he had in mind.

I hadn't focused on this issue at all.  I was simply imposing the
requirement for "immediate" priority change, but did not
intend to change the "not while performing a protected action"
wording.

> --Ted

-Tuck

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

From: 	Ted Baker
Sent: 	Monday, March 22, 1999 5:00 PM

Tuck,

I was not asserting that you changed the "not while performing a
protected action", but that you made it significantly harder to
implement, by requiring that the deferral be *exactly* limited to
the duration of the (outermost) protected action (and no longer).
In the GNAT runtime system, we check for pending priority changes
at points where abort deferral ends.  This includes the outermost
part of *most* protected actions, but also finalizers and other
places where abort is deferred.

What I am asking for is that the AI allow the priority change to
be deferred over any region where abort is deferred, including
protected actions.

In a broader sense, if there is language distinguishing the
single-processor case from the MP case, I think we should treat
implementations over OS threads the same as the MP case.  In
effect, they are the same.  The intent of the OS thread
implementations is to hide the number of processors -- so that an
application an move transparently between a machine with any
number of processor to a machine with any other number of
processors.

--Ted

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

!topic ai-00188 proposed revision (99-03-21)
!from Jean-Pierre Rosen

Ted, if your concern is related to the issue of mono/multi processor,
there is no definition in the RM of what a multi-processor is.
It seems perfectly acceptable to me that running threads outside Ada's
implementation control be considered as a "virtual multi-processor".

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

!topic ai-00188 proposed revision (99-03-21)
!reference Jean-Pierre Rosen
!from Ted Baker

| Ted, if your concern is related to the issue of mono/multi processor,
| there is no definition in the RM of what a multi-processor is.
| It seems perfectly acceptable to me that running threads outside Ada's
| implementation control be considered as a "virtual multi-processor".

I don't have a problem with this, so long as it is written down somewhere,
and applied during validation testing.

--Ted

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

From: Alan Burns
Sent: Monday, November 24, 2003  6:43 AM

...

I also had an old AI (188) assigned to me.
This concerns the immediacy of abort and priority
change. Abort has to be immediate, but priority change
as soon as implementation can. The body of the AI has
a number of contributions from Ted Baker explaining and
defending the current wording. His arguement seem straightforward
and convincing. I recommend no action on this AI.

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

From: Alan Burns
Sent: Monday, November 24, 2003  6:43 AM

Minutes of last meeting concerning AI-188/03 state:
"Alan will rewrite the AI as a confirmation AI."

I'm not exactly sure what is means (sorry). So here is an attempt to redo the
AI.

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


Questions? Ask the ACAA Technical Agent