Version 1.7 of ais/ai-00237.txt

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

!standard C.07.02 (17)          00-12-07 AI95-00237/03
!class binding interpretation 00-05-31
!status work item 00-06-01
!status received 00-05-16
!qualifier Clarification
!priority Low
!difficulty Medium
!subject Finalization of task attributes
!summary
The master of task attributes is the master of the instantiation of Ada.Task_Attributes that creates them. Task attributes can be finalized at any point after their task is terminated and no later than the completion of the master of the instantiation of Ada.Task_Attributes that created them.
!question
C.7.2(17) says:
"When a task terminates, the implementation shall finalize all attributes of the task, and reclaim any other storage associated with the attributes."
Does this mean after a task terminates? (Yes.) Can the termination occur concurrently with the interrogation of attributes of the task? (No.)
This wording also appears to allow an attribute to outlive its type. Is this intended? (No.)
!recommendation
(See summary.)
!wording
Add the following after C.7.2(13):
When the master of an instantiation of Ada.Task_Attributes is finalized, the associated attribute for all tasks is finalized.
Delete C.7.2(17).
Add the following after C.7.2(29):
After a task terminates, an implementation may finalize all attributes of the task (instead of when the master of the instantiation is finalized), and reclaim any other storage associated with the attributes.
Add "finalization of a task attribute" to C.7.1(17).
!discussion
Although it is not clear from the RM, it is not possible in general for a task to finalize its own attributes. That occurs because a task that is never activated may have attributes that require finalization.
However, this begs the question: if a task owning attributes cannot finalize them, what task does? One way to attempt to answer the question is to determine the master of the attributes. (After all, for ordinary objects, it is the master that determines when they are finalized.) However, the RM never addresses this at all.
It is clear that the task attributes should not exist any longer than the instantiation that created them. If they do exist past that point, there is the risk that their type is also no longer accessible, and that the finalization may depend on entities that no longer exist. Therefore, we declare that the master of the instantiation is the master of the task attributes.
This gives a clear point by which the finalization of attributes must have completed: the completion of the master which contains the instantation. Once we have this clear point, we no longer need the (now) conflicting rule that says that the attributes are finalized when their task terminates. Moreover, this rule complicates implementation of task attributes, requiring an interaction between the attributes package and the task supervisor upon task termination. This can be difficult to accomplish when Ada tasking is built on top of an existing operating systems threading mechanisms.
Therefore, we convert this rule to an implementation permission, allowing finalization at any point after a task terminates. We leave it as an implementation permission (rather than deleting it outright) for three reasons:
* So that existing implementation needs not changed;
* So that storage can be recovered when a task terminates. For long-running applications which dynamically create tasks, this storage can be significant;
* So that attributes can be implemented as a property of a task (say, as space in a task control block [TCB]). In order to support that, we have to be able to finalize attributes when task data structures are freed.
An implementation taking advantage of this permission must insure that only a single task finalizes the attributes. (It is possible for a task to terminate at the same time that the master containing the instantation is left. It must never be the case that both tasks finalize the attributes.)
It is important that attributes are not finalized before task termination, because they can be accessed until T'Terminated becomes True. We do not want to be able to access finalized task attributes.
Since we do not define which task finalizes the attributes (or even if it is a real task), we make the use of Current_Task in the Finalize routine of a task attribute a bounded error.
!corrigendum C.7.1(17)
Replace the paragraph:
It is a bounded error to call the Current_Task function from an entry body or an interrupt handler. Program_Error is raised, or an implementation-defined value of the type Task_ID is returned.
by:
It is a bounded error to call the Current_Task function from an entry body, interrupt handler, or finalization of a task attribute. Program_Error is raised, or an implementation-defined value of the type Task_ID is returned.
!corrigendum C.7.2(13)
Insert after the paragraph:
For all the operations declared in this package, Tasking_Error is raised if the task identified by T is terminated. Program_Error is raised if the value of T is Null_Task_ID.
the new paragraph:
When the master of an instantiation of Ada.Task_Attributes is finalized, the associated attribute for all tasks is finalized.
!corrigendum C.7.2(17)
Delete the paragraph:
When a task terminates, an implementation shall finalize all attributes of the task, and reclaim any other storage associated with the attributes.
!corrigendum C.7.2(29)
Insert after the paragraph:
An implementation is allowed to place restrictions on the maximum number of attribute a task may have, the maximum size of each attribut, and the total storage size allocated for all attributes of a task.
the new paragraph:
After a task terminates, an implementation may finalize all attributes of the task (instead of when the master of the instantiation is finalized), and reclaim any other storage associated with the attributes.
!ACATS test
It would be possible to create a test to insure that task attributes are finalized at some point between the termination of the task and the leaving of the instantation's master, but such a test would not add much value to CXC7003.A (which already tests finalization of attributes, but not this specific case).
!appendix

From: Michael Yoder
Sent: Monday, May 15, 2000 4:34 PM

C.7.2(17) says:

"When a task terminates, the implementation shall finalize all attributes
of the task, and reclaim any other storage associated with the attributes."

Does this mean *after* a task terminates, or at some time in the near
vicinity?  And what behavior is allowed if this termination occurs
concurrently with the interrogation of attributes of the task?

Any answer other than that the finalization occurs after termination (and
that termination is atomic with respect to operations involving task
attributes) has unpleasant consequences.  These take the form of race
conditions when interrogating the attributes (they can be used after being
finalized in such a case, or even simultaneously with being finalized).

If it occurs after finalization, what is permissible behavior for the
Ada.Task_Identification.Current_Task function during this finalization?
(The natural-seeming answer, that it is the task whose attributes are being
finalized, would have the consequence that Current_Task returns a
terminated task.)

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

From: Ted Baker
Sent: Monday, May 15, 2000 6:29 PM

The processing involved in task termination is sufficiently
complicated that it cannot be considered to be atomic in any
strong sense.  There is an interval of time during which a task is
in the process of terminating, but not yet terminated.  Some time
during this process the task becomes terminated, after which the
value of the 'Terminated attribute will start returning the value
True.  (I don't think the Ada language needs to define this point
precisely.)  After this point, if a task is in some way manages to
call Current_Task'Terminated it will see the value True, just as
any other task would see that attribute of the same task.

I don't see this behavior as being a problem.  I do think that
anyone who expects to do complicated processing in a finalizer (in
particular, behavior that requires the current task to not be
terminated) is asking for trouble.

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

From: Tucker Taft
Sent: Monday, May 15, 2000 5:55 PM

> Any answer other than that the finalization occurs after termination (and
> that termination is atomic with respect to operations involving task
> attributes) has unpleasant consequences.

Good point.  So (of course ;-) the answer is that task termination is
atomic with respect to task attribute interrogation, and that
before finalizing task attributes, the task is (marked) terminated.

It is a bit surprising that you can set and get attributes of
a task after it is completed, normally or abnormally.  I.e.
task'callable can be false, but you can still fiddle with its
attributes (I just noticed that our RTS got this wrong -- we raise
Tasking_Error if the task is uncallable -- looks like yet another
ACATS test might be needed...).

> If it occurs after finalization, what is permissible behavior for the
> Ada.Task_Identification.Current_Task function during this finalization?
> (The natural-seeming answer, that it is the task whose attributes are being
> finalized, would have the consequence that Current_Task returns a
> terminated task.)

Yes, I would say that Is_Terminated(Current_Task) should be true
during attribute finalization -- admittedly weird.

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

From: Randy Brukardt
Sent: Monday, May 15, 2000 8:01 PM

> Yes, I would say that Is_Terminated(Current_Task) should be true
> during attribute finalization -- admittedly weird.

Say what? You want us to rewrite our runtime systems so that tasks can
execute after termination just for task attributes? That sounds as silly as
returning terminated tasks outside of their master was in Ada 83.

In Janus/Ada at least, Terminated=True is equivalent to all data structures
destroyed. It is set just previous to exiting to the scheduler to let
another task run, and there is no possibility of coming back.

I suppose we could somehow add a TCB flag "Tuckers_Bogus_Terminate", and set
it during the finalization of the task (returning it rather than the real
"Terminated" to queries of 'Terminated), but that would require adding at
least one supervisor call or a "magic" finalization chain marker.

I think Ted has the right answer (termination is not atomic, because it
involves finalization). The ability of task attributes to be finalized can
be useful, because it allows user to insure resources are freed when the
task terminates. But using that capability does not need to depend on
anything in the task itself, so tightly defining this is not necessary for
the primary use.

Some certified compilers limit task attributes to a single word (using the
permission of C.7.2(29)), thus sidestepping the issue (a tagged type can fit
into a single word). If we insist on a tightly defined semantics, I think we
will end up seeing more compilers adopting similar restrictions.

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

From: Michael Yoder
Sent: Tuesday, May 16, 2000 9:39 AM

Randy Brukardt wrote, responding to Tucker Taft:
>> Yes, I would say that Is_Terminated(Current_Task) should be true
>> during attribute finalization -- admittedly weird.
>
>Say what? You want us to rewrite our runtime systems so that tasks can
>execute after termination just for task attributes? That sounds as silly as
>returning terminated tasks outside of their master was in Ada 83.

Actually, I like Tucker's answer better than the one I had originally hoped
for (namely, that interrogating Current_Task during attribute finalization
was a bounded error).

>In Janus/Ada at least, Terminated=True is equivalent to all data structures
>destroyed. It is set just previous to exiting to the scheduler to let
>another task run, and there is no possibility of coming back.

That is a pleasant property, but I wouldn't consider this relevant to the
issue unless it was a condition required by the present or future LRM.  Is
there a consensus that it ought to become so?

>I think Ted has the right answer (termination is not atomic, because it
>involves finalization). The ability of task attributes to be finalized can
>be useful, because it allows user to insure resources are freed when the
>task terminates. But using that capability does not need to depend on
>anything in the task itself, so tightly defining this is not necessary for
>the primary use.

I don't understand the last part of this paragraph.  What do you consider
to be the primary use?

Termination must be atomic in this sense: at some point in time,
interrogating T'Terminated (explicitly or implicitly) must become true and
remain so.  Making this attribute mushy in *any* sense is asking for much
trouble.  Let us not mix the two meanings of the word "termination" here:
"termination" as the process of tearing down a task isn't relevant.  What
matters is when the task becomes terminated, as a binary state change.

>Some certified compilers limit task attributes to a single word (using the
>permission of C.7.2(29)), thus sidestepping the issue (a tagged type can fit
>into a single word). If we insist on a tightly defined semantics, I think we
>will end up seeing more compilers adopting similar restrictions.

But not having tightly defined semantics makes the feature much harder to
use correctly.  There isn't any implementation difficulty here: insuring
termination is atomic to uses of attributes is as simple as having a
termination flag of an atomic boolean type.

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

From: Ted Baker
Sent: Tuesday, May 16, 2000 10:27 AM

| So (of course ;-) the answer is that task termination is
| atomic with respect to task attribute interrogation, and that
| before finalizing task attributes, the task is (marked) terminated.

That is possible.  On the other hand, I don't think the language
of the ARM (below) is so tight as to require that the task be
marked terminated before the finalization starts, not do I think
it needs to be tighter.

| 17 When a task terminates, the implementation shall finalize all
| attributes of the task, and reclaim any other storage associated
| with the attributes.

Termination is really a process, and marking the task terminated
simply means it is committed to this process ... not that the
process of task termination has completed.  With finalization of
task attributes being part of this process, and the finalization
code possibly taking an unbounded amount of time (a bad usage) to
run, the termination process could potentially be very protracted.

By the way, there is no reason to assume the finalization of task
attributes of a task T is done by the same task T.  I just looked
at the GNARL, and noticed that the finalization of task attributes
for a task T is generally done by some other task T, generally one
of the master tasks of T.  I think this is entirely consistent
with the ARM and with the way in which the attributes were created
(which could be by the task itself or any other task).

I also noticed in GNARL that the finalization of task attributes
is done late in the termination process, just before the task
control block is deallocated.  That is, when the task state
becomes terminated the task may continue executing in the runtime
system for a while, and may continue to exist as a referenceable
entity for a while after it stops executing.  Finally, when there
can be no further reference to the task, the attributes are
finalized and the control block is deallocated.

This postponement of finalization seems consistent with the ARM,
since it is still part of the termination process.  I originally
thought it was friendlier to users, since my original intent for
user-defined task attributes in Ada9X was that they continue to be
useable throughout the same scope as the language-defined task
attributes (like T'Terminated).  However, at some point the clause
was put in saying that Tasking_Error should be raised for
referenced to attributes of terminated tasks, so the postponement
of finalization does not have any benefit.

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

From: Randy Brukardt
Sent: Tuesday, May 16, 2000 11:47 AM

> Termination must be atomic in this sense: at some point in time,
> interrogating T'Terminated (explicitly or implicitly) must
> become true and remain so.  Making this attribute mushy in *any*
> sense is asking for much trouble.  Let us not mix the two meanings
> of the word "termination" here: "termination" as the process of
> tearing down a task isn't relevant.  What matters is when the task
> becomes terminated, as a binary state change.

OK, but why do you care? That is, how can you write a useful program
that cares whether 'Terminated changes before or after the finalization
of task attributes? (One that simply prints out the value of 'Terminated
is not useful!)

I can't do it without using a task attribute from the Finalize of another
attribute, but that is likely to have triggered the bounded error for
C.7.2(13.1/1). Moreover, C.7.2(16/1) allows an implementation to use a
per-task
lock to insure atomic operations, and that would deadlock. So using task
attributes in Finalize should be avoided.

> But not having tightly defined semantics makes the feature much harder to
> use correctly.

Again, I don't see this. Please provide an example that doesn't use task
attributes in a Finalize.

> There isn't any implementation difficulty here: insuring
> termination is atomic to uses of attributes is as simple as having a
> termination flag of an atomic boolean type.

By adding precision where none was present before, you are forcing (some)
implementors to take an effort to modify their task supervisors. This is a
particularly difficult area to work on, and I think we need to see that
there is some *real* benefit to users before we require work from
implementors.

The change is certainly more than "having a termination flag". Janus/Ada
does not allow the program direct access to the TCB, so each entity visible
to the program  requires the addition of supervisor calls. This would take
at least two new supervisor calls (one to query the "real" termination flag,
and one to set the "fake" termination flag before doing attribute
finalization). Moreover, we would have to carefully examine every use of the
current termination flag to see if was used for "real" termination or to
return the value of 'Terminated. There is a very real chance that the change
would break something subtle, potentially causing days of debugging.

So, I think that in the absence of a real benefit to users, this question
should not be answered.

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

From: Ted Baker
Sent: Tuesday, May 16, 2000 1:17 PM

| Termination must be atomic in this sense: at some point in time,
| interrogating T'Terminated (explicitly or implicitly) must become true and
| remain so.

The property you state above is not atomicity, but monotonicity.
No one has suggested that the change in value of T'Terminated
is not monotonic.

| But not having tightly defined semantics makes the feature much harder to
| use correctly.  There isn't any implementation difficulty here: insuring
| termination is atomic to uses of attributes is as simple as having a
| termination flag of an atomic boolean type.

If you attempt to access a user-defined task attribute of a
terminated task you will get Program_Error, unless you have
disabled this check, or you are using the pointer method and have
a reference to the attribute via a dangling pointer.  In the
latter cases you are programming erroneously.

Again, you cannot make any assumption about what task is executing
the finalization code for the attributes of a task.  Therefore,
it would be erroneous to use the value returned by Current_Task.

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

From: Michael Yoder
Sent: Tuesday, May 16, 2000 1:19 PM

The case I care about is that mentioned in my original message: when other
tasks use attributes of a task which is in the process of becoming
terminated.  (That is why I included implicit use of 'Terminated above.)
These are the "race conditions" I spoke of.  No use of task attributes in
Finalize is needed, only the usual, expected kind of uses by other tasks.
In fact, is isn't necessary to export task IDs out of their scope.

*Any* use of task attributes counts if this use could occur either before
or after the task terminates.  (For example, a monitor task sampling the
attribute periodically.)

The example was given in my original message: "[task attributes] can be
used after being finalized in this case, or even simultaneously with being
finalized."  I'm asserting that the language of C.7.2(17) should be
interpreted so as to prevent uses of task attributes after they are
finalized, or (worse) concurrently with being finalized.  More precisely,
attempted use should raise Tasking_Error in accordance with C.7.2(13).

>By adding precision where none was present before, you are forcing (some)
>implementors to take an effort to modify their task supervisors. This is a
>particularly difficult area to work on, and I think we need to see that
>there is some *real* benefit to users before we require work from
>implementors.

The benefit is that an entire *class* of usage becomes possible.  I would
say that any use which doesn't involve exporting task IDs out of scope (so
erroneous execution doesn't enter into the picture) should be considered
normal usage.  The alternative is to say that correct use of task
attributes must allow for the possibility that the task could terminate,
and the finalization procedure could be run, concurrently with independent
use of the attribute.

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

From: Randy Brukardt
Sent: Tuesday, May 16, 2000 3:51 PM

> The case I care about is that mentioned in my original message: when other
> tasks use attributes of a task which is in the process of becoming
> terminated.  (That is why I included implicit use of 'Terminated above.)
> These are the "race conditions" I spoke of.  No use of task attributes in
> Finalize is needed, only the usual, expected kind of uses by other tasks.
> In fact, is isn't necessary to export task IDs out of their scope.

OK, thanks for explaining this. I had read your original message before
sending the last message, and I could not decipher what caused the race
conditions you were talking about.

Unfortunately, this discussion has been filled with irrelevant details, like
the value of 'Terminated and returning terminated tasks, none of which has
anything to do with the problem at hand.

It is completely clear that any reference to an attribute that is being
finalized (or already has been finalized) should raise Tasking_Error. (If
that isn't true, than any reference to a task attribute is potentially
erroneous, which clearly isn't acceptable).

However, it certainly isn't necessary to require compilers to support
running terminated tasks in order to get that behavior. The 'Terminated
value is of no use in this case anyway (because testing the attribute and
then doing an operation is a potential race condition), so it seems to me
that the real problem is that C.7.2(13) is tied too tightly to termination.

I would suggest making access to task attributes during the process of
termination a bounded error, such that they either work as expected or raise
Tasking_Error. Alternatively, we could extend/revise C.7.2(13) to say that
Tasking_Error is raised if the finalization of the attribute has begun.
(Indeed, that could completely replace the existing rule.)

Changing the meaning of 'Terminated here is distributed pain for at least
some run-time systems, and has no user value (at least, it doesn't have
anything to do with the example you stated). Tweaking the rules for
attributes alone localizes any needed changes to the attribute code itself;
and I suspect that most implementations get this right somehow.

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

From: Michael Yoder
Sent: Tuesday, May 16, 2000 3:44 PM

Ted Baker wrote:
>| Termination must be atomic in this sense: at some point in time,
>| interrogating T'Terminated (explicitly or implicitly) must become true and
>| remain so.
>
>The property you state above is not atomicity, but monotonicity.
>No one has suggested that the change in value of T'Terminated
>is not monotonic.

Well, yes, but this change must in effect be atomic by virtue of the rules
in 9.10(2-10), plus a lot of citations I didn't want to run down.  Now that
I look at it more closely, I think these rules plus C.7.2(17) should
suffice in this particular instance.  (Taking a strict interpretation of
the latter, as I have advocated in other messages.)  I believe it is
provable that termination is effectively atomic with respect to nearly any
tasking operation, but I'd hate to have to construct all the proofs.  :-)

>| But not having tightly defined semantics makes the feature much harder to
>| use correctly.  There isn't any implementation difficulty here: insuring
>| termination is atomic to uses of attributes is as simple as having a
>| termination flag of an atomic boolean type.
>
>If you attempt to access a user-defined task attribute of a
>terminated task you will get Program_Error, unless you have
>disabled this check, or you are using the pointer method and have
>a reference to the attribute via a dangling pointer.  In the
>latter cases you are programming erroneously.

This only applies to the specific case of dereferencing a value supplied by
Reference.  The cases of using Value, Set_Value, or Reinitialize remain
problems with respect to the synchronization issues regarding finalization.
 (Sorry if the phrase "use of task attributes" was vague on this point.)

>Again, you cannot make any assumption about what task is executing
>the finalization code for the attributes of a task.  Therefore,
>it would be erroneous to use the value returned by Current_Task.

This is an entirely reasonable answer to the final question of my first
message, assuming you are using "erroneous" colloquially here.  If not I'd
argue it is preferable to make it a bounded error, and rule as to what
behavior is allowed.

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

From: Jean-Pierre Rosen
Sent: Tuesday, May 16, 2000 4:03 PM

I was surprised in this discussion that everybody talked only about *terminated*
tasks. For variables declared in the task body, finalization happens when the
task is *completed*, but not yet *terminated* - see 9.3(5).

Is there any reason to believe that task attributes do not behave the same?
After all, they are quite like variables declared directly within the task.
Admitedly, the phrasing "when the task terminates" is vague, but it would seem
logical to admit this describes the termination process in 9.3(5).

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

From: Tucker Taft
Sent: Tuesday, May 16, 2000 9:27 PM

Randy Brukardt wrote:
> ...
>
> It is completely clear that any reference to an attribute that is being
> finalized (or already has been finalized) should raise Tasking_Error. (If
> that isn't true, than any reference to a task attribute is potentially
> erroneous, which clearly isn't acceptable).
>
> However, it certainly isn't necessary to require compilers to support
> running terminated tasks in order to get that behavior. The 'Terminated
> value is of no use in this case anyway (because testing the attribute and
> then doing an operation is a potential race condition), so it seems to me
> that the real problem is that C.7.2(13) is tied too tightly to termination.
>
> I would suggest making access to task attributes during the process of
> termination a bounded error, such that they either work as expected or raise
> Tasking_Error. Alternatively, we could extend/revise C.7.2(13) to say that
> Tasking_Error is raised if the finalization of the attribute has begun.
> (Indeed, that could completely replace the existing rule.)

I would prefer to see us change this so that you get Tasking_Error if
a task is *completed* or abnormal and you reference its task attributes.
That is the usual boundary between normal and Tasking_Error propagation.
I wonder why we made task attributes different?  Is it perhaps
that a task wants to refer to its own attributes during finalization?
Is that added capability useful/worth the trouble?

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

From: Tucker Taft
Sent: Tuesday, May 16, 2000 7:54 PM


Michael Yoder wrote:
> ...  I would
> say that any use which doesn't involve exporting task IDs out of scope (so
> erroneous execution doesn't enter into the picture) should be considered
> normal usage.  The alternative is to say that correct use of task
> attributes must allow for the possibility that the task could terminate,
> and the finalization procedure could be run, concurrently with independent
> use of the attribute.

It seems the critical requirement is that no access to a task attribute is
permitted after it has begun to be finalized.  I.e., Tasking_Error is raised
on reference to a task attribute that is being, or has been finalized.
It would seem "nice" that 'Terminated return True before you start getting
these kinds of Tasking_Errors, but that seems somewhat less critical.

I agree with Mike that it should *not* be erroneous to reference task attributes
of a task concurrent with its terminating, and it should *not* be possible to
successfully get/set an attribute after it has been finalized.

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

From: Randy Brukardt
Sent: Wednesday, May 17, 2000 11:25 AM

Tucker Taft wrote:

> I would prefer to see us change this so that you get Tasking_Error if
> a task is *completed* or abnormal and you reference its task
> attributes. That is the usual boundary between normal and Tasking_Error
> propagation.

I agree. The only reason I didn't suggest it was that it seemed to be too large
a change - someone might care.

> I wonder why we made task attributes different?  Is it perhaps
> that a task wants to refer to its own attributes during finalization?
> Is that added capability useful/worth the trouble?

The AARM offers no enlightenment here.

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

From: Michael Yoder
Sent: Wednesday, May 17, 2000 11:48 AM

Tucker wrote:

>I would prefer to see us change this so that you get Tasking_Error if
>a task is *completed* or abnormal and you reference its task attributes.
>That is the usual boundary between normal and Tasking_Error propagation.

This would have the strong virtue that my original second question would
need no answer: during finalization of task attributes, Current_Task would
always be the task whose attributes are being finalized, and it wouldn't be
terminated yet.  Or rather, it would enable a change along such lines.  I
would ask Ted Baker et al. to weigh in as to how painful such a change
would be.

>I wonder why we made task attributes different?  Is it perhaps
>that a task wants to refer to its own attributes during finalization?
>Is that added capability useful/worth the trouble?

I don't think you lose anything here: currently the task is terminated in
at least some existing implementations, so attributes aren't available
anyway.  Also, any scheme that allowed this would probably have to include
precise rules about the order of finalization of the attributes, or it
wouldn't be usable in any event.

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

From: Ted Baker
Sent: Wednesday, May 17, 2000 11:33 AM

| This only applies to the specific case of dereferencing a value
| supplied by Reference.  The cases of using Value, Set_Value, or
| Reinitialize remain problems with respect to the synchronization
| issues regarding finalization.  (Sorry if the phrase "use of
| task attributes" was vague on this point.)

That is pretty clearly specified as safe.

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

From: Ted Baker
Sent: Wednesday, May 17, 2000 11:35 AM

| I was surprised in this discussion that everybody talked only
| about *terminated* tasks.  For variables declared in the task
| body, finalization happens when the task is *completed*, but not
| yet *terminated* - see 9.3(5).

| Is there any reason to believe that task attributes do not behave
| the same ? After all, they are quite like variables declared
| directly within the task. Admitedly, the phrasing "when the task
| terminates" is vague, but it would seem logical to admit this
| describes the termination process in 9.3(5).

There can be a very long (maybe forever) delay between completion
and termination of a task.  Finalization of task attributes before
termination is illegal.

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

From: Ted Baker
Sent: Wednesday, May 17, 2000 12:42 PM

| I would prefer to see us change this so that you get
| Tasking_Error if a task is *completed* or abnormal and you
| reference its task attributes.  That is the usual boundary
| between normal and Tasking_Error propagation.  I wonder why we
| made task attributes different?  Is it perhaps that a task wants
| to refer to its own attributes during finalization?  Is that
| added capability useful/worth the trouble?

I think this would be a very bad idea.

Anybody who uses task attributes (e.g., for user-defined
scheduling, resource management) is likely to continue to need
the attribute until the task stops executing.

Remember that with finalization the meaning of "complete" is
pretty much gone.  It effectively just means the task can no
longer make rendezvous.  After a task completes it can still have
active children and still do meaningful execution, through
finalization actions.

1) We should always avoid unnecessary language changes.
2) This change would gain nothing.
3) This change would cost users functionality and
   increase the risk of user race conditions.
4) This change would require changes to implementations,
   and possibly break existing code.

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

From: Ted Baker
Sent: Wednesday, May 17, 2000 12:52 PM

| This would have the strong virtue that my original second question would
| need no answer: during finalization of task attributes, Current_Task would
| always be the task whose attributes are being finalized, and it wouldn't be
| terminated yet.  Or rather, it would enable a change along such lines.  I
| would ask Ted Baker et al. to weigh in as to how painful such a change
| would be.

WHOA!!!  (Isn't anybody reading?)  I mentioned earlier that there
are situations where this is impossible, i.e., the task whose
attributes are being finalized never even activated, but we still
have to finalize the attribute values.

Remember the purpose of these attributes, which is to allow a user
to keep track of user-defined resources associated with tasks, and
recover the resources when they can no longer be used.

If we change anything here, it should be to allow access to the
attributes of terminated tasks (without Tasking_Error) up the
point where the task can no longer be referenced, i.e. until the
point where the system resources of the task are recovered by the
implementation.

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

From: Randy Brukardt
Sent: Wednesday, May 17, 2000 3:32 PM

Ted said:

> If we change anything here, it should be to allow access to the
> attributes of terminated tasks (without Tasking_Error) up the
> point where the task can no longer be referenced, i.e. until the
> point where the system resources of the task are recovered by the
> implementation.

We *have* to change something here, because the current situation allows
access to finalized attributes on some implementations. We need to at least
tighten up the language of this section to prevent that.

But certainly your idea is at least as bad as Tucker's: it requires proxy
finalizations, which may not be possible on all implementations of
finalization. And it certainly would require most implementations to change.

I still think my idea was the best, because it eliminated the direct
connection between termination (i.e. 'Terminated) and attribute access,
without substantially changing anything for users. Probably most
implementations would already compily:

Replace C.7.2(13) by:

For all of the operations defined in this package, Tasking_Error is raised
if the finalization of the attribute has begun.

Combined with C.7.2(17), this is similar to the existing rule, but it
eliminates worrying about whether a terminated task (as opposed to completed
task) can run. (Remember that objects of *all* types are finalized, not just
tagged types.)

I think this has the minimal change, and avoids the grey area. But I'm no
expert in real-time programming, so I might have missed something.

			Randy.

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

From: Ted Giering
Sent: Wednesday, May 17, 2000 3:23 PM

Ted Baker wrote:
> If we change anything here, it should be to allow access to the
> attributes of terminated tasks (without Tasking_Error) up the
> point where the task can no longer be referenced, i.e. until the
> point where the system resources of the task are recovered by the
> implementation.

As you point out in a previous message, that would  require changes to
some implementations, in particular Apex.  Our runtime has a terminated
task mark itself as terminated and then finalize its attributes.  The
terminated flag itself is used to determine if Tasking_Error should be
raised on attribute reference.  Once the attributes are finalized the
task never runs again.  Deferring attribute finalization further would
require having another task do the work, which I suspect would be a
nontrivial change.

I wonder if the original idea of saying that the attributes are
finalized on task termination is just to indicate that their
finalization needs to come after the rest of the task body
finalization, that is, the finalization of objects declared in the task
body, just to preserve LIFO ordering.  Finalizing the attributes after
marking the task as terminated obviates the need to further specify the
order of attribute finalization, as Mike pointed out, which simplifies
implementation.

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

From: Tucker Taft
Sent: Wednesday, May 17, 2000 9:57 PM

Randy Brukardt wrote:
> Replace C.7.2(13) by:
>
> For all of the operations defined in this package, Tasking_Error is raised
> if the finalization of the attribute has begun.

I presume you only meant to replace the first sentence C.7.2(13)
I would rather see :

   For all of the operations defined in this package, Tasking_Error is raised if the
   task identified by T is terminated, or the implementation has begun
   finalization of the attribute.

> Combined with C.7.2(17), this is similar to the existing rule, but it
> eliminates worrying about whether a terminated task (as opposed to completed
> task) can run. (Remember that objects of *all* types are finalized, not just
> tagged types.)
>
> I think this has the minimal change, and avoids the grey area. But I'm no
> expert in real-time programming, so I might have missed something.

I think we should preserve the fact that once 'Terminated is true,
you get Tasking_Error.  You may start getting it a bit earlier than that,
but no later.

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

From: Robert A Duff
Sent: Thursday, May 18, 2000 10:31 AM

>    For all of the operations defined in this package, Tasking_Error is raised if the
>    task identified by T is terminated, or the implementation has begun
>    finalization of the attribute.

Don't we want to allow the implementation to raise T_E if it has started
finalizing *some* attribute, and some other task accesses some *other*
attribute?  Otherwise, the implementation has to keep track of which
attributes it has finalized, individually.  It seems easier to implement
if it can simply keep track of the fact that it has started finalizing
the attributes.  It seems like this would not affect programs -- how can
you write a program that cares about the difference between "we have
started finalizing attribute X" and "we are about to start finalizing
attribute X real soon -- as soon as we get done finalizing attribute Y"?
Such a program would get T_E anyway, if the other task were just a
little bit slower.

Am I making sense?

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

From: Michael Yoder
Sent: Thursday, May 18, 2000 12:32 PM

Ted Baker wrote:
>I mentioned earlier that there
>are situations where this is impossible, i.e., the task whose
>attributes are being finalized never even activated, but we still
>have to finalize the attribute values.

I cannot find this in your earlier messages.  Could you provide a
pointer?  If I have missed a message I'd like to read it.

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

From: Jean-Pierre Rosen
Sent: Thursday, May 18, 2000 2:35 AM
To: Ada-Comment List
Subject: Re: [Ada-Comment] finalization of task attributes; value of
Current_Task

> | I was surprised in this discussion that everybody talked only
> | about *terminated* tasks.  For variables declared in the task
> | body, finalization happens when the task is *completed*, but not
> | yet *terminated* - see 9.3(5).
>
> | Is there any reason to believe that task attributes do not behave
> | the same ? After all, they are quite like variables declared
> | directly within the task. Admitedly, the phrasing "when the task
> | terminates" is vague, but it would seem logical to admit this
> | describes the termination process in 9.3(5).
>
> There can be a very long (maybe forever) delay between completion
> and termination of a task.  Finalization of task attributes before
> termination is illegal.
>
Of course. I just meant that:
- during finalization, the task should be seen as completed, but not terminated.
- finalization of task attributes should be considered part of "finalization of
  the task body", as defined in 9.3(5).

I agree that accessing the attribute after finalization has started should raise
Tasking_Error, which is a bit earlier than when the task is terminated.

(Note however that there are other places in the language where you can access a
variable after it has been finalized, but that would be unfortunate in this
case, since it would mean accessing released memory).

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

From: Ted Baker
Sent: Thursday, May 18, 2000 12:30 PM

| As you point out in a previous message, that would require changes to
| some implementations, in particular Apex.  Our runtime has a terminated
| task mark itself as terminated and then finalize its attributes.  The
| terminated flag itself is used to determine if Tasking_Error should be
| raised on attribute reference.  Once the attributes are finalized the
| task never runs again.  Deferring attribute finalization further would
| require having another task do the work, which I suspect would be a
| nontrivial change.

I am not pushing for a change.  I would prefer leaving the
language as it is.  I just wanted to point out in opposition to
the proposal for moving finalization of attributes earlier (task
completion) that if we are ready to break implementations and
applications, it would be better to gain something useful for the
user.  I think the later finalization would do that.

| I wonder if the original idea of saying that the attributes are
| finalized on task termination is just to indicate that their
| finalization needs to come after the rest of the task body finalization,
| that is, the finalization of objects declared in the task body,
...
| Finalizing the attributes after marking the
| task as terminated obviates the need to further specify the order of
| attribute finalization, as Mike pointed out, which simplifies
| implementation.

That is what I have always thought.  That is, the finalization
of task attributes must happen after the finalization of all the
objects within the task body.  In that way those finalizations
can safely use the task attributes.

| ...just to preserve LIFO ordering.

I don't think LIFO fits here, since the values of the task
attributes can be changed dynamically during the lifetime of the
task.  Also, a new task attribute can be created after the
creation of a task.  There is just no connection between the
lifetimes of the attribute values and the tasks, other than it
makes sense toe force cleanup at the end of the task to avoid
storage leakage.

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

From: Ted Baker
Sent: Thursday, May 18, 2000 12:15 PM

| We *have* to change something here, because the current situation allows
| access to finalized attributes on some implementations. We need to at least
| tighten up the language of this section to prevent that.

I don't see any such gap.  The language currently requires that
Tasking_Error be raised if the user attempts to access one of
these attributes of a task that has reached the "terminated"
state.  I think we all agree that the task is marked as
"terminated" when it begins the termination process, so that
during finalization the task is viewed as terminated.

| But certainly your idea is at least as bad as Tucker's: it requires proxy
| finalizations, which may not be possible on all implementations of
| finalization. And it certainly would require most implementations to change.

1) The concept of "proxy" here has no relevance, as these objects
that are being finalized do not "belong" to any one task in the
sense that local objects do.  In general, the attribute objects
will have already been initialized via what you are calling a
"proxy".  Moreover, if another task changes the value of an
attribute, the finalization will be done by the task that changes
the attribute value.  In general, these attributes can be
initialized by any task and finalized by any task.

2) You have no choice but to use another task in the case where the
task was never activated.

Everything I said above applys to the current semantics,
and I can accept leaving things alone since they are not really
broken.  I think no change is called for.

On the other hand, if we are to make a change, I think the
argument is in favor of requiring that finalization be delayed
further, for the reasons stated in my earlier e-mail.

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

From: Randy Brukardt
Sent: Thursday, May 18, 2000 2:51 PM

> I don't see any such gap.  The language currently requires that
> Tasking_Error be raised if the user attempts to access one of
> these attributes of a task that has reached the "terminated"
> state.  I think we all agree that the task is marked as
> "terminated" when it begins the termination process, so that
> during finalization the task is viewed as terminated.

WHOA! (Deja-vu:-) Apparently, your messages aren't the only ones that aren't
being read. I certainly don't agree with the above statement - I believe that
any model where a terminated task can execute is flawed. That is why we have the
"completed" state - it applies to a task which has finished executing but still
has finalization to do.

Which is why I proposed rewriting C.7.2(13) to eliminate the problem. But you
seem to have refused to even comment on it - thus we seem to have two parallel
conversations.

In any case, C.7.2(17) does not say what you stated; if there really is a
consensus that your statement is true, then we need to rewrite C.7.2(17) to say
so (and to provide a red flag that the Ada 'Terminated has to be carried as a
separate flag - it would then have nothing to do with the *real* status of the
task).

> | But certainly your idea is at least as bad as Tucker's: it requires proxy
> | finalizations, which may not be possible on all implementations of
> | finalization. And it certainly would require most
> implementations to change.
>
> 1) The concept of "proxy" here has no relevance, as these objects
> that are being finalized do not "belong" to any one task in the
> sense that local objects do.  In general, the attribute objects
> will have already been initialized via what you are calling a
> "proxy".  Moreover, if another task changes the value of an
> attribute, the finalization will be done by the task that changes
> the attribute value.  In general, these attributes can be
> initialized by any task and finalized by any task.

There is something very wrong with the model you explain here. The lifetime of
the attribute has to be at least as long as the task that it is an attribute of.
However, the task that sets the attribute may have terminated long before the
attribute is finalized; there is no way in general for that task to finalize the
attribute.

The only possible ways to implement these things are either that they "belong"
to the task containing the attribute (possibly requiring a proxy operation), or
that they "belong" to a pseudo-task that surrounds the environment task. In
either case, setting them requires a assigning them so that belong to the
appropriate scope (possibly with some sort of proxy); they cannot remain owned
by the caller.

> 2) You have no choice but to use another task in the case where the
> task was never activated.

And since no such task is available in general, it can only be done at the
appropriate point by launching an extra task to do it. (The task supervisor
itself can't call user code, as that might call back into the task supervisor,
which could deadlock or worse.)

You have convinced me that it is impossible to correctly implement these things
(at least in Janus/Ada). Or, at least that it is unbearably expensive. And all
for a feature of very little benefit (tasks don't terminate very often in real
Ada programs, as they usually are either library level or declared by an access
to task at the library level). (The memory deallocation is not a problem, as it
can occur along with deallocation of other task structures).

The problem, of course, is the use of controlled types as task attributes. The
only solution I see is prohibiting them altogether. I doubt I could get enough
support for that in RM, but an implementation can do it with creative use of
C.7.2(18). I recommend that to all of the implementors.

(For me personally, a better solution would be to burn all of my Ada books and
go bag groceries -- I'd make more money that way...)

				Randy.


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

From: Michael Yoder
Sent: Thursday, May 18, 2000 1:13 PM

At 11:31 AM 5/18/00 -0400, you wrote:
> >    For all of the operations defined in this package, Tasking_Error is
> raised if the
> >    task identified by T is terminated, or the implementation has begun
> >    finalization of the attribute.
>
>Don't we want to allow the implementation to raise T_E if it has started
>finalizing *some* attribute, and some other task accesses some *other*
>attribute?  Otherwise, the implementation has to keep track of which
>attributes it has finalized, individually.  It seems easier to implement
>if it can simply keep track of the fact that it has started finalizing
>the attributes.  It seems like this would not affect programs -- how can
>you write a program that cares about the difference between "we have
>started finalizing attribute X" and "we are about to start finalizing
>attribute X real soon -- as soon as we get done finalizing attribute Y"?
>Such a program would get T_E anyway, if the other task were just a
>little bit slower.

Yes, but an implementation that went down this path wouldn't need the new
flexibility.  (This is equivalent to what Randy called bogus termination
earlier.)  It could rename the property "attribute finalization started" to
"terminated," and rename "terminated" to 'truly and sincerely terminated"
when the RTL internally used the property that all of a task's data
structures were gone.

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

From: Ted Baker
Sent: Thursday, May 18, 2000 4:22 PM

>WHOA!!!  (Isn't anybody reading?)  I mentioned earlier that there
>are situations where this is impossible, i.e., the task whose
>attributes are being finalized never even activated, but we still
>have to finalize the attribute values.

| I cannot find this in your earlier messages.  Could you provide a
| pointer?  If I have missed a message I'd like to read it.

Sorry.  Since I don't see the echo-back copy of the message in my
mail compendium, it may have one of those messages I occasionally
lose when somebody interrupts me and my system goes down before I
finish composing and hit the send key, or maybe it was one of
those cases where I decided I was over-elaborating the point and
decided to delete part of the message before hitting the send key.
Here is the point:

There is a period of time between creation of a task and its
activation, during which the task object exists but there is
no associated active thread of control.  If an exception is
raised in the creator/activator task the newly created task
will never be activated.  However, it may have task attributes
and the attributes still need to be finalized.  This cannot be
done by the task itself, since that task was never activated
and has no thread of control.

Hence, it is absolutely necessary that there be a provision for
what has been (I believe incorrectly, but memorably) called
"proxy" finalization of the attributes.

Given this necessity, there is no benefit to an implemenation in
insisting in other cases that the finalization of attribute values
ever be done by the task with which they are associated.

| 17   When a task terminates, the implementation shall finalize all attributes
| of the task, and reclaim any other storage associated with the attributes.

I think I can speak with some authority on this issue, since the
only reason we have this clause is that I argued for it back when
I was on the 9X MRT.  Tucker and Offer did not want it originally,
until I convinced them that users need this capability to prevent
storage leakage and clean up dangling references.

The word "when" is used in the above clause in the sense it is
commonly used in sentence such "When you finish eating, please
wash the dishes."

The clause does not say the task shall finalize the attributes.
It says "the implementation".  That was intentional, because there
are situations where the task has never started execution, as
mentioned above.

The finalization of attributes is connected in this sentence with
the reclamation of storage.  That is intentional, and is
consistent with the treatment of unchecked deallocation of
objects, which also requires finalization of attributes.

The finalization of the task attributes would normally be done by
whatever thread of control relaims the storage of the task.

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

From: Michael Yoder
Sent: Thursday, May 18, 2000 3:53 PM
To: Ada-Comment List
Subject: Re: [Ada-Comment] finalization of task attributes; value of
Current_Task

Randy Brukardt wrote:

>The only possible ways to implement these things are either that they
>"belong" to the task containing the attribute (possibly requiring a proxy
>operation), or that they "belong" to a pseudo-task that surrounds the
>environment task. In either case, setting them requires a assigning them so
>that belong to the appropriate scope (possibly with some sort of proxy);
>they cannot remain owned by the caller.

Actually, you can have them belong to the environment task itself.  This
seems to raise the question "Who finalizes the environment task's
attributes?".  However, if you examine the process closely, you find that
the attributes get finalized as their scopes are exited, so that when the
time comes to finalize the environment task's attributes after its
termination, the number left to finalize must be zero.  So you escape by a
whisker.

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

From: Ted Baker
Sent: Thursday, May 18, 2000 3:53 PM
To: ada-comment@ada-auth.org
Subject: Re: [Ada-Comment] finalization of task attributes; value of
Current_Task

| Don't we want to allow the implementation to raise T_E if it has started
| finalizing *some* attribute, and some other task accesses some *other*
| attribute?  Otherwise, the implementation has to keep track of which
| attributes it has finalized, individually.

That is what the current semantics say, i.e.,
you mark the task as Terminated at some point, and start finalization
after that point.  The task attribute operations just check
raise Tasking error if T'Terminated is true.
It is all very simple.

WHAT IS THE PROBLEM PEOPLE ARE TRYING TO SOLVE HERE?

This whole thread seems to be talking about making unnecessary
languages changes.  I have not yet seen any problem that requires
a language change.

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

From: Randy Brukardt
Sent: Thursday, May 18, 2000 6:10 PM

Mike Yoder wrote:

> Actually, you can have them belong to the environment task itself.  This
> seems to raise the question "Who finalizes the environment task's
> attributes?".  However, if you examine the process closely, you find that
> the attributes get finalized as their scopes are exited, so that when the
> time comes to finalize the environment task's attributes after its
> termination, the number left to finalize must be zero.  So you escape by a
> whisker.

You are either being unclear here, or one of us completely misunderstands
the model, because the attributes certainly survive their (original) scopes
exiting.
Set_Value clearly is an assignment (including the call to Adjust)
[C.7.2(11)]. The original scope of the item is irrelevant. This assignment
would presumably arrange to have the item in the appropriate scope. (Ted
seems to have this misunderstanding.)

But in that case, the attributes of the environment task certainly still
exist when it terminates - because nothing else could finalize them. Whether
it matters (or whether they simply can be finalized "early"), is an open
question.

In Janus/Ada, at least, the environment task is special (in order that
programs that don't use any tasking can avoid the substantial overhead of
the task supervisor), and when it's finalization is complete, the only
possible thing to do is an immediate exit of the program. It's not practical
to change that.

Doing finalization of these entities is clearly a problem. We're using a
special finalization item tag to do this when the task terminates, but as
Ted points out, that doesn't work for unactivated tasks.

Our task supervisor cannot call user code (it's not reentrant when a context
switch is required, as there is only a single save area); it has to use
another task to finalize things. And forcing a task to finalize something is
a one-way trip: it's not possible to return to what it was previously doing
(because the saved registers, etc, would be killed if it swapped out). So
the only way to handle unactivated tasks would be a spawn a task
specifically to call the finalize.

I find this whole thing quite dubious, because in practice, Ada tasks don't
terminate until the program does. The only time I've seen tasks terminate
before the end of the program is in validation tests and in a couple of test
programs I constructed to make sure that the resources are recovered at that
point. But end users tend to call and complain that the resources (mainly
memory) aren't recovered when the task is completed: which isn't possible in
Ada 95 because the task has to run to execute finalizations. They mistake
completion for termination. That distinction is confusing enough (and that
is why I object to any semantics that implies that terminated tasks can run,
even for a short period). Anyway, when these things are finalized is
unlikely to matter to most programs, simply because all of the tasks
terminate along with the application. Similarly storage leakage of
attributes is nearly irrelevant.

It is interesting to note that the only reason that this package even has
*anything* to do with the task supervisor is C.7.2(17). Otherwise, it is
simple stand-alone library package.

Perhaps something on the line of Ted's idea is right: change C.7.2(17) into
an implementation permission. Then there would be no requirement to finalize
these things at an particular point, and the problems would go away -- they
could be finalized as late as the ending of the application. As it is, the
only viable alternative for Janus/Ada is to completely prohibit the use of
controlled types in Ada.Task_Attributes -- because the work involved in
getting this to work right far exceeds any possible benefit.

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

From: Randy Brukardt
Sent: Thursday, May 18, 2000 6:29 PM

> WHAT IS THE PROBLEM PEOPLE ARE TRYING TO SOLVE HERE?

I think that everybody but you thought it was possible, even expected, for
the task itself to finalize the attributes. Thus all of the discussion about
when the 'Terminated flag.

You are clearly right about that, but I think it is too expensive to force
implementors to do, and this implementor, at least, has no intention of
spending a couple of weeks to redo all of our task supervisor to handle a
case that hardly ever appears in practice. And based on our experience with
environment-level finalization in Claw, compiler writers have a lot more
important things to get right before worrying about this one.

If it was up to me, I'd simply repeal C.7.2(17), since it no longer serves
any real purpose (C.7.2(13) and the generic instantiation rules seem to
prevent all of the problem cases.) But banning controlled types as
attributes works as well. I suspect that any attempt to test this would have
the effect of causing a lot of compilers to do exactly that.

For what it's worth, Janus/Ada has never made any attempt to implement
C.7.2(17), and based on this discussion, its clear it should never try to do
so.

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

From: Tucker Taft
Sent: Thursday, May 18, 2000 5:57 PM

Ted Baker wrote:
> WHAT IS THE PROBLEM PEOPLE ARE TRYING TO SOLVE HERE?

The problem is that the RM is not clear what is the value of 'Terminated
while attribute finalization is occurring.  You think it is clear that
'Terminate is true before finalization starts, and I agree that solves
Mike's problem.  However, Randy indicates that making 'Terminated appear true
before finalization of attributes is finished is a hardship in his compiler.

So one solution is to allow Tasking_Error to be raised either when the
task is terminated, or when it has reached the stage of finalizing task
attributes, whichever comes first.  The other solution is to require
that 'Terminated be true before finalization starts.  I believe Randy
would prefer the first solution.  You seem to believe that the latter
is clearly the intent of the RM, but at least Randy doesn't agree.

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

From: Ted Baker
Sent: Friday, May 19, 2000 5:42 PM
To: ada-comment@ada-auth.org
Subject: Re: [Ada-Comment] finalization of task attributes; value of
Current_Task

I did not get that from his comments, but I don't see leaving this
detail unspecified as being a problem.

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

From: Tucker Taft
Sent: Thursday, May 18, 2000 8:56 PM

Randy Brukardt wrote:
>
> Mike Yoder wrote:
>
> > Actually, you can have them belong to the environment task itself.  This
> > seems to raise the question "Who finalizes the environment task's
> > attributes?".  However, if you examine the process closely, you find that
> > the attributes get finalized as their scopes are exited, so that when the
> > time comes to finalize the environment task's attributes after its
> > termination, the number left to finalize must be zero.  So you escape by a
> > whisker.
>
> You are either being unclear here, or one of us completely misunderstands
> the model, because the attributes certainly survive their (original) scopes
> exiting.
> ...

When the scope of an instantiation of Ada.Task_Attributes ends, it makes sense
to finalize the corresponding attribute in all tasks. This is particularly
important if the instantiation is not library level, because the attribute type
might also be going away soon after the instantiation goes away. So I believe
what Mike is saying is that by the time the environment task terminates, all of
the instantiations of Ada.Task_Attributes have been finalized, and hence there
are no attributes left on it.

It is unfortunate that the RM doesn't talk explicitly about what happens when
an instantiation of Ada.Task_Attributes is finalized.  Our implementation
happens to follow the same approach as Mike suggests, namely finalizing the
attribute in all tasks when the instantiation is finalized, but it is hard to
find a requirement for that in the RM (other than the usual underlying
reasonableness requirement that Robert Dewar mentions now and then ;-).

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

From: Michael Yoder
Sent: Friday, May 19, 2000 10:39 AM

Ted Baker wrote:
>WHAT IS THE PROBLEM PEOPLE ARE TRYING TO SOLVE HERE?

C.7.2(17) says "When a task terminates,...".  This is ambiguous; if it had
said "After a task terminates" there would be no ambiguity.  I phrased my
original query conditionally exactly because I *feared* the ambiguity was
intentional, and *hoped* that pointing out the consequences would lead to
tightening the language (or interpreting it tightly).

Here is a trial balloon.  Randy could clearly use C.7.2(29) to restrict
attributes to those too small to contain controlled components or task
components.  It seems reasonable that any restriction looser than that
should be permitted while still claiming to implement Annex C.  So, for
example, he could say that his implementation forbids attributes requiring
non-null finalization.  Then there would be no obstacle to taking the
strict interpretation, unless there are others here with lurking
objections, as it were.

My preference would be to change the word "when" to "after" in C.7.2(17).

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

From: Ted Baker
Sent: Friday, May 19, 2000 5:54 PM

| C.7.2(17) says "When a task terminates,...".  This is ambiguous; if it had
| said "After a task terminates" there would be no ambiguity.  I phrased my
| original query conditionally exactly because I *feared* the ambiguity was
| intentional, and *hoped* that pointing out the consequences would lead to
| tightening the language (or interpreting it tightly).

In my recollection, the ambiguity was intentional, and I think it
is useful.

| Here is a trial balloon.  Randy could clearly use C.7.2(29) to restrict
| attributes to those too small to contain controlled components or task
| components.  It seems reasonable that any restriction looser than that
| should be permitted while still claiming to implement Annex C.  So, for
| example, he could say that his implementation forbids attributes requiring
| non-null finalization.  Then there would be no obstacle to taking the
| strict interpretation, unless there are others here with lurking
| objections, as it were.

This is a reasonable approach.

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

From: Michael Yoder
Sent: Friday, May 19, 2000 9:33 AM

Randy Brukardt wrote:
>Mike Yoder wrote:
>
> > Actually, you can have them belong to the environment task itself.  This
> > seems to raise the question "Who finalizes the environment task's
> > attributes?".  However, if you examine the process closely, you find that
> > the attributes get finalized as their scopes are exited, so that when the
> > time comes to finalize the environment task's attributes after its
> > termination, the number left to finalize must be zero.  So you escape by a
> > whisker.
>
>You are either being unclear here, or one of us completely misunderstands
>the model, because the attributes certainly survive their (original) scopes
>exiting.

You are right that I misunderstand the model if this is true, and upon
reading C.7.2 I find no support for my belief, which dismays me.  My belief
comes from this paragraph of section C.6.2 of the Ada 95 Rationale:

"The generic package Task_Attributes can be instantiated locally in a scope
deeper than the library level.  The effect of such an instantiation is to
define a new attribute (for all tasks) for the lifetime of that
scope.  When the scope is left, the corresponding attribute no longer
exists and cannot be referenced anymore.  An implementation may therefore
deallocate all such attribute objects when the scope is left."

Such deallocation would presumably require that finalization be done first.

Failing to allow this (indeed, failing to *require* this) would have very
serious consequences: you could create objects whose finalization used
variables and types that no longer existed, for example.

This is certainly a turn of affairs I didn't anticipate.  :-)  I confess I
took the above paragraph on faith without looking for explicit support in
the LRM.

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

From: Ted Baker
Sent: Friday, May 19, 2000 5:56 PM

I believe it was intended that when the scope of an instantiation
of Task_Attributes is left, the attribute values be finalized and
the associated storage recovered.  That is how we implemented it in
GNARL.

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

From: Randy Brukardt
Sent: Friday, May 19, 2000 1:32 PM

Well, I doubt that anyone would seriously argue that we don't want to require
finalization at this point. So, I think we need at add something like
   "When the master of an instantiation of Ada.Task_Attributes is finalized,
the associated attribute for all tasks is finalized."
after C.7.2(13).

This has the advantage of making it clear what the master for task attribute
objects is, which makes the semantics much more deterministic. (The master
matters, of course, for types with controlled subcomponents).

I would argue that adding this rule makes C.7.2(17) unnecessary, so I would
suggest turning it into an implementation permission (so that existing
implementations would not have to change).
   "When a task terminates, an implementation may finalize all attributes of
the task, and reclaim any other storage associated with the attributes."

The second change would eliminate all of my objections/problems, and would have
very little effect on real programs (since tasks rarely terminate before the
entire program).

The need to spawn a task to finalize attributes when a task terminates is far to
heavyweight for a feature that will be rarely used (that is, the combination of
controlled task attributes and tasks that actually terminate). I don't think
that the expense to every tasking program (in size, at least) and especially to
every task that uses task attributes (even of none of them are controlled) is
justified.

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

From: Robert A Duff
Sent: Friday, May 19, 2000 1:13 PM

J-P says:

> (Note however that there are other places in the language where you can
> access a variable after it has been finalized, but that would be
> unfortunate in this case, since it would mean accessing released
> memory).

Yes, there are other places in the language where you can reference
finalized objects.  However, there is no place in the language where a
task can reference an object that is simultaneously being finalized by a
different task.  At least, there *should* be no such place, which was
Mike's original point.

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

From: Robert A Duff
Sent: Friday, May 19, 2000 12:52 PM

Mike Yoder says:

> You are right that I misunderstand the model if this is true, and upon
> reading C.6.7 I find no support for my belief, which dismays me.  My belief
> comes from this paragraph of section C.6.2 of the Ada 95 Rationale:
>
> "The generic package Task_Attributes can be instantiated locally in a scope
> deeper than the library level.  The effect of such an instantiation is to
> define a new attribute (for all tasks) for the lifetime of that
> scope.  When the scope is left, the corresponding attribute no longer
> exists and cannot be referenced anymore.  An implementation may therefore
> deallocate all such attribute objects when the scope is left."
>
> Such deallocation would presumably require that finalization be done first.
>
> Failing to allow this (indeed, failing to *require* this) would have very
> serious consequences: you could create objects whose finalization used
> variables and types that no longer existed, for example.

Yes, that does seem like a hole.

So are we saying that an attribute can be finalized at any time after
'Terminated becomes true, and before the instantiation goes away?  In
particular, for a library-level instantiation, all task attributes can
be finalized just before the program is done.  In fact, this implies
that an implementation that does the finalization *only* when the
instantiation is finalized is correct -- the implementation can
completely ignore task termination, and just let the attributes stay
around until much later.

If "when" means "after", then it could be "long after".

That implementation would seem to make Randy happy.  True?

Is this what you and Ted believe the rules should be (or what the rules
already are, in Ted's case)?

- Bob

P.S. Our implementation has some problems in this area.  I'm waiting for
this discussion to settle down before I fix them!

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

From: Michael Yoder
Sent: Friday, May 19, 2000 11:34 AM

I wrote:
...  Randy could clearly use C.7.2(29) to restrict attributes to those too
small to contain controlled components or task components.

Dummy!  Task attributes can't be limited, so task components can't occur here.

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

From: Ted Baker
Sent: Friday, May 19, 2000 1:31 PM

| I agree that accessing the attribute after finalization has
| started should raise Tasking_Error, which is a bit earlier than
| when the task is terminated.

No.  The above remark implies that termination is an instantaneous
transition.  The task needs to marked as Terminated before the
finalization of attributes begins.  --Ted

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

From: Ted Baker
Sent: Friday, May 19, 2000 1:34 PM

| ... and rename "terminated" to 'truly and sincerely terminated"
| when the RTL internally used the property that all of a task's data
| structures were gone.

No.  If you did this there would be no place where T'Terminated
could ever return False.  That is because the earliest point you
can delete the last of the task's data structures is when there
can be no further reference to the task.

Moreover, if you did this change I believe it would break lots of
applications and guess it would break quite a few validation
tests, since I recall quite a few of them using T'Terminated at
points and expecting it to return False.

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

From: Michael Yoder
Sent: Friday, May 19, 2000 2:16 PM
To: Ada-Comment List
Subject: Re: [Ada-Comment] finalization of task attributes; value of
Current_Task

You misunderstand what I was saying.  What I said had bearing only on
implementations that wanted to take advantage of the change being discussed
which would allow raising Tasking_Error when an attribute's finalization
started, this finalization being started *before* the task became terminated.

Bob's suggestion was that this exception might be permitted when *any*
attribute had started finalization.  My point was: if the implementation
was recording this point in time for the sake of the attributes package, it
could simply redefine when 'Terminated became true to be identical with
that point in time.  If the RTS had previously been using the property that
termination implied all data structures were gone, it could rename its old
"terminated" property to be something else (e.g. finalized, or fully
terminated, or whatever) when it needed this stronger property to hold for
the sake of its internal algorithms.

The point, then, was that such an implementation would not need the
additional implementation flexibility, since it could by a simple
transformation comply with the stricter requirement that 'Terminated be
true before attribute finalization started.

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

From: Michael Yoder
Sent: Friday, May 19, 2000 3:25 PM

Randy Brukardt wrote:
>The need to spawn a task to finalize attributes when a task terminates is
>far to heavyweight for a feature that will be rarely used (that is, the
>combination of controlled task attributes and tasks that actually
>terminate). I don't think that the expense to every tasking program (in
>size, at least) and especially to every task that uses task attributes (even
>of none of them are controlled) is justified.

I think you need only one global task to get early attribute finalization
(in your implementation).  I could tolerate the overhead of one task for
the sake of having task attributes, but you might judge differently.

I like the suggestion you and Bob have independently proposed.

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

From: Ted Baker
Sent: Friday, May 19, 2000 5:27 PM

| ... any model where a terminated task can execute is flawed.

You should have objected more strongly during the Ada 9X processs,
then.  This is not something new.  It is a change that has been
there in the language definition all along.

| That is why we have the "completed" state - it applies to a task
| which has finished executing but still has finalization to do.

There are other reasons for Completed, including waiting for
dependent tasks to terminate.  Your comment about finalization
only applies to finalization of objects declared within the task.

| Which is why I proposed rewriting C.7.2(13) to eliminate the problem. But
| you seem to have refused to even comment on it - thus we seem to have two
| parallel conversations.

Sorry.  I saw that and did not comment on the specifics because I
am completely oppoesed to making any change.  There is no need for
change, and this is a case where change breaks implementations and
user programs.  Hence.

| In any case, C.7.2(17) does not say what you stated; if there really is a
| consensus that your statement is true, then we need to rewrite C.7.2(17) to
| say so (and to provide a red flag that the Ada 'Terminated has to be carried
| as a separate flag - it would then have nothing to do with the *real* status
| of the task).

No. C.7.2(17) does say what I stated.

| 17 When a task terminates, the implementation shall finalize all
| attributes of the task, and reclaim any other storage associated
| with the attributes.

Interpreting this as ambiguously as it was intended, i.e., to
cover the range of meanings from "when a person finishes eating
the person shall wash up the dishes" through "when a person eats
the person shall not talk with his mouth full", this means that
finalization should be done some time during or after termination.

Interpreting this as ambiguously as it was intended, the implementation
may cause the task itself to do the finalization, or do it via some
other thread of control, as appropriate.

Interpreting this in the context of stroage reclamation, as it was
intended, the finalization of attributes should be done as part
of the deallocation of the storage associated with the task
implementation.

| There is something very wrong with the model you explain here. The lifetime
| of the attribute has to be at least as long as the task that it is an
| attribute of. However, the task that sets the attribute may have terminated
| long before the attribute is finalized; there is no way in general for that
| task to finalize the attribute.

I did not say the task that created the attribute needs to
finalize it.  I just argued that there is no need for a special
connection between a given task and who finalizes the attributes
associated with the given task for the last time.

| The only possible ways to implement these things are either that they
| "belong" to the task containing the attribute (possibly requiring a proxy
| operation), or that they "belong" to a pseudo-task that surrounds the
| environment task. In either case, setting them requires a assigning them so
| that belong to the appropriate scope (possibly with some sort of proxy);
| they cannot remain owned by the caller.

There is no need for the attributes to be "owned" by any
particular task.

The usual concept of "scope" does not apply to task attributes in
the sense of objects that are declared within a master.  The
storage for an attribute value may be allocated (and initialized)
when (a) an instance of the Task_Attributes package is elaborated
at run time -- at which point the elaboration of the package
creates default attribute values for all existing tasks, (b) a new
task is created -- at which point the creation of the task creates
defacult values for the existing attributes of the task, (c) a
call to Set_Value or Reinitialize changes the value from the
default to a non-default value (if the implementation chooses to
optimize the default values in a way that eliminates the need for
storage until a nondefault value is assigned).

If you need to think in terms of scope, the scope of the
task attributes is the same as that of the "task control block"
object in the Ada runtime system.

| > 2) You have no choice but to use another task in the case where the
| > task was never activated.

| And since no such task is available in general, it can only be done at the
| appropriate point by launching an extra task to do it. (The task supervisor
| itself can't call user code, as that might call back into the task
| supervisor, which could deadlock or worse.)

Well.... you have hit a tender spot.  (By the way, what exactly is
the "task supervisor"?  We don't have one in GNARL.)  The notion
of finalization is already inherently risky, given that it can
take place after a task has been aborted, and during finalization
abort is deferred.  This means that if a finalizer gets stuck in
a loop or such, there is no way to kill the task.  This problem was
known from the beginning, and it was accepted that finalizers are
critical code, that must be very tightly verified and kept simple.
Finalization of a task attribute may be a tiny bit riskier, if there
is more than one task who can do it, since there must be some kind of
lock that prevents concurrent finalizations of the same object, and
that lock could cause a deadlock if the finalizer runs amok.
Does this seem bad?  I don't see it as any worse than any other
way a program can run amok, since all Ada tasks are in the same
logical address space (due to stack and pointer sharing), and so
may easily trash both each other's states and that of the Ada
runtime system if they run badly amok.

| You have convinced me that it is impossible to correctly implement these
| things (at least in Janus/Ada). Or, at least that it is unbearably
| expensive. And all for a feature of very little benefit (tasks don't
| terminate very often in real Ada programs, as they usually are either
| library level or declared by an access to task at the library level). (The
| memory deallocation is not a problem, as it can occur along with
| deallocation of other task structures).

| The problem, of course, is the use of controlled types as task attributes.
| The only solution I see is prohibiting them altogether. I doubt I could get
| enough support for that in RM, but an implementation can do it with creative
| use of C.7.2(18). I recommend that to all of the implementors.

I do agree that allowing task attributes of controlled types turned
out to be more costly and riskier than I had expected when it went into
Ada 9X.  At this point I would not personally object to a langauge
change that dropped this feature completely, but I expect there would
be users who would object.  Therefore, I think the best solution is
to leave it as is, and don't tighten the semantics or validation
tests.  Any such tightening would just hurt implementors, and
by extension users.

| (For me personally, a better solution would be to burn all of my Ada books
| and go bag groceries -- I'd make more money that way...)

That is too painful.

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

From: Ted Baker
Sent: Friday, May 19, 2000 5:39 PM

| Our task supervisor cannot call user code (it's not reentrant when a context
| switch is required, as there is only a single save area); it has to use
| another task to finalize things. And forcing a task to finalize something is
| a one-way trip: it's not possible to return to what it was previously doing
| (because the saved registers, etc, would be killed if it swapped out). So
| the only way to handle unactivated tasks would be a spawn a task
| specifically to call the finalize.

In GNARL the whole runtime system is layered over a thread
implementation, and so if there is anything like a "supervisor" it
is in the thread layer.  The finalization of task attributes is
done by the master of the task when it leaves the scope of the
task or task access types declaration, or by the task that does an
unchecked deallocation (if any) on the task object.

I agree that this call-out to execute the finalizers makes me feel
as if walking on very thin ice, since the call is made with the
runtime system lock of the task held locked.  A bad finalizer
could deadlock.

| I find this whole thing quite dubious, because in practice, Ada tasks don't
| terminate until the program does. The only time I've seen tasks terminate
| before the end of the program is in validation tests and in a couple of test
| programs I constructed to make sure that the resources are recovered at that
| point. But end users tend to call and complain that the resources (mainly
| memory) aren't recovered when the task is completed: which isn't possible in
| Ada 95 because the task has to run to execute finalizations. They mistake
| completion for termination. That distinction is confusing enough (and that
| is why I object to any semantics that implies that terminated tasks can run,
| even for a short period). Anyway, when these things are finalized is
| unlikely to matter to most programs, simply because all of the tasks
| terminate along with the application. Similarly storage leakage of
| attributes is nearly irrelevant.

| It is interesting to note that the only reason that this package even has
| *anything* to do with the task supervisor is C.7.2(17). Otherwise, it is
| simple stand-alone library package.

Right.  The hook back into the tasking runtime system is very
awkward.

| Perhaps something on the line of Ted's idea is right: change C.7.2(17) into
| an implementation permission. Then there would be no requirement to finalize
| these things at an particular point, and the problems would go away -- they
| could be finalized as late as the ending of the application. As it is, the
| only viable alternative for Janus/Ada is to completely prohibit the use of
| controlled types in Ada.Task_Attributes -- because the work involved in
| getting this to work right far exceeds any possible benefit.

I would not object to that resolution.

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

From: Ted Baker
Sent: Friday, May 19, 2000 5:49 PM

| It is unfortunate that the RM doesn't talk explicitly about what
| happens when an instantiation of Ada.Task_Attributes is
| finalized.  Our implementation happens to follow the same
| approach as Mike suggests, namely finalizing the attribute in
| all tasks when the instantiation is finalized, but it is hard to
| find a requirement for that in the RM (other than the usual
| underlying reasonableness requirement that Robert Dewar mentions
| now and then ;-).

GNARL also finalizes all the instances of a given attribute when
the scope of the package instance is left.  This is the only
sensible thing to do.

My own feeling at this point in the disucssion is that an
implementation might do well to finagle an excuse to omit support
for task attributes of a controlled type.  The only serious loss
is the ability to stop storage leakage.  It would remove what may
be a too-tempting "hook" for users to hang overly complex task
finalization code, that could end up being very unreliable.

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

From: Ted Baker
Sent: Friday, May 19, 2000 6:07 PM

| Well, I doubt that anyone would seriously argue that we don't want to
| require finalization at this point. So, I think we need at add something
| like
|    "When the master of an instantiation of Ada.Task_Attributes is finalized,
| the associated attribute for all tasks is finalized."
| after C.7.2(13).

| This has the advantage of making it clear what the master for task attribute
| objects is, which makes the semantics much more deterministic. (The master
| matters, of course, for types with controlled subcomponents).

| I would argue that adding this rule makes C.7.2(17) unnecessary, so I would
| suggest turning it into an implementation permission (so that existing
| implementations would not have to change).
|    "When a task terminates, an implementation may finalize all attributes of
| the task, and reclaim any other storage associated with the attributes."

| The second change would eliminate all of my objections/problems, and would
| have very little effect on real programs (since tasks rarely terminate
| before the entire program).

| The need to spawn a task to finalize attributes when a task terminates is
| far to heavyweight for a feature that will be rarely used (that is, the
| combination of controlled task attributes and tasks that actually
| terminate). I don't think that the expense to every tasking program (in
| size, at least) and especially to every task that uses task attributes (even
| of none of them are controlled) is justified.

I would not object to this change, since it seems to be neutral or
friendly to both vendors and users.

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

From: Tucker Taft
Sent: Thursday, June 01, 2000 8:28 AM

Randy Brukardt wrote:
>
> Here is the writeup for AI-237, based on the conclusions of the discussion
> on Ada comment. (I've omitted the lengthy E-Mail discussion from this mail;
> please download the AI from the web site (www.ada-auth.org/~acats/arg) if
> you're interested.)
>
>                         Randy.

This looks pretty good to me.  My only complaint is that we are still
somewhat ambiguous in the proposed wording that finalization may only
happen *after* the task terminates.  Just saying it may occur "when" the task
terminates might be misconstrued, in the same way the current wording
has been misconstrued.

-Tuck
--
-Tucker Taft   stt@averstar.com   http://www.averstar.com/~stt/
Technical Director, Commercial Division, AverStar (formerly Intermetrics)
(http://www.averstar.com/services/IT_consulting.html)  Burlington, MA  USA
*************************************************************

From: Randy Brukardt
Sent: Thursday, June 01, 2000 12:12 PM

Tuck said:

> This looks pretty good to me.  My only complaint is that we are still
> somewhat ambiguous in the proposed wording that finalization may only
> happen *after* the task terminates.  Just saying it may occur "when" the
> task terminates might be misconstrued, in the same way the current
> wording has been misconstrued.

You are correct here. I meant to fix that; I changed the wording of the
permission to "After the task terminates, ...". I'm not sure that reads well,
but it was easy. :-)

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

From: Randy Brukardt (Editor)

The following points were raised at the November 2000 ARG meeting:

  It is possible to have a memory leak if you don't finalize attribute when
  the task is terminated.

  It is possible that the instantiation to go away at the same time that a task
  is going away. Thus, two threads could try to finalize the same object at the
  time. An implementation must prevent this.

  The current task is undefined in the finalization (it might be a terminated
  task).

These points were added to the discussion, and the use oc Current_Task during
the finalization of a task attribute was made into a bounded error.

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


Questions? Ask the ACAA Technical Agent