Next: , Previous: , Up: Elaboration Order Handling in GNAT   [Contents][Index]


9.14 Resolving Task Issues

The model of execution in Ada dictates that elaboration must first take place, and only then can the main program be started. Tasks which are activated during elaboration violate this model and may lead to serious concurrent problems at elaboration time.

A task can be activated in two different ways:

Since the elaboration of a partition is performed by the environment task servicing that partition, any tasks activated during elaboration may be in a race with the environment task, and lead to unpredictable state and behavior. The static model seeks to avoid such interactions by assuming that all code in the task body is executed at elaboration time, if the task was activated by elaboration code.

package Decls is
   task Lib_Task is
      entry Start;
   end Lib_Task;

   type My_Int is new Integer;

   function Ident (M : My_Int) return My_Int;
end Decls;
with Utils;
package body Decls is
   task body Lib_Task is
   begin
      accept Start;
      Utils.Put_Val (2);
   end Lib_Task;

   function Ident (M : My_Int) return My_Int is
   begin
      return M;
   end Ident;
end Decls;
with Decls;
package Utils is
   procedure Put_Val (Arg : Decls.My_Int);
end Utils;
with Ada.Text_IO; use Ada.Text_IO;
package body Utils is
   procedure Put_Val (Arg : Decls.My_Int) is
   begin
      Put_Line (Arg'Img);
   end Put_Val;
end Utils;
with Decls;
procedure Main is
begin
   Decls.Lib_Task.Start;
end Main;

When the above example is compiled with the static model, an elaboration circularity arises:

error: elaboration circularity detected
info:    "decls (body)" must be elaborated before "decls (body)"
info:       reason: implicit Elaborate_All in unit "decls (body)"
info:       recompile "decls (body)" with -gnatel for full details
info:          "decls (body)"
info:             must be elaborated along with its spec:
info:          "decls (spec)"
info:             which is withed by:
info:          "utils (spec)"
info:             which is withed by:
info:          "decls (body)"

In the above example, Decls must be elaborated prior to Main by virtue of a with clause. The elaboration of Decls activates task Lib_Task. The static model conservatibely assumes that all code within the body of Lib_Task is executed, and generates an implicit Elaborate_All pragma for Units due to the call to Utils.Put_Val. The pragma implies that both the spec and body of Utils, along with any units they `with', must be elaborated prior to Decls. However, Utils’s spec `with's Decls, implying that Decls must be elaborated before Utils. The end result is that Utils must be elaborated prior to Utils, and this leads to a circularity.

In reality, the example above will not exhibit an ABE problem at run time. When the body of task Lib_Task is activated, execution will wait for entry Start to be accepted, and the call to Utils.Put_Val will not take place at elaboration time. Task Lib_Task will resume its execution after the main program is executed because Main performs a rendezvous with Lib_Task.Start, and at that point all units have already been elaborated. As a result, the static model may seem overly conservative, partly because it does not take control and data flow into account.

When faced with a task elaboration circularity, a programmer has several options available:


Next: , Previous: , Up: Elaboration Order Handling in GNAT   [Contents][Index]