!standard C.7.1 (03) 99-08-31 AI95-00101/05 !class binding interpretation 95-10-12 !status Corrigendum 2000 99-05-25 !status WG9 approved 95-06-14 !status ARG approved 11-0-0 (by letter ballot) 96-06-05 !status ARG approved (subject to letter ballot) 9-0-1 95-11-01 !status received 95-10-12 !qualifier Error !subject Abort_Task has a parameter of mode 'in'. !summary Task_Identification.Abort_Task takes a parameter of mode 'in': procedure Abort_Task (T : Task_Id); !question C.7.1(3) shows procedure Abort_Task taking a parameter of mode 'in out'. Is this correct? (No.) !recommendation (See summary.) !wording (See summary.) !discussion Abort_Task does not modify its parameter, which is a Task_ID. Therefore, its parameter should be of mode 'in'. Furthermore, if the parameter is of mode 'in out', then one cannot pass a function call or a constant. For example, Abort_Task(Current_Task) should be allowed. For another example, the following ought to be allowed: type Task_ID_Array is array (Natural range <>) of Task_ID; procedure Abort_Some_Tasks(Tasks: Task_ID_Array) is begin for I in Tasks'Range loop Abort_Task(Tasks(I)); end loop; end Abort_Some_Tasks; ... Abort_Some_Tasks((This_Task_ID, That_Task_ID, The_Other_Task_ID)); Hence, this parameter should be of mode 'in'. Note that Abort_Task is not analogous to Unchecked_Deallocation. After a call to an instance of Unchecked_Deallocation, the designated object ceases to exist, and any reference to it would be erroneous; therefore it makes sense for Unchecked_Deallocation to set the access object to null. However, after a call to Abort_Task, the task object continues to exist, and the task might even keep running for a while. Therefore, it does not make sense for Abort_Task to set its parameter to Null_Task_ID. Note that it is harmless to abort the same task twice -- either with an abort_statement, or with Abort_Task. !corrigendum C.07.01(03) @dprepl @xcode<@b Abort_Task (T : @b Task_Id);> @dby @xcode<@b Abort_Task (T : Task_Id);> !ACATS test A C-Test is needed to check that calls to Abort_Task work even for functions or constants as parameters. !appendix !section C.7.1(03) !subject Why does Abort_Task have an in out parameter? !reference RM95-C.7.1(3);6.0 !from Norman Cohen 95-09-06 !reference as: 95-5325.a Robert A Duff 95-10-11>> !discussion Ada.Task_Identification.Abort_Task takes a single parameter, of type Task_ID. The parameter is of mode in out rather than in, even though the semantics of Abort_Task given in C.7.1(9) do not indicate that the procedure alters its parameter. As Keith Thompson pointed out to me, this makes the call Abort_Task(Current_Task) illegal, so the in out mode does no good and a small amount of harm. It ought to be changed to mode in by a binding interpretation. (If this were still the language-design stage, I would also suggest giving the parameter the default-value expression Current_Task.) **************************************************************** !section C.7.1(03) !subject Why does Abort_Task have an in out parameter? !reference RM95-C.7.1(3);6.0 !reference Norman Cohen 95-09-06 !reference 95-5325.a Robert A Duff 95-10-11 !from Offer pazy 95-10-12 !reference as: 95-5331.a Offer Pazy 95-10-12>> !discussion Norm cohen writes: > Ada.Task_Identification.Abort_Task takes a single parameter, of type > Task_ID. The parameter is of mode in out rather than in, even though > the semantics of Abort_Task given in C.7.1(9) do not indicate that the > procedure alters its parameter. > > As Keith Thompson pointed out to me, this makes the call > Abort_Task(Current_Task) illegal, so the in out mode does no good and a > small amount of harm. It ought to be changed to mode in by a binding > interpretation. > (If this were still the language-design stage, I would > also suggest giving the parameter the default-value expression > Current_Task.) This is clearly a bug, but I'd rather have the semantics of the parameter upon return changed (to its original, mistakenly dropped, intent) as opposed to making it an IN only parameter. The parameter should be Null_Task_Id upon return to prevent the object from being used again for other operations requiring Task_Id. This is similar to other destroy/free operations and seems to be the desired semantics. It is true that in this way, one cannot call it directly for the result of Current_Task, but I don't think that this is often the need (I definitely would not recommed having teh default be Current_Task, a bug here will get totally undetected which would be unfriendly. Aborting a task should not be "easy", you should be required to specify which task you want to abort, even if it costs you typing several more characters :-). When aborting self is needed, one can use a local variable to store the Task_Id value od self. Offer Pazy 31 Robinwood Ave. Boston, MA 02130 USA (617)522-5988 pazy@world.std.com **************************************************************** !section C.7.1(03) !subject Why does Abort_Task have an in out parameter? !reference RM95-C.7.1(3);6.0 !reference 95-5325.a Robert A Duff 95-10-11 !from Ted Baker 95-09-12 !reference as: 95-5332.a Ted Baker 95-10-12>> !discussion I can't think of any good reason for the task ID parameter of Abort_Task to be "in out". In fact, I never noticed it. I suspect this was a typo, introduced somewhere along the way. It should be scheduled to be changed, in the first set of technical corrigenda. Such a change should be upward-compatible from a user's point of view.  **************************************************************** !section C.7.1(03) !subject Why does Abort_Task have an in out parameter? !reference RM95-C.7.1(3);6.0 !reference Norman Cohen 95-09-06 !reference 95-5325.a Robert A Duff 95-10-11 !reference 95-5331.a Offer Pazy 95-10-12 !from Ted Baker 95-10-13 !reference 95-5339.a Ted Baker 95-10-13>> !discussion Offer Pazy writes: | ... I'd rather have the semantics of the parameter | upon return changed (to its original, mistakenly dropped, intent) as opposed | to making it an IN only parameter. The parameter should be Null_Task_Id | upon return to prevent the object from being used again for other operations | requiring Task_Id. This is similar to other destroy/free operations and | seems to be the desired semantics. The situation is not exactly analogous to unchecked deallocation. The task may continue to execute, and then to exist, for some time after it is aborted, so we may still meaningfully reference the corresponding ID. --Ted **************************************************************** !section C.7.1(03) !subject Why does Abort_Task have an in out parameter? !reference RM95-C.7.1(3);6.0 !reference Norman Cohen 95-09-06 !reference 95-5325.a Robert A Duff 95-10-11 !reference 95-5331.a Offer Pazy 95-10-12 !reference 95-5339.a Ted Baker 95-10-13 !from Robert I. Eachus 95-10-16 !reference 95-5343.a Robert I. Eachus 95-10-16>> !discussion Ted Baker said: > The situation is not exactly analogous to unchecked deallocation. > The task may continue to execute, and then to exist, for some time > after it is aborted, so we may still meaningfully reference the > corresponding ID. Really? RM 9.8(1): "An abort_statement causes one or more tasks to become abnormal, thus preventing any further interaction with such tasks." RM95 C.7.1(9): "The effect of Abort_Task is the same as the abort_statement for the task identified by T." RM95 C.7.1(18): "If a value of Task_ID is passed as a parameter to any of the operations declared in this package (or any language defined child of this package), and the corresponding task object no longer exists, the execution of the program is erroneous." (Hmmm... This reads a lot harsher than intended. My point is that any attempt to reference a task after it is aborted is either futile or fraught with danger. A program designed knowing the specifics of the implementation may be able to do something meaningful, but it is extremely implementation dependent.) Robert I. Eachus with Standard_Disclaimer; use Standard_Disclaimer; function Message (Text: in Clever_Ideas) return Better_Ideas is... **************************************************************** !section C.7.1(03) !subject Why does Abort_Task have an in out parameter? !reference RM95-C.7.1(3);6.0 !reference Norman Cohen 95-09-06 !reference 95-5325.a Robert A Duff 95-10-11 !reference 95-5331.a Offer Pazy 95-10-12 !reference 95-5339.a Ted Baker 95-10-13 !from Ted Baker 95-10-16 !reference 95-5344.a Ted Baker 95-10-16>> !discussion I said: > The situation is not exactly analogous to unchecked deallocation. > The task may continue to execute, and then to exist, for some time > after it is aborted, so we may still meaningfully reference the > corresponding ID. | Robert Eachus asked: | Really? Yes, REALLY. | RM 9.8(1): "An abort_statement causes one or more tasks to become | abnormal, thus preventing any further interaction with such tasks." That text is part of the introduction, carried over almost unchanged from Ada'83. It was probably an editorial mistake to replace to simply replace "rendezvous" by "interaction", which is less well defined. However, in any case, there are meaningful ways to refer to a task via it's ID that do not involve interaction. | RM95 C.7.1(9): "The effect of Abort_Task is the same as the | abort_statement for the task identified by T." Fine. | RM95 C.7.1(18): "If a value of Task_ID is passed as a parameter to | any of the operations declared in this package (or any language | defined child of this package), and the corresponding task object no ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | longer exists, the execution of the program is erroneous." ^^^^^^^^^^^^^ Note that the task object may continue to exist (and the task to execute) after the task is aborted, for an abitrarily long time. Moreover, it is possible to write programs in a way that guarantees the the task will continue to exist. | (Hmmm... This reads a lot harsher than intended. My point is that | any attempt to reference a task after it is aborted is either futile | or fraught with danger. A program designed knowing the specifics of | the implementation may be able to do something meaningful, but it is | extremely implementation dependent.) No. It does not rely on anything special about the implementation. In fact, the situation is not much different than in Ada'83, since we already had the 'Terminated attribute then, which could meaningfully be called to check up on how an aborted task is coming along. In Ada'95 we also have Is_Terminated. Moreover, if we know the task has not yet terminated, we can use values of task-specific attributes. --Ted Baker **************************************************************** !section C.7.1(03) !subject Why does Abort_Task have an in out parameter? !reference RM95-C.7.1(3);6.0 !reference 95-5325.a Robert A Duff 95-10-11 !reference 95-5331.a Offer Pazy 95-10-12 !reference 95-5339.a Ted Baker 95-10-13 !reference 95-5343.a Robert I. Eachus 95-10-16 !reference 95-5344.a Ted Baker 95-10-16 !reference 95-5345.a Robert I. Eachus 95-10-16>> !discussion (Let me say it up front this time. The furious sound of the debate should not be allowed to conceal the fact that Ted's position is very close to mine. But in this forum, we can't blithely decide to accept some parts of the RM and not others. If it is broken, we need to fix it. Personally I don't think the RM is broken, but the ice is awful thin.) | RM 9.8(1): "An abort_statement causes one or more tasks to become | abnormal, thus preventing any further interaction with such tasks." Ted said: > That text is part of the introduction, carried over almost > unchanged from Ada'83. It was probably an editorial mistake to > replace to simply replace "rendezvous" by "interaction", which is > less well defined. However, in any case, there are meaningful > ways to refer to a task via it's ID that do not involve > interaction. Either, it's right, it's a note, or we need a binding interpretation. I think it is correct. Any action which requires interaction--some action as well by the aborted task--is no longer possible. And I agree, that there are some meaningful inquiries which do not require interaction. | RM95 C.7.1(9): "The effect of Abort_Task is the same as the | abort_statement for the task identified by T." > Fine. Agreed. ;-) | RM95 C.7.1(18): "If a value of Task_ID is passed as a parameter to | any of the operations declared in this package (or any language | defined child of this package), and the corresponding task object no ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | longer exists, the execution of the program is erroneous." ^^^^^^^^^^^^^ > Note that the task object may continue to exist (and the task to > execute) after the task is aborted, for an abitrarily long time. Agreed. > Moreover, it is possible to write programs in a way that > guarantees the the task will continue to exist. Definitely not portably. (Hmmm. Not quite true. You can abort the task that call you inside a rendezvous, and continue to refer to that task until the rendezvous is left. Is there a meaningful use for this?) > No. It does not rely on anything special about the implementation. Yes, it does. It requires an implementation where the name of an aborted task remains valid after the abort. You may not be able to conceive of such an implementation, but I can, and the cost of keeping the name alive would be high. (Basically an implementation where tasks have their own address spaces, and accesses are provided by capabilities. Since the a tasks may be on different processors, there should be no requirement to wait before flushing the capability for an aborted task.) > In fact, the situation is not much different than in Ada'83, since > we already had the 'Terminated attribute then, which could > meaningfully be called to check up on how an aborted task is > coming along. In Ada'95 we also have Is_Terminated. You make my point better than you could imagine. Requiring 'TERMINATED to work outside the tasks master was one of the biggest mistakes the ARG made. (Corrected later, but it did a lot of damage.) Let's not repeat history. > Moreover, if we know the task has not yet terminated, we can use > values of task-specific attributes. Didn't I say risky? Since the task may terminate at any point where it is not in an abort protected region. (And any aborted task cannot BE in an abort protected region--think about it.) So the task can and will go away under you--unless you know a lot of implementation details. Robert I. Eachus with Standard_Disclaimer; use Standard_Disclaimer; function Message (Text: in Clever_Ideas) return Better_Ideas is... **************************************************************** !section C.7.1(03) !subject Why does Abort_Task have an in out parameter? !reference RM95-C.7.1(3);6.0 !reference 95-5325.a Robert A Duff 95-10-11 !reference 95-5331.a Offer Pazy 95-10-12 !reference 95-5339.a Ted Baker 95-10-13 !reference 95-5343.a Robert I. Eachus 95-10-16 !reference 95-5344.a Ted Baker 95-10-16 !from Ted Baker 95-10-16 !reference 95-5346.a Ted Baker 95-10-16>> !discussion It seems we may be wasting words over some confusion between the meanings of abort, terminate, and exist. 1) Task abortion does not imply immediate termination. 2) Task termination does not imply the task necessarily is allowed to immediately cease to exist, or that no further reference to it is allowed. | RM 9.8(1): "An abort_statement causes one or more tasks to become | abnormal, thus preventing any further interaction with such tasks." I don't believe the term "interaction" is formally defined. Clearly, rendezvous and requeuing on entries of the task are ruled out. I don't think it is worth pushing the envelope further at this time, since it does not affect the outcome present question. I said it is possible to write programs in a way that guarantees a task will continue to exist up to some defined point after it is aborted. Robert said (but then withdrew the statement on the same line): | Definitely not portably. (Hmmm. Not quite true. You can abort | the task that call you inside a rendezvous, and continue to refer to | that task until the rendezvous is left. Is there a meaningful use for | this?) Yes, there are several ways of doing this portably. Abort deferral during protected actions and during finalization provide plenty of opportunity. I said that this does not rely on anything implementation-dependent. Robert said: | Yes, it does. It requires an implementation where the name of an | aborted task remains valid after the abort. You may not be able to | conceive of such an implementation, but I can, and the cost of keeping | the name alive would be high. (Basically an implementation where | tasks have their own address spaces, and accesses are provided by | capabilities. Since the a tasks may be on different processors, there | should be no requirement to wait before flushing the capability for an | aborted task.) All this is required of the implementation by the Ada standard. Reference to the task ID value remains valid until the task no longer exists. It must continue to exist until either the scope of the task object is left, or the task object is unchecked-deallocated. Robert said: | ... requiring 'TERMINATED to work outside the tasks master was one | of the biggest mistakes the ARG made. (Corrected later, but it | did a lot of damage.) Let's not repeat history. Inside or outside the task's master is not an issue here. A task may be meaningfully referenced, either by name or via task ID value, within its own master, after the task has been aborted. --Ted Baker **************************************************************** !section C.7.1(03) !subject Why does Abort_Task have an in out parameter? !reference RM95-C.7.1(3);6.0 !reference 95-5325.a Robert A Duff 95-10-11 !reference 95-5331.a Offer Pazy 95-10-12 !reference 95-5339.a Ted Baker 95-10-13 !reference 95-5343.a Robert I. Eachus 95-10-16 !reference 95-5344.a Ted Baker 95-10-16 !from Offer Pazy 95-10-16 !reference 95-5347.a Offer Pazy 95-10-16>> !discussion I still like the idea of Abort_Task returning Null_Task_Id, but the arguments presented by Ted are completely correct, so maybe the right solution is changing the formal to "in". There are many (legitimate and intentional) way to interact with an abnormal task (as Ted pointed out). The "interaction" word at the introduction is totally non-normative. Of course you can, even fo rrendezvous, but then you get Tasking_error. It does not mean that the task does not exist or that the implementation is allowed to not support this. The name (and the task-id) of the task exist until it goes out of scope or unchecked deallocated (even in Ada 83 you could do 'Terminated or 'callable on such tasks. In fact, in several places in the annexes, we have made special arrangements to allow user to refer *safely* to abnormal but not yet terminated tasks (attribute, dynamic priorities!, Hold, etc.), so let's not confuse the issues, there is nothing impl-defined here. And it has nothing to do with abort deferred regions either, there is a time period between when the task becomes abnormal and when it is terminated. This window may be visible on multi processors, and the semantics make it sage to refer to such a task, since tasking error will be raised, if you did it a bit too late. So there is no problem here and let's go back to the original issue. I have stated my prefernces, but I can see the other points too, so I don't feel strongly either way anymore. But please, please, please (Bevakasha Norm), let's not have the default be Curernt_Task. It is very strange that the default if you do something wrong would be a suicide (also difficult to debug). It is true that more and more state adopt the capital punishment, but even there it applies only if you succeed, not if you "fail". Offer Pazy 31 Robinwood Ave. Boston, MA 02130 USA (617)522-5988 pazy@world.std.com **************************************************************** !section 13.9.1(08) !subject Is it always erroneous to test 'TERMINATED for an aborted task? !reference RM95 13.9.1(8);6.0 !reference RM95 9.8(1);6.0 !reference RM95 9.8(4);6.0 !reference RM95 9.9(1);6.0 !reference RM95-C.7.1(9);6.0 !reference RM95-C.7.1(18);6.0 !from Robert I. Eachus 95-10-17 !reference 95-5348.a Robert I. Eachus 95-10-17>> !discussion I figured it was time to separate this topic from the discussion on Abort_Task, becuase it seems to me as if a binding interpretation is likely to be required, whatever the "correct" interpretation is. I think the correct answer is that there are some--but very few-- non-erroneous cases where T'Terminated, T'Callable, Is_Terminated, and Is_Callable can be used with an aborted task. However 13.9.1(8) seems very draconian: RM 13.9.1(8): "It is erroneous to evaluate a primary that is a name denoting an abnormal object, or to evaluate a prefix that denotes an abnormal object." I think it was only intended to apply to names involved in disrupted assignments, but 13.9.1(5) specifically mentions an abort as a way for an object to become abnormal, and 9.8(1) is much more explicit: RM 9.8(4): "Each named task is then aborted, which consists of making the task abnormal and aborting the execution of the corresponding task_body unless it is already completed." In addition we have: RM 9.8(1): "An abort_statement causes one or more tasks to become abnormal, thus preventing any further interaction with such tasks." RM95 C.7.1(9): "The effect of Abort_Task is the same as the abort_statement for the task identified by T." RM95 C.7.1(18): "If a value of Task_ID is passed as a parameter to any of the operations declared in this package (or any language defined child of this package), and the corresponding task object no longer exists, the execution of the program is erroneous." It seems clear that there are many cases where T'Terminated or Is_Terminated for an aborted task must be erroneous, and I see little advantage to users to resolving many of them in any other way. (For example, if you pass a Task_ID outside the scope of it's master, which is the case C.7.1(18) addresses.) Are there cases where we should guarantee the validity? Section 9.9 (2&3) implies that there are. The definition of T'Callable is that "...a task is callable unless it is completed or abnormal," which certainly implies that there are some cases where it is non-erroneous for an abnormal task. The only one I could think of is within the aborted task. If the aborted task is the called task in a rendezvous, this might even be meaningful. So I can see a faint possibility of resolving this as a ramification, but not really. We would be saying that the name of a task is never abnormal within the task itself, but the attribute 'Callable depends on the outside view. Finally are there other attributes which are valid for otherwise erroneous prefixes? For example if an array assignment is disrupted, is there any reason to consider A'FIRST erroneous? Probably not worth worrying about, but someone else may want to broaden this issue. Robert I. Eachus with Standard_Disclaimer; use Standard_Disclaimer; function Message (Text: in Clever_Ideas) return Better_Ideas is... **************************************************************** !section 13.9.1(08) !subject Is it always erroneous to test 'TERMINATED for an aborted task? !reference RM95 13.9.1(8);6.0 !reference RM95 9.8(1);6.0 !reference RM95 9.8(4);6.0 !reference RM95 9.9(1);6.0 !reference RM95-C.7.1(9);6.0 !reference RM95-C.7.1(18);6.0 !reference 95-5348.a Robert I. Eachus 95-10-17 !from Tucker Taft 95-10-18 !reference 95-5349.a Tucker Taft 95-10-18>> !discussion > I figured it was time to separate this topic from the discussion on > Abort_Task, becuase it seems to me as if a binding interpretation is > likely to be required, whatever the "correct" interpretation is. I > think the correct answer is that there are some--but very few-- > non-erroneous cases where T'Terminated, T'Callable, Is_Terminated, and > Is_Callable can be used with an aborted task. However 13.9.1(8) seems > very draconian: > > RM 13.9.1(8): "It is erroneous to evaluate a primary that is a name > denoting an abnormal object, or to evaluate a prefix that denotes an > abnormal object." > > I think it was only intended to apply to names involved in > disrupted assignments, but 13.9.1(5) specifically mentions an abort as > a way for an object to become abnormal, and 9.8(1) is much more > explicit: > > RM 9.8(4): "Each named task is then aborted, which consists of > making the task abnormal and aborting the execution of the > corresponding task_body unless it is already completed." This confusion is due to an unfortunate overloading of the term "abnormal." An abnormal task is not an abnormal object! I never noticed this overloading until just now, since the two meanings were always completely separated in my mind. Now I see that using "abnormal" for objects resulting from a disrupted assignment was a very unfortunate choice of terms. This use of "abnormal" has nothing whatsoever to do with the state of a task called "abnormal." Probably at this point, the simpler "fix" is to change all uses of the term "abnormal" relating to a task to be simply "uncallable." This is really the only guaranteed immediate affect of aborting a task -- rendering the task uncallable. Aborting a task has no effect on the task object, and certainly doesn't make the task object become nonexistent. That only happens due to unchecked_deallocation or leaving the scope where the task object is declared. You can test 'Callable and 'Terminated completely safely after aborting a task; you can refer to the discriminants of the task object; you can ask the 'Size or the 'Address of the task object. As A. A. Milne would say, there is not even a smidgen of erroneousness about it... ... [the rest is elided due to this fundamental confusion...] > Robert I. Eachus -Tuck **************************************************************** !section 13.9.1(08) !subject Is it always erroneous to test 'TERMINATED for an aborted task? !reference RM95 13.9.1(8);6.0 !reference RM95 9.8(1);6.0 !reference RM95 9.8(4);6.0 !reference RM95 9.9(1);6.0 !reference RM95-C.7.1(9);6.0 !reference RM95-C.7.1(18);6.0 !reference 95-5348.a Robert I. Eachus 95-10-17 !reference 95-5349.a Tucker Taft 95-10-18 !from Robert I. Eachus !reference 95-5350.a Robert I. Eachus 95-10-18>> !discussion Tucker said: > This confusion is due to an unfortunate overloading of the term > "abnormal." An abnormal task is not an abnormal object! > I never noticed this overloading until just now, since the two > meanings were always completely separated in my mind. A lot of us didn't, that's how these things slip through. But as I said, I think we can't clean up this one without a binding interpretation. > Now I see that using "abnormal" for objects resulting from a disrupted > assignment was a very unfortunate choice of terms. This use of > "abnormal" has nothing whatsoever to do with the state of a task > called "abnormal." I wish it were that easy to bell the cat. It is clear that aborting a task can make tasks objects abnormal in the 13.9.1 sense. The right cure is probably to keep both uses of abnormal, and distinguish between an abnormal task object and an abnormal task. > Probably at this point, the simpler "fix" is to change all uses > of the term "abnormal" relating to a task to be simply "uncallable." > This is really the only guaranteed immediate affect of aborting > a task -- rendering the task uncallable. No. Aborting a task can interrupt an assignment which is not abort deferred, and it will render all tasks for which the aborted task is the master abnormal in the 13.9.1 sense--but not always immediately. This is what makes fixing the problem a testy chore. We need to keep the sentence in 13.9.1(5), and fix 9.8. Robert I. Eachus with Standard_Disclaimer; use Standard_Disclaimer; function Message (Text: in Clever_Ideas) return Better_Ideas is... **************************************************************** !section 13.9.1(08) !subject Is it always erroneous to test 'TERMINATED for an aborted task? !reference RM95 13.9.1(8);6.0 !reference RM95 9.8(1);6.0 !reference RM95 9.8(4);6.0 !reference RM95 9.9(1);6.0 !reference RM95-C.7.1(9);6.0 !reference RM95-C.7.1(18);6.0 !reference 95-5348.a Robert I. Eachus 95-10-17 !from Bob Duff !reference 95-5351.a Robert A Duff 95-10-18>> !discussion I think it's time to clarify some terminology. The RM uses the term "abnormal" in two different ways. Now, with hindsight, that seems like maybe not such a good idea. ;-) In 13.9.1, "abnormal" is applied to objects. It is, indeed, erroneous to do just about anything to an abnormal object. In 9.8, "abnormal" is applied to tasks. Referencing an abnormal task is *not* erroneous. In particular, T'Terminated, where T denotes a task object containing an abnormal task, is *not* erroneous. Similarly, calling entries of an abnormal task is *not* erroneous. There also seems to be some confusion about when a task object ceases to exist. In C.7.1, we find that it's erroneous to use a Task_ID in certain ways, if the task *object* corresponding to that Task_ID no longer exists. Aborting a task does *not* make any objects stop existing. An object ceases to exist when you leave the master in which the object is declared. Heap objects cease to exist when Unchecked_Deallocation is done. This is true of all objects, and task objects are no exception. Thus, calling Abort_Task(ID), where ID identifies a task that has been aborted already, is *not* usually erroneous. It's only erroneous if the ID has escaped outside the task's master. Consider three tasks T1, T2, and T3. If T2 and T3 both do: abort T1; simultaneously, then one of them will grab T1 first, and make this task abnormal. The second abort of T1 is harmless -- NOT erroneous. The same is true for: Abort_Task(T1_Id); where T1_Id = T1'Identity. All of the above follows directly from the RM, and I see no need for any AI to address these issues. (Although I admit that if we were still in RM-writing mode, I would reconsider the idea of using "abnormal" to mean two completely different things.) Back to the original question, which is whether Abort_Task should take an 'in' or 'in out' parameter: Offer suggested that aborting a task is analogous to Unchecked_Deallocation, which takes in 'in out' parameter, so it can null it out. However, I claim these two things are not analogous. After U_D, the designated object ceases to exist, and deallocating the same object twice is erroneous. But aborting a task does not cause the task *object* to stop existing. And aborting the same task twice is harmless. Therefore, I do not think it's a good idea to null out the task ID. Furthermore, Abort_Task is supposed to behave just like an abort_statement (except that one takes a Task_ID, whereas the other takes a task object). An abort_statement does not null out anything; therefore, Abort_Task should not either. Thus, Abort_Task does not (and should not) modify its parameter in any way. Therefore, this parameter should be of mode 'in'. As pointed out originally by Norm Cohen, making the parameter be of mode 'in' has the advantage that you can say Abort_Task(Current_Task) without declaring an extra temp variable. The same thing is true of a user-defined function that returns a Task_ID -- it would be convenient to allow a call to such a function to be passed to Abort_Task. Or a constant -- consider a procedure Abort_Several_Tasks, which takes a parameter of mode 'in', which is an array of several Task_IDs. Abort_Several_Tasks should simply loop through the array, calling Abort_Task -- it should not have to declare an extra temp variable. Finally, Norm Cohen also suggested that it might make sense to make Current_Task be the default for Abort_Task. I agree with Offer that we should not do that. Suicide should not be the default behavior. - Bob **************************************************************** !section 13.9.1(08) !subject Is it always erroneous to test 'TERMINATED for an aborted task? !reference RM95 13.9.1(8);6.0 !reference RM95 9.8(1);6.0 !reference RM95 9.8(4);6.0 !reference RM95 9.9(1);6.0 !reference RM95-C.7.1(9);6.0 !reference RM95-C.7.1(18);6.0 !from Robert I. Eachus 95-10-17 !reference 95-5348.a Robert I. Eachus 95-10-17 !from Offer pazy 95-10-18 !reference 95-5352.a Offer Pazy 95-10-18>> !discussion There is nothing ic common (I hope) between abnormal tasks and abnormal objects. If we did not screw up in CH 9 C and D, the discussion is always about *abnormal tasks* and not *abnormal task objects* and this is the difference that make you analysis inapplicable (again, I hope). If you could assign task objects and then the assignment would abort, then the task object would become abnormal, not the task itself. So personally, I don't see and need for binding interpretation or any other clarification. To emphasize, it is perfectly OK (and meaningful) to use the attributes and the operations in Task_Identificatio on abnormal tasks. Offer Pazy 31 Robinwood Ave. Boston, MA 02130 USA (617)522-5988 pazy@world.std.com **************************************************************** !section 13.9.1(08) !subject Is it always erroneous to test 'TERMINATED for an aborted task? !reference RM95 13.9.1(8);6.0 !reference RM95 9.8(1);6.0 !reference RM95 9.8(4);6.0 !reference RM95 9.9(1);6.0 !reference RM95-C.7.1(9);6.0 !reference RM95-C.7.1(18);6.0 !reference 95-5348.a Robert I. Eachus 95-10-17 !reference 95-5349.a Tucker Taft 95-10-18 !reference 95-5350.a Robert I. Eachus 95-10-18 !from Bob Duff !reference 95-5353.a Robert A Duff 95-10-19>> !discussion >...But as I > said, I think we can't clean up this one without a binding interpretation. ... > I wish it were that easy to bell the cat. It is clear that > aborting a task can make tasks objects abnormal in the 13.9.1 sense. Robert, I think you are missing the fact that 13.9.1 defines "abnormal object", whereas 9.8 defines "abnormal task". A task is not an object. A task object is not a task, but *contains* a task. Therefore, it is clear that aborting a task DOES NOT make task objects abnormal (in the 13.9.1 sense). Aborting a task makes *tasks* abnormal, which has nothing to do with 13.9.1. I again apologize for overloading the term "abnormal". But this overloading is quite correct, and is resolved by whether you're talking about a task or an object. - Bob **************************************************************** !section 13.9.1(08) !subject Is it always erroneous to test 'TERMINATED for an aborted task? !reference RM95 13.9.1(8);6.0 !reference RM95 9.8(1);6.0 !reference RM95 9.8(4);6.0 !reference RM95 9.9(1);6.0 !reference RM95-C.7.1(9);6.0 !reference RM95-C.7.1(18);6.0 !reference 95-5348.a Robert I. Eachus 95-10-17 !reference 95-5352.a Offer Pazy 95-10-18 !from Robert I. Eachus 95-10-18 !reference 95-5355.a Robert I. Eachus 95-10-19>> !discussion First, after rereading RM95 9.8 and comparing it with RM83 9.10, the newer wording avoids the use of abnormal after the defining instance. In fact the only further references to abnormal in the chapter seem to be in 9.8(21) which uses it in the 13.9.1 sense, and specifically references 13.9.1, and in 9.9(2), the definition of callable. But the use of abnormal in 9.9(2) refers to the "Task denoted by T." There is no way I can construct this as refering other than to the task object without explicit wording distinguishing the task object denoted by the name from the task created by the elaboration of the object declaration. RM 9.2(2) has a chance to do that and doesn't: "A task object (which represents one task) can be created either as part of the elaboration of an object_declaration, or as part of the evaluation of an allocator. All TASKS created by the elaboration of..." So I think it takes a BI to distinguish between task objects and the tasks themselves. In particular look at 13.11.2(9): "...if the object being freed contains tasks, the object might not be deallocated." Offer Pazy said: > There is nothing ic common (I hope) between abnormal tasks and abnormal > objects. If we did not screw up in CH 9 C and D, the discussion is always > about *abnormal tasks* and not *abnormal task objects* and this is the > difference that make you analysis inapplicable (again, I hope). I agree that we need to distinguish between tasks in an abnormal state, and task objects which are abnormal. If I thought that making that distinction would be enough, we could agree to it and go on to other issues. But there is another problem. When you follow the 9.8(5) definition of aborted to 13.9.1(5), you find that aborts can and do make objects erroneous (and it must in some cases). Now the INTENT surely was that an assignment in an aborted task not make that entire task object abnormal, and 13.9.1(7) certainly allows implementations not to do that. But the opposite choice is also implied. The clarifaction really needed here is that 13.9.1(4) discusses objects or parts of objects becoming abnormal, but doesn't say when assignment to a subcomponent is allowed to make the entire object abnormal. > If you could assign task objects and then the assignment would > abort, then the task object would become abnormal, not the task > itself. So personally, I don't see and need for binding > interpretation or any other clarification. If you expect the "average" reader of the RM, who by the way is pretty sophisticated, to not only pick up on this subtlety, but manage to correctly decide which tasks become abnormal in each sense, then there is no need for an AI. But I can't find the distinction in the RM, so I think that an AI is required. I also think that it should be written as a binding interpretation. **************************************************************** !section 13.9.1(08) !subject Is it always erroneous to test 'TERMINATED for an aborted task? !reference RM95 13.9.1(8);6.0 !reference RM95 9.8(1);6.0 !reference RM95 9.8(4);6.0 !reference RM95 9.9(1);6.0 !reference RM95-C.7.1(9);6.0 !reference RM95-C.7.1(18);6.0 !reference 95-5348.a Robert I. Eachus 95-10-17 !reference 95-5351.a Robert A Duff 95-10-18 !from Robert I. Eachus 95-10-19 !reference 95-5356.a Robert I. Eachus 95-10-19>> !discussion > I think it's time to clarify some terminology. So do I. ;-) > The RM uses the term "abnormal" in two different ways. Now, with > hindsight, that seems like maybe not such a good idea. ;-) Agreed. > In 9.8, "abnormal" is applied to tasks. Referencing an abnormal task is > *not* erroneous. In particular, T'Terminated, where T denotes a task > object containing an abnormal task, is *not* erroneous. Similarly, > calling entries of an abnormal task is *not* erroneous. Ah, this seems to be the intent. But quote me the words which say that tasks are not task objects. In my reply to Offer, I quoted evidence that there is no distinction made between a task and task object in the RM. In fact, the term task object is only used to avoid confusion with task types. > There also seems to be some confusion about when a task object > ceases to exist. In C.7.1, we find that it's erroneous to use a > Task_ID in certain ways, if the task *object* corresponding to > that Task_ID no longer exists. Aborting a task does *not* make > any objects stop existing. An object ceases to exist when you > leave the master in which the object is declared. Heap objects > cease to exist when Unchecked_Deallocation is done. This is true > of all objects, and task objects are no exception. Thus, calling > Abort_Task(ID), where ID identifies a task that has been aborted > already, is *not* usually erroneous. It's only erroneous if the > ID has escaped outside the task's master. I agree with all of this except the last sentence. If a task object still exists, I agree that 'TERMINATED should work. That is why I wrote the comment. But there are three ways for a task object to disappear: 1) If the scope of the master is left. 2) If the task object, or an object containing the task (13.11.2). 3) If no reference to the task object exists, and the task becomes completed. You may argue that garbage collection for tasks which are referenced by Task_IDs are an exception to the last case. I personally think that Task_IDs can be ignored by garbage collectors, but that it would be very unfriendly to do so. However, you must interpret the RM to allow garbage collection for tasks which are not the targets of Task_IDs. General garbage collection in Ada is tough, but recycling tasks should be easy. > Consider three tasks T1, T2, and T3. If T2 and T3 both do... All > of the above follows directly from the RM, and I see no need for > any AI to address these issues. (Although I admit that if we were > still in RM-writing mode, I would reconsider the idea of using > "abnormal" to mean two completely different things.) No argument (unless one of the task is the master of another). > Back to the original question, which is whether Abort_Task should take > an 'in' or 'in out' parameter: Offer suggested that aborting a task is > analogous to Unchecked_Deallocation, which takes in 'in out' parameter, > so it can null it out. However, I claim these two things are not > analogous. After U_D, the designated object ceases to exist, and > deallocating the same object twice is erroneous. But aborting a task > does not cause the task *object* to stop existing. And aborting the > same task twice is harmless. Therefore, I do not think it's a good idea > to null out the task ID. We need to argue this in the original chain. However, discussion of the assertion in the fourth sentence above does belong here. Aborts can and will cause task objects to stop existing. However, in the normal case it will not be the named task objects which disappear, but their children. The Abort_Task procedure takes one argument, and no task can be its own master, so normally the task object (and the Task_ID) will continue to be valid after the call--assuming we sort this issue out right. Robert I. Eachus with Standard_Disclaimer; use Standard_Disclaimer; function Message (Text: in Clever_Ideas) return Better_Ideas is... **************************************************************** !section 13.9.1(08) !subject Is it always erroneous to test 'TERMINATED for an aborted task? !reference RM95 13.9.1(8);6.0 !reference RM95 9.8(1);6.0 !reference RM95 9.8(4);6.0 !reference RM95 9.9(1);6.0 !reference RM95-C.7.1(9);6.0 !reference RM95-C.7.1(18);6.0 !reference 95-5348.a Robert I. Eachus 95-10-17 !reference 95-5349.a Tucker Taft 95-10-18 !reference 95-5350.a Robert I. Eachus 95-10-18 !reference 95-5353.a Robert A Duff 95-10-19 !from Robert I. Eachus 95-10-20 !reference 95-5360.a Robert I. Eachus 95-10-20>> !discussion Bob Duff said: > I think you are missing the fact that 13.9.1 defines "abnormal > object", whereas 9.8 defines "abnormal task". A task is not an > object. A task object is not a task, but *contains* a task. > Therefore, it is clear that aborting a task DOES NOT make task > objects abnormal (in the 13.9.1 sense). Aborting a task makes > *tasks* abnormal, which has nothing to do with 13.9.1. I keep wondering what all the fuss is about. I agree that this is what we want the RM to say. But unless someone can point out where the RM specifically says that the task object and task are separate entities, and that the task object denotes the task, we need a BI. I am not arguing that what Bob advocates is wrong, or not what is intended. It is just not in the Ada 95 RM. I'm sorry, I just regard this as a minor "easy" AI that must be a binding interpretation because the words that would make it a ramification are nowhere to be found--or not to be found in the Ada 95 RM. The sentences I would like to quote ARE in the Ada 83 RM: RM83 9.2(2): "A task object is an object whose type is a task type. The value of a task object designates a task that has entries of the corresponding task type." RM83 9.3(1): "A task body defines the execution of any task that is designated by a task object of the corresponding task type." Now read RM95 9.1(15-18) and RM95 9.2(2). I conclude from 9.1(15-18) that a task object DOES NOT contain or denote a task, it contains among other things a representation of the state of the task. I also conclude from 9.2 that a task object represents ONE task, but no mention of denoting a task. Now go back to RM95 9.8(5): "...the named task is then aborted, which consists of making the task abnormal..." The dependence on names here is the problem. The name is the name of a task object. See for example, RM95 9.1(10) where explicitly the name in a single task declaration is the name of a task object. Since nowhere is it said that the name denotes both a task object and a task, we need a fix, or the object, which is the only thing denoted, is what becomes abnormal. (The same thing applies in 9.9(2&3) where tasks denoted by a name are explicitly mentioned.) Robert I. Eachus with Standard_Disclaimer; use Standard_Disclaimer; function Message (Text: in Clever_Ideas) return Better_Ideas is... **************************************************************** !section C.7.1(03) !subject Why does Abort_Task have an in out parameter? !reference RM95-C.7.1(3);6.0 !reference Norman Cohen 95-09-06 !reference 95-5325.a Robert A Duff 95-10-11 !reference 95-5331.a Offer Pazy 95-10-12 !reference 95-5339.a Ted Baker 95-10-13 !reference 95-5343.a Robert I. Eachus 95-10-16 !from Robert I. Eachus 95-10-22 !reference 95-5363.a Robert I. Eachus 95-10-22>> !discussion Assuming that everyone is agreed that there is a distinction between task objects and tasks, which one does a Task_ID identify? I have been assuming that a Task_ID identifies the task, not the task object. Since 13.11.2(9-15) implies that there is no problem deallocating unterminated tasks without discriminants, and the bounded error conditions for the discriminated case involve references to the discriminants, I assume that Ada.Task_Identification.Current_Task is not permitted to fail just because the task object does not exist. (RM95 C.7.1(18) specifically does not apply.) My mental image is that Task_ID returns a system defined pointer to the base of the task stack, and pointers to the code and task object are located there. (Actually, if the task object has pointer to the code entry point, you don't need one on the stack, but that is a detail.) One alternative implementation would have Current_Task return a pointer to the task object, and Unchecked_Deallocation would never be allowed to deallocate the task object for an unterminated task. The other alternative is to have Current_Task return a pointer to the task object even if it no longer exists. Since it is erroneous to use the Task_ID in that case there is no problem, at least from a legality standpoint. Which is right? Or are all three permitted? If the first implementation is legal, then Abort_Task should be allowed to set T to Null_Task_ID. ****************************************************************