!standard 09.10 (06) 00-04-11 AI95-00118/05 !class binding interpretation 96-04-04 !status Corrigendum 2000 99-07-28 !status WG9 approved 96-12-07 !status ARG approved 9-0-3 96-10-07 !status work item (letter ballot requested and failed) 96-09-15 !status ARG approved 9-0-0 (subject to editorial review) 96-06-17 !status work item 96-04-04 !status received 96-04-04 !priority Medium !difficulty Hard !qualifier Omission !subject Termination signals query of Terminate attribute !summary A task T2 can rely on values of variables that are updated by another task T1, if task T2 first verifies that T1'Terminated is True. !question Consider: task body T is Stop_Pulse : Integer; task Local_Task is ... end Local_Task; task body Local_Task is begin Stop_Pulse := 17; end T1; begin loop if Local_Task'Terminated then Rely_On(Stop_Pulse=17); -- Is this erroneous? (No.) exit; end if; end loop; end T; Since there is no signaling as per 9.10(2-10) between the assignment to Stop_Pulse and any action in task T prior to the call on Rely_On, reliance on the update to Stop_Pulse by Local_Task is erroneous by 9.10(11). 9.10(6) doesn't apply, since T is not yet (or ever) waiting for the termination of Local_Task in the Ada technical sense of "waiting". !recommendation (See summary.) !wording An action A1 signals an action A2 if A1 is the termination of a task T, and A2 is the evaluation of the expression T'Terminated. !discussion It would be surprising if T'Terminated were True, but T failed to update any locally-cached variables, or the querying task failed to see those updates. The wording is written so that Ada.Task_Identificiation.Is_Terminated() (where evaluates to T'Identity) works the same as T'Terminated. It would be very surprising if this function, defined to be the same as 'Terminated, had a different signaling behavior. Note that we do not say anything about the Callable attribute; if the Callable attribute becomes False, the task might still have a local cache that is out of sync with global variables. !corrigendum 9.10(6) @dinsa @xbullet @dinst @xbullet !ACATS test It is possible to write a test for the example given here, but it probably would work even for an incorrect implementation. !appendix !section 9.10(11) !subject signaling concept may be incomplete !reference RM95-9.10(11) !from Erhard Ploedereder !keywords signaling, shared variables, sequential !reference 95-5398.a Erhard Ploedereder 95-11-29>> !discussion Consider: task body T is Stop_Pulse : Integer; task Local_Task is ... end Local_Task; task body Local_Task is Stop_pulse := 17; end T1; begin loop if Local_Task'Terminated then Rely_on(Stop_Pulse=17); -- you better not. exit; end if; end loop; Since there is no signaling as per 9.10(2-10) between the assignment to Stop_Pulse and any action in task T prior to the call on Rely_On, reliance on the update to Stop_Pulse by Local_Task is erroneous by 9.10(11). 9.10(6) doesn't apply, since T is not yet (or ever) waiting for the termination of Local_Task in the Ada technical sense of "waiting". Clearly, one would like this idiom to work as "expected" and shared variables, whose changed values are cached by the implementation of local tasks, to be updated upon termination at the latest. There should be a rule requiring that, upon termination of a task, its updates to shared variables must have occurred, if these variables are read by other tasks. **************************************************************** !section 9.10(11) !subject signaling concept may be incomplete !reference RM95-9.10(11) !keywords signaling, shared variables, sequential !reference 95-5398.a Erhard Ploedereder 95-11-29 !from Offer Pazy 95-11-30 !reference 95-5404.a Offer Pazy 95-12-1>> !discussion Erhard, I agree with your analysis and I also agree that it would be *nice* if termination would be folded in the signaling concept. But: > Clearly, one would like this idiom to work as "expected" and shared > variables, whose changed values are cached by the implementation of local > tasks, to be updated upon termination at the latest. Why is it so important? I mean, why is it so "clear"? Since Ada does not provide a way to really wait on a termination of another task (if we exclude the business of masters which is another issue), only to query the 'terminated attribute, I don't see where spin-waiting will be the practical way to achieve that. With a simple PO, you can get the same result, admittedly with more overhead, but I think that in a real life example, using a PO will be much more realistic. So to summarize, I am interested to know why you find this example so useful? On the implementation side, there is (admittedly small) penalty for doing what you ask for. If the reason that Stop_Pulse is not safely available to T is becuase it is in a register, it is practically guaranteed that when Local_Task terminates. all the register-variables (those which are visible to other tasks), will be flushed back to memory. No problem here. But your example suggests that you were thinking of a multi-processor, presumably with enough processors so you don't care of dedicating one for the spin-wait. In these cases we have to think about non-consistent caches. Unless the implementatation keeps a "good" (i.e. quite elaborate) track of all the global variables that the task touches, the entire cache will have to be flushed to the real memory when the task terminates. (I may be wrong here, but I think that most such caches don't allow you to flush individual words. They usually flush the entire cache or regions of it.) Just a thought. Offer Pazy 31 Robinwood Ave. Boston, MA 02130 USA (617)522-5988 pazy@world.std.com **************************************************************** !section 9.10(11) !subject signaling concept may be incomplete !reference RM95-9.10(11) !keywords signaling, shared variables, sequential !reference 95-5398.a Erhard Ploedereder 95-11-29 !from Erhard Ploedereder !reference 95-5404.a Offer Pazy !reference 95-5407.a Erhard Ploedereder 95-12-3>> !discussion Offer writes: > If the reason that Stop_Pulse is not safely available to > T is becuase it is in a register, it is practically guaranteed that when > Local_Task terminates. all the register-variables (those which are visible > to other tasks), will be flushed back to memory. No problem here. What makes you so sure ? (This is actually where my problem started, even if the comment cast it in terms of 'TERMINATED.) In terms of language rules, there doesn't seem to be any such guarantee, unless the local task completes via a terminate alternative (to engage ARM 9.10(6)) AND the master has finalization code to execute (to be able to reference the variable shared between master and slave task after the slave's termination) AND that finalization code references the shared variable. > Why is it so important? I mean, why is it so "clear"? Admittedly, I'm not sure. Of course, using a PO solves the problem. But really, the 'TERMINATED example comes as a bit of a surprise, if the answer is that there are circumstances where I cannot expect that updates to shared variables have happened by the time the task has terminated. **************************************************************** !from Randy Brukardt 99-10-07 At the recent ARG meeting, it was decided to expand this AI so that Ada.Task_Identification.Is_Terminated(T'Identity) acts the same as T'Terminated. ****************************************************************