CVS difference for ais/ai-10266.txt

Differences between 1.1 and version 1.2
Log of other versions for file ais/ai-10266.txt

--- ais/ai-10266.txt	2002/06/11 05:15:50	1.1
+++ ais/ai-10266.txt	2002/06/12 00:36:46	1.2
@@ -1025,3 +1025,306 @@
 
 ****************************************************************
 
+From: Tucker Taft
+Sent: Tuesday, June 11, 2002  12:12 AM
+
+Can you comment on my proposed "simplification:"
+
+    Each master task may specify a procedure to handle task termination
+(presumably using an access-to-procedure value rather than dispatching).
+The specified procedure is called when any subtask terminates. If a master
+task doesn't specify such a procedure, the procedure of its master is called,
+and so on up the chain to the environment task.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Tuesday, June 11, 2002  12:32 AM
+
+> Can you comment on my proposed "simplification:"
+
+Well, it's the middle of the night, but I'll try.
+
+>     Each master task may specify a procedure to handle task termination
+> (presumably using an access-to-procedure value rather than dispatching).
+> The specified procedure is called when any subtask terminates.  If a master
+> task doesn't specify such a procedure, the procedure of its master is called,
+> and so on up the chain to the environment task.
+
+That would solve my minor concern, and certainly would be a new capability. I
+wonder if there would be fine enough control if that was the only possibility
+(although of course the finalization object approach is always available).
+
+But who calls this procedure? Is there some way we can make it work in the
+Storage_Error case (assuming that the master task isn't also raising
+Storage_Error)?
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Tuesday, June 11, 2002  7:18 AM
+
+>That would solve my minor concern, and certainly would be a new capability.
+>I wonder if there would be fine enough control if that was the only
+>possibility (although of course the finalization object approach is always
+>available).
+>
+
+I agree it is a minimial capability.  But it seems that it would still be
+useful.  You could have a registry indexed by task ID if you wanted to
+get fancier, with the handler procedure looking up the task that terminated,
+and taking some appropriate action based on the ID.
+
+>But who calls this procedure? Is there some way we can make it work in the
+>Storage_Error case (assuming that the master task isn't also raising
+>Storage_Error)?
+
+I would stick with the execution model described for the original proposal.
+I don't understand the big problem with storage_error.  Presuming you can
+handle storage_error at all, the stack must be cut back somewhat before
+entering the exception handler.  I presume the call to this termination
+procedure would come from the exception handler of "last resort" that the
+run-time system provides for every task.
+
+****************************************************************
+
+From: Ted Baker
+Sent: Tuesday, June 11, 2002  9:00 AM
+
+| Each master task may specify a procedure to handle task
+| termination (presumably using an access-to-procedure value
+| rather than dispatching).  The specified procedure is called
+| when any subtask terminates.  If a master task doesn't specify
+| such a procedure, the procedure of its master is called, and so
+| on up the chain [of masters] to the environment task.
+
+It is a bit ironic to finally introduce to Ada what seems to be an
+asynchronous signal handler (like a SIGCHLD handler in Unix/POSIX).
+
+On the other hand, it might be implementable very simply, *provided*
+the ARG doesn't end up trying to bind up all the ragged semantic
+edges too neatly. Among the various semantic details that I
+hope will be left simple and ugly:
+
+1) Which thread executes the handler.  It should be
+implementation-defined which thread of control executes this
+handler.  It should not be specified as being executed by the task
+that terminates or the task that bound the handler, or we get into
+a whole mess of details, including how it can be interleaved with
+the normal execution of that task, and how the priority relates to
+the priorities (active and base) of that task.  In particular, it
+should be allowed that the terminating task's thread call the
+handler as part of the termination processing, or that this
+handling be done by a tasking kernel, or by a waiting server
+thread provided by the runtime system.
+
+2) Priority of the handler.  It might seem this should be at least
+as high as the lower of priority of the task that terminates, but
+I can imagine cirumstances under which failure of a high priority
+task should not be allowed to cause other high priority tasks to
+miss deadlines while the handler executes.
+
+3) Exception propagation. If this handler attempts to propagate an
+exception, it should be quietly lost.  (Or else we end up having
+yet another handler procedure, to receive notification of failed
+termination handler procedures?)
+
+4) Abort semantics.  If the thread that executes the termination
+handler is an Ada task that is aborted while the handler is
+executing, the effect should be implementation-defined.
+
+5) Synchronization of shared variables touched by the handler.
+The handler may be limited to volatile and atomic variables.
+If that is not general enough, perhaps the handler could be
+allowed to be a protected procedure?
+
+6) The effect of blocking (and deadlock) in the handler.  What if
+the handler calls a task or protected entry, a delay statement, or
+some other blocking operation?  Depending on which thread
+executes the handler, the side-effects could be quite varied.
+It would be simplest to forbid calls to poentially blocking
+operations.
+
+****************************************************************
+
+From: Robert A. Duff
+Sent: Tuesday, June 11, 2002  3:00 PM
+
+> It is a bit ironic to finally introduce to Ada what seems to be an
+> asynchronous signal handler (like a SIGCHLD handler in Unix/POSIX).
+
+I was assuming the termination handler is called by the terminating
+task.  Thus, "is called when any subtask terminates" ought to be "before
+the task terminates."  Otherwise, we get into the can of worms Ted
+describes.
+
+I must say, I don't much like this feature...
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Tuesday, June 11, 2002  3:30 PM
+
+This is all discussed in a fair amount of detail in the
+original proposal, and I would recommend we stick with
+those semantics.  Of course the run-time system
+can always use "as-if" rules to fake it, but in general,
+the assumption is that the dying task calls the procedure,
+at a time when its task attributes are still well defined.
+
+I suppose if we are going with the handler model, we should
+probably make this an access-to-protected procedure.  That
+has another nice feature in that you can easily associate
+some data with the procedure, since the associated protected
+object is an implicit parameter to such procedures.
+
+This also helps to address the priority issue, since the
+ceiling priority of the protected object determines the
+priority.  Of course, it also limits the priority of
+tasks that it can handle.
+
+>
+> I must say, I don't much like this feature...
+
+Can you say a bit more than that.  Otherwise this
+sounds like the usual unhelpful FUD comment ;-).
+
+****************************************************************
+
+From: Robert A. Duff
+Sent: Tuesday, June 11, 2002  9:21 AM
+
+>     task body Tsk is
+>     begin
+>        ...
+>     exception
+>        when others =>
+>           Ada.Text_IO.Put_Line ("*** Exception raised in TSK!!!");
+>     end;
+>
+> What happens frequently is that Storage_Error is raised when Tsk's stack is
+> exhausted; then the "others" handler is executed, but the call on Text_IO
+> (which  is accomplished by the task, thus using the task's stack) raises
+> Storage_Error again.
+
+If the "..." above uses up all the task's stack space, then that space
+ought to be reclaimed before entering the handler.  So the Put_Line
+should work (unless the task's stack is *very* small, or unless stacks
+are growable and the whole program's memory is uses up).
+
+There are many problems with Storage_Error in Ada.  It is practically
+impossible to write a non-erroneous handler for Storage_Error.
+But that's beside the point, here.
+
+By the way, on some of our embedded targets, we run in a default mode
+where a message is printed (or some such thing) whenever a task is
+killed by an exception.  If the purpose is debugging, this seems
+sufficient.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Tuesday, June 11, 2002   6:01 PM
+
+> >     task body Tsk is
+> >     begin
+> >        ...
+> >     exception
+> >        when others =>
+> >           Ada.Text_IO.Put_Line ("*** Exception raised in TSK!!!");
+> >     end;
+> >
+> > What happens frequently is that Storage_Error is raised when Tsk's stack is
+> > exhausted; then the "others" handler is executed, but the call on Text_IO
+> > (which  is accomplished by the task, thus using the task's stack) raises
+> > Storage_Error again.
+>
+> If the "..." above uses up all the task's stack space, then that space
+> ought to be reclaimed before entering the handler.  So the Put_Line
+> should work (unless the task's stack is *very* small, or unless stacks
+> are growable and the whole program's memory is uses up).
+
+It is, but the typical problem is that the task itself has objects using up the
+entire stack. (This problem is made worse by the fact that Janus/Ada does
+procedure-level allocation for blocks, which means that the space for the
+largest block is allocated out of the procedures (in this case, the tasks) own
+activation space)).
+
+Ada.Text_IO takes quite a bit of stack space, and task stacks are pretty small
+by default. (Making them larger by default would not help much, we've had
+several customers adjust their declarations to just fit the (default) stack,
+and then have problems.) So it is not at all impossible for a call to
+Ada.Text_IO to blow the stack, depending on the declarations in the task. This
+has even happened to me a few times.
+
+A typical problem case is something like:
+
+    task body Tsk is
+       <bunch of declarations here>
+    begin
+        ...
+        Ada.Text_IO.Put_Line ("..."); -- Raises Storage_Error.
+    exception
+        when others =>
+           Ada.Text_IO.Put_Line ("*** Exception raised in TSK!!!");
+    end;
+
+In this case, there is plenty of space to handle the exception (we always
+insure that by reserving the space when the handler is entered). But both calls
+to Ada.Text_IO.Put_Line will raise Storage_Error. The only way around this is
+to have another thread get the notification.
+
+> There are many problems with Storage_Error in Ada.  It is practically
+> impossible to write a non-erroneous handler for Storage_Error.
+> But that's beside the point, here.
+
+You're right, its beside the point. I'm interested in practical, not
+theoretical, help here.
+
+> By the way, on some of our embedded targets, we run in a default mode
+> where a message is printed (or some such thing) whenever a task is
+> killed by an exception.  If the purpose is debugging, this seems
+> sufficient.
+
+I looked into that years ago, but it is not possible with our current task
+model. The problem is that unhandled exceptions is not something that the task
+supervisor sees. We generate an empty "others" handler surrounding the entire
+contents of the task; the task supervisor only sees normal completion of the
+task.
+
+To provide a feature like that would require an extra supervisor call
+specifically to provide that error message (something we would not consider
+then because of the space implications), or having the compiler generate the
+message directly into the code (which would require the compiler to gain
+knowledge about writing text, something it currently does not know how to do).
+
+Implementing one of these proposals probably would require adding an additional
+supervisor call (probably a weeks work), but at least here the significant cost
+of doing that could be justified by the need to implement the new language.
+
+---
+
+Tucker said:
+
+>I would stick with the execution model described for the original proposal.
+>I don't understand the big problem with storage_error.  Presuming you can
+>handle storage_error at all, the stack must be cut back somewhat before
+>entering the exception handler.  I presume the call to this termination
+>procedure would come from the exception handler of "last resort" that the
+>run-time system provides for every task.
+
+Most of this I explained above. My point is that there are perfectly good
+(perhaps not perfect) ways to do this now in the language. Why should we bother
+going through all of this effort if we are not going to provide any truly new
+capabilities. The ability to provide a global handler would be nice, but it is
+isn't worth much if the only thing I cannot handle myself (Storage_Error) is
+not handled here, either.
+
+Ted demonstrates all of the annoying reasons why we cannot provide a solution
+to the (IMHO) real problem. (I expect that many of the people asking for this
+capability are expecting it to work in the Storage_Error case, while no
+proposal to date has done so.) Therefore, I (still) see no reason to bother
+with a broken solution in this case.
+
+****************************************************************
+

Questions? Ask the ACAA Technical Agent