[comp.lang.ada] Interesting feature of task priorities

arny@cbnewsl.ATT.COM (arny.b.engelson) (03/15/89)

After 6 years of programming in Ada, I am still learning about the nuances
of this language.  What follows is a lesson I (and others) spent several
hours learning.  For those of you that don't know, or have forgotten, the
following may save you from duplicating the frustrating search I underwent
in identifying this.  It has to do with when task activation takes place, and
how it affects task scheduling when running tasks of different priorities.

The crux of the problem was that when a task is created as a result of a
"new" assignment, and the newly created task is of a higher priority than
the task currently running, the new task begins running before the
assignment statement containing the "new" gets a chance to complete.  That
means the variable pointing to the newly created task object is still null
(assuming this is the first assignment) even though the task object exists
and is in fact executing.

I got clobbered by this when a task which was in turn created by the "new
task" attempted to rendezvous with it by referencing this as-yet-unassigned
variable.  This raised a Constraint_Error, which I had a helluva time
tracking down because all I could get as a source of the exception (even
with the debugger) was an address in the Ada runtime system outside of my
program.  As it turns out, some rather advanced features of the debugger
would have helped me in identifying the line causing the problem, had I
known to use them.  Runtime error reporting deficiencies aside, this was
pretty interesting.

This error only occurred (using this task scheduler) if task priorities are
assigned.  The risk of the error, however, is still present if the program
were to be run using a different task scheduler.  Thankfully, this whole
mess has (more than one) fairly simple solution (which are of course left to
the reader as an exercise :-) ).
The one I will choose involves blocking the "new task" from creating any
other tasks until the assignment to the variable takes place (an additional
rendezvous), simply because it fit easily into my program.

  - Arny Engelson   (201)386-4816   att!wayback!arny

If anyone's interested, the remainder of this article is a code fragment
representing the situation.  Note that it is a FRAGMENT, with pieces missing
and changed to save space, and I have NOT run this identical fragment.

procedure Called_By_Low_Priority_Task is
   task type Baby;
   type Baby_Ptr is access Baby;
   B : Baby_Ptr;
   task type Parent is  -- Default (higher) priority
      entry Baby_Complete;
      entry All_Complete;
   end;
   type Parent_Ptr is access Parent;
   P : Parent_Ptr;
   task body Baby is  -- Default (higher) priority
   begin
      P.Baby_Complete;  -- Constraint Error here!
   end;
   task body Parent is
   begin
-- Fix by adding new accept statement here
      B := new Baby;
      accept Baby_Complete;
      accept All_Complete;
   end;
begin
   P := new Parent;
-- Fix by adding new rendezvous call with P here
   P.All_Complete;
end;