Version 1.7 of ais/ai-00118.txt

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

!standard 09.10 (06)          00-04-11 AI95-00118/05
!class binding interpretation 96-04-04
!status Corrigendum 2000 99-07-28
!status WG9 approved 96-12-07
!status ARG approved 9-0-3 96-10-07
!status work item (letter ballot requested and failed) 96-09-15
!status ARG approved 9-0-0 (subject to editorial review) 96-06-17
!status work item 96-04-04
!status received 96-04-04
!priority Medium
!difficulty Hard
!qualifier Omission
!subject Termination signals query of Terminate attribute
!summary
A task T2 can rely on values of variables that are updated by another task T1, if task T2 first verifies that T1'Terminated is True.
!question
Consider:
task body T is Stop_Pulse : Integer;
task Local_Task is ... end Local_Task;
task body Local_Task is begin Stop_Pulse := 17; end T1;
begin loop if Local_Task'Terminated then Rely_On(Stop_Pulse=17); -- Is this erroneous? (No.) exit; end if; end loop; end T;
Since there is no signaling as per 9.10(2-10) between the assignment to Stop_Pulse and any action in task T prior to the call on Rely_On, reliance on the update to Stop_Pulse by Local_Task is erroneous by 9.10(11). 9.10(6) doesn't apply, since T is not yet (or ever) waiting for the termination of Local_Task in the Ada technical sense of "waiting".
!recommendation
(See summary.)
!wording
An action A1 signals an action A2 if A1 is the termination of a task T, and A2 is the evaluation of the expression T'Terminated.
!discussion
It would be surprising if T'Terminated were True, but T failed to update any locally-cached variables, or the querying task failed to see those updates.
The wording is written so that Ada.Task_Identificiation.Is_Terminated(<expr>) (where <expr> evaluates to T'Identity) works the same as T'Terminated. It would be very surprising if this function, defined to be the same as 'Terminated, had a different signaling behavior.
Note that we do not say anything about the Callable attribute; if the Callable attribute becomes False, the task might still have a local cache that is out of sync with global variables.
!corrigendum 9.10(6)
Insert after the paragraph:
the new paragraph:
!ACATS test
It is possible to write a test for the example given here, but it probably would work even for an incorrect implementation.
!appendix

!section 9.10(11)
!subject signaling concept may be incomplete
!reference RM95-9.10(11)
!from Erhard Ploedereder
!keywords signaling, shared variables, sequential
!reference 95-5398.a Erhard Ploedereder  95-11-29>>
!discussion

Consider:

task body T is
 Stop_Pulse : Integer;

 task Local_Task is ... end Local_Task;

 task body Local_Task is
   Stop_pulse := 17;
 end T1;

begin
 loop
    if Local_Task'Terminated then
       Rely_on(Stop_Pulse=17);      -- you better not.
       exit;
    end if;
 end loop;

Since there is no signaling as per 9.10(2-10) between the assignment to
Stop_Pulse and any action in task T prior to the call on Rely_On, reliance
on the update to Stop_Pulse by Local_Task is erroneous by 9.10(11).
9.10(6) doesn't apply, since T is not yet (or ever) waiting for the
termination of Local_Task in the Ada technical sense of "waiting".

Clearly, one would like this idiom to work as "expected" and shared
variables, whose changed values are cached by the implementation of local
tasks, to be updated upon termination at the latest.

There should be a rule requiring that, upon termination of a task, its
updates to shared variables must have occurred, if these variables are read
by other tasks.

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

!section 9.10(11)
!subject signaling concept may be incomplete
!reference RM95-9.10(11)
!keywords signaling, shared variables, sequential
!reference 95-5398.a Erhard Ploedereder  95-11-29
!from Offer Pazy 95-11-30
!reference 95-5404.a Offer Pazy 95-12-1>>
!discussion

Erhard,

I agree with your analysis and I also agree that it would be *nice* if
termination would be folded in the signaling concept. But:

> Clearly, one would like this idiom to work as "expected" and shared
> variables, whose changed values are cached by the implementation of local
> tasks, to be updated upon termination at the latest.

Why is it so important? I mean, why is it so "clear"?  Since Ada does not
provide a way to really wait on a termination of another task (if we exclude
the business of masters which is another issue), only to query the
'terminated attribute, I don't see where spin-waiting will be the practical
way to achieve that. With a simple PO, you can get the same result,
admittedly with more overhead, but I think that in a real life example,
using a PO will be much more realistic.  So to summarize, I am interested to
know why you find this example so useful?

On the implementation side, there is (admittedly small) penalty for doing
what you ask for.  If the reason that Stop_Pulse is not safely available to
T is becuase it is in a register, it is practically guaranteed that when
Local_Task terminates. all the register-variables (those which are visible
to other tasks), will be flushed back to memory.  No problem here.  But your
example suggests that you were thinking of a multi-processor, presumably
with enough processors so you don't care of dedicating one for the
spin-wait. In these cases we have to think about non-consistent caches.
Unless the implementatation keeps a "good" (i.e. quite elaborate) track of
all the global variables that the task touches, the entire cache will have
to be flushed to the real memory when the task terminates.  (I may be wrong
here, but I think that most such caches don't allow you to flush individual
words. They usually flush the entire cache or regions of it.)  Just a
thought.

Offer Pazy
31 Robinwood Ave.
Boston, MA 02130
USA
(617)522-5988
pazy@world.std.com

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

!section 9.10(11)
!subject signaling concept may be incomplete
!reference RM95-9.10(11)
!keywords signaling, shared variables, sequential
!reference 95-5398.a Erhard Ploedereder  95-11-29
!from Erhard Ploedereder
!reference 95-5404.a Offer Pazy
!reference 95-5407.a Erhard Ploedereder 95-12-3>>
!discussion

Offer writes:
> If the reason that Stop_Pulse is not safely available to
> T is becuase it is in a register, it is practically guaranteed that when
> Local_Task terminates. all the register-variables (those which are visible
> to other tasks), will be flushed back to memory.  No problem here.

What makes you so sure ?  (This is actually where my problem started, even
if the comment cast it in terms of 'TERMINATED.)
In terms of language rules, there doesn't seem to be any such guarantee,
unless the local task completes via a terminate alternative (to engage ARM
9.10(6)) AND the master has finalization code to execute (to be able to
reference the variable shared between master and slave task after the
slave's termination) AND that finalization code references the shared
variable.

> Why is it so important? I mean, why is it so "clear"?
Admittedly, I'm not sure. Of course, using a PO solves the problem. But
really, the 'TERMINATED example comes as a bit of a surprise, if the
answer is that there are circumstances where I cannot expect that updates
to shared variables have happened by the time the task has terminated.


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

!from Randy Brukardt  99-10-07

At the recent ARG meeting, it was decided to expand this AI so that
Ada.Task_Identification.Is_Terminated(T'Identity) acts the same as
T'Terminated.

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

Questions? Ask the ACAA Technical Agent